Skip to content

Commit c1fb335

Browse files
authored
Merge pull request #335 from krassowski/improve/autocomplete
Implement a workaround for #334
2 parents 56e121f + 93d9509 commit c1fb335

File tree

3 files changed

+75
-37
lines changed

3 files changed

+75
-37
lines changed

packages/jupyterlab-lsp/src/features/completion/completion.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { CompletionTriggerKind } from '../../lsp';
1+
import {
2+
AdditionalCompletionTriggerKinds,
3+
CompletionTriggerKind,
4+
ExtendedCompletionTriggerKind
5+
} from '../../lsp';
26
import * as CodeMirror from 'codemirror';
37
import { CodeMirrorIntegration } from '../../editor_integration/codemirror';
48
import { JupyterFrontEnd } from '@jupyterlab/application';
@@ -18,7 +22,6 @@ import { ILSPCompletionThemeManager } from '@krassowski/completion-theme/lib/typ
1822

1923
export class CompletionCM extends CodeMirrorIntegration {
2024
private _completionCharacters: string[];
21-
// TODO chek if this works if yest then remove settings from options
2225
settings: FeatureSettings<LSPCompletionSettings>;
2326

2427
get completionCharacters() {
@@ -44,7 +47,7 @@ export class CompletionCM extends CodeMirrorIntegration {
4447
this.settings.composite.continuousHinting
4548
) {
4649
(this.feature.labIntegration as CompletionLabIntegration)
47-
.invoke_completer(CompletionTriggerKind.Invoked)
50+
.invoke_completer(AdditionalCompletionTriggerKinds.AutoInvoked)
4851
.catch(console.warn);
4952
return;
5053
}
@@ -126,7 +129,7 @@ export class CompletionLabIntegration implements IFeatureLabIntegration {
126129
});
127130
}
128131

129-
invoke_completer(kind: CompletionTriggerKind) {
132+
invoke_completer(kind: ExtendedCompletionTriggerKind) {
130133
let command: string;
131134
this.current_completion_connector.trigger_kind = kind;
132135

@@ -135,7 +138,7 @@ export class CompletionLabIntegration implements IFeatureLabIntegration {
135138
} else {
136139
command = 'completer:invoke-file';
137140
}
138-
return this.app.commands.execute(command).then(() => {
141+
return this.app.commands.execute(command).catch(() => {
139142
this.current_completion_connector.trigger_kind =
140143
CompletionTriggerKind.Invoked;
141144
});

packages/jupyterlab-lsp/src/features/completion/completion_handler.ts

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import {
2+
CompletionConnector,
23
CompletionHandler,
34
ContextConnector,
4-
KernelConnector,
5-
CompletionConnector
5+
KernelConnector
66
} from '@jupyterlab/completer';
77
import { CodeEditor } from '@jupyterlab/codeeditor';
88
import { JSONArray, JSONObject } from '@lumino/coreutils';
9-
import { CompletionItemKind, CompletionTriggerKind } from '../../lsp';
9+
import {
10+
AdditionalCompletionTriggerKinds,
11+
CompletionItemKind,
12+
CompletionTriggerKind,
13+
ExtendedCompletionTriggerKind
14+
} from '../../lsp';
1015
import * as lsProtocol from 'vscode-languageserver-types';
1116
import { VirtualDocument } from '../../virtual/document';
1217
import { IVirtualEditor } from '../../virtual/editor';
@@ -17,7 +22,6 @@ import {
1722
} from '../../positioning';
1823
import { LSPConnection } from '../../connection';
1924
import { Session } from '@jupyterlab/services';
20-
import ICompletionItemsResponseType = CompletionHandler.ICompletionItemsResponseType;
2125

2226
import { CodeCompletion as LSPCompletionSettings } from '../../_completion';
2327
import { FeatureSettings } from '../../feature';
@@ -27,6 +31,7 @@ import {
2731
KernelKind
2832
} from '@krassowski/completion-theme/lib/types';
2933
import { LabIcon } from '@jupyterlab/ui-components';
34+
import ICompletionItemsResponseType = CompletionHandler.ICompletionItemsResponseType;
3035

3136
/**
3237
* A LSP connector for completion handlers.
@@ -44,7 +49,7 @@ export class LSPConnector
4449
responseType = ICompletionItemsResponseType;
4550

4651
virtual_editor: IVirtualEditor<CodeEditor.IEditor>;
47-
trigger_kind: CompletionTriggerKind;
52+
trigger_kind: ExtendedCompletionTriggerKind;
4853

4954
protected get suppress_auto_invoke_in(): string[] {
5055
return this.options.settings.composite.suppressInvokeIn;
@@ -156,6 +161,17 @@ export class LSPConnector
156161
cursor_in_root
157162
);
158163

164+
const lsp_promise = this.fetch_lsp(
165+
token,
166+
typed_character,
167+
virtual_start,
168+
virtual_end,
169+
virtual_cursor,
170+
document,
171+
position_in_token
172+
);
173+
let promise: Promise<CompletionHandler.ICompletionItemsReply> = null;
174+
159175
try {
160176
if (this._kernel_connector && this._has_kernel) {
161177
// TODO: this would be awesome if we could connect to rpy2 for R suggestions in Python,
@@ -165,41 +181,34 @@ export class LSPConnector
165181
const kernelLanguage = await this._kernel_language();
166182

167183
if (document.language === kernelLanguage) {
168-
return Promise.all([
184+
promise = Promise.all([
169185
this._kernel_connector.fetch(request),
170-
this.fetch_lsp(
171-
token,
172-
typed_character,
173-
virtual_start,
174-
virtual_end,
175-
virtual_cursor,
176-
document,
177-
position_in_token
178-
)
186+
lsp_promise
179187
]).then(([kernel, lsp]) =>
180188
this.merge_replies(this.transform_reply(kernel), lsp, this._editor)
181189
);
182190
}
183191
}
184-
185-
return this.fetch_lsp(
186-
token,
187-
typed_character,
188-
virtual_start,
189-
virtual_end,
190-
virtual_cursor,
191-
document,
192-
position_in_token
193-
).catch(e => {
194-
console.warn('LSP: hint failed', e);
195-
return this.fallback_connector
196-
.fetch(request)
197-
.then(this.transform_reply);
198-
});
192+
if (!promise) {
193+
promise = lsp_promise.catch(e => {
194+
console.warn('LSP: hint failed', e);
195+
return this.fallback_connector
196+
.fetch(request)
197+
.then(this.transform_reply);
198+
});
199+
}
199200
} catch (e) {
200201
console.warn('LSP: kernel completions failed', e);
201-
return this.fallback_connector.fetch(request).then(this.transform_reply);
202+
promise = this.fallback_connector
203+
.fetch(request)
204+
.then(this.transform_reply);
202205
}
206+
207+
return promise.then(reply => {
208+
reply = this.suppress_if_needed(reply);
209+
this.trigger_kind = CompletionTriggerKind.Invoked;
210+
return reply;
211+
});
203212
}
204213

205214
async fetch_lsp(
@@ -216,6 +225,11 @@ export class LSPConnector
216225
console.log('[LSP][Completer] Fetching and Transforming');
217226
console.log('[LSP][Completer] Token:', token, start, end);
218227

228+
const trigger_kind =
229+
this.trigger_kind == AdditionalCompletionTriggerKinds.AutoInvoked
230+
? CompletionTriggerKind.Invoked
231+
: this.trigger_kind;
232+
219233
let lspCompletionItems = ((await connection.getCompletion(
220234
cursor,
221235
{
@@ -226,7 +240,7 @@ export class LSPConnector
226240
document.document_info,
227241
false,
228242
typed_character,
229-
this.trigger_kind
243+
trigger_kind
230244
)) || []) as lsProtocol.CompletionItem[];
231245

232246
let prefix = token.value.slice(0, position_in_token + 1);
@@ -398,6 +412,19 @@ export class LSPConnector
398412
save(id: CompletionHandler.IRequest, value: void): Promise<any> {
399413
return Promise.resolve(undefined);
400414
}
415+
416+
private suppress_if_needed(reply: CompletionHandler.ICompletionItemsReply) {
417+
if (this.trigger_kind == AdditionalCompletionTriggerKinds.AutoInvoked) {
418+
if (reply.start == reply.end) {
419+
return {
420+
start: reply.start,
421+
end: reply.end,
422+
items: []
423+
};
424+
}
425+
}
426+
return reply;
427+
}
401428
}
402429

403430
/**

packages/jupyterlab-lsp/src/lsp.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ export enum CompletionTriggerKind {
4545
TriggerForIncompleteCompletions = 3
4646
}
4747

48+
export enum AdditionalCompletionTriggerKinds {
49+
AutoInvoked = 9999
50+
}
51+
52+
export type ExtendedCompletionTriggerKind =
53+
| CompletionTriggerKind
54+
| AdditionalCompletionTriggerKinds;
55+
4856
export type CompletionItemKindStrings = keyof typeof CompletionItemKind;
4957

5058
/**

0 commit comments

Comments
 (0)