Skip to content

Commit d5c5c3e

Browse files
committed
[Autocomplete] Fix trigger character; relax filtering
1 parent d751f90 commit d5c5c3e

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

lib/main/atom/autoCompleteProvider.ts

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
import * as Atom from "atom"
33
import * as ACP from "atom/autocomplete-plus"
44
import * as fuzzaldrin from "fuzzaldrin"
5-
import {CompletionEntryDetails, CompletionEntryIdentifier} from "typescript/lib/protocol"
5+
import {
6+
CompletionEntryDetails,
7+
CompletionEntryIdentifier,
8+
CompletionsTriggerCharacter,
9+
} from "typescript/lib/protocol"
610
import {GetClientFunction, TSClient} from "../../client"
711
import {handlePromise} from "../../utils"
812
import {ApplyEdits} from "../pluginManager"
@@ -58,10 +62,10 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
5862
if (!location) return []
5963

6064
// Don't auto-show autocomplete if prefix is empty unless last character is '.'
61-
if (!prefix && !opts.activatedManually) {
62-
const lastChar = getLastNonWhitespaceChar(opts.editor.getBuffer(), opts.bufferPosition)
63-
if (lastChar !== ".") return []
64-
}
65+
const triggerCharacter = getTrigger(
66+
getLastNonWhitespaceChar(opts.editor.getBuffer(), opts.bufferPosition),
67+
)
68+
if (!prefix && !opts.activatedManually && !triggerCharacter) return []
6569

6670
// Don't show autocomplete if we're in a string.template and not in a template expression
6771
if (
@@ -72,7 +76,12 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
7276
}
7377

7478
try {
75-
let suggestions = await this.getSuggestionsWithCache(prefix, location, opts.activatedManually)
79+
let suggestions = await this.getSuggestionsWithCache({
80+
prefix,
81+
location,
82+
triggerCharacter,
83+
activatedManually: opts.activatedManually,
84+
})
7685

7786
suggestions = fuzzaldrin.filter(suggestions, prefix, {
7887
key: "displayText",
@@ -181,11 +190,17 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
181190
}
182191

183192
// Try to reuse the last completions we got from tsserver if they're for the same position.
184-
private async getSuggestionsWithCache(
185-
prefix: string,
186-
location: FileLocationQuery,
187-
activatedManually: boolean,
188-
): Promise<SuggestionWithDetails[]> {
193+
private async getSuggestionsWithCache({
194+
prefix,
195+
location,
196+
triggerCharacter,
197+
activatedManually,
198+
}: {
199+
prefix: string
200+
location: FileLocationQuery
201+
triggerCharacter?: CompletionsTriggerCharacter
202+
activatedManually: boolean
203+
}): Promise<SuggestionWithDetails[]> {
189204
if (this.lastSuggestions && !activatedManually) {
190205
const lastLoc = this.lastSuggestions.location
191206
const lastCol = getNormalizedCol(this.lastSuggestions.prefix, lastLoc.offset)
@@ -199,7 +214,11 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
199214
}
200215

201216
const client = await this.getClient(location.file)
202-
const suggestions = await getSuggestionsInternal(client, location, prefix, activatedManually)
217+
const suggestions = await getSuggestionsInternal({
218+
client,
219+
location,
220+
triggerCharacter: activatedManually ? undefined : triggerCharacter,
221+
})
203222

204223
this.lastSuggestions = {
205224
client,
@@ -213,19 +232,21 @@ export class AutocompleteProvider implements ACP.AutocompleteProvider {
213232
}
214233
}
215234

216-
async function getSuggestionsInternal(
217-
client: TSClient,
218-
location: FileLocationQuery,
219-
prefix: string,
220-
activatedManually: boolean,
221-
) {
235+
async function getSuggestionsInternal({
236+
client,
237+
location,
238+
triggerCharacter,
239+
}: {
240+
client: TSClient
241+
location: FileLocationQuery
242+
triggerCharacter?: CompletionsTriggerCharacter
243+
}) {
222244
if (parseInt(client.version.split(".")[0], 10) >= 3) {
223245
// use completionInfo
224246
const completions = await client.execute("completionInfo", {
225-
prefix,
226247
includeExternalModuleExports: false,
227248
includeInsertTextCompletions: true,
228-
triggerCharacter: activatedManually ? undefined : (prefix.slice(-1) as any),
249+
triggerCharacter,
229250
...location,
230251
})
231252
return completions.body!.entries.map(
@@ -234,7 +255,6 @@ async function getSuggestionsInternal(
234255
} else {
235256
// use deprecated completions
236257
const completions = await client.execute("completions", {
237-
prefix,
238258
includeExternalModuleExports: false,
239259
includeInsertTextCompletions: true,
240260
...location,
@@ -392,3 +412,25 @@ const kindMap: {[key in protocol.ScriptElementKind]: ACPCompletionType | undefin
392412
index: undefined,
393413
construct: undefined,
394414
}
415+
416+
// This may look strange, but it guarantees the list is consistent with the type
417+
const triggerCharactersMap: {[K in CompletionsTriggerCharacter]: null} = {
418+
".": null,
419+
'"': null,
420+
"'": null,
421+
"`": null,
422+
"/": null,
423+
"@": null,
424+
"<": null,
425+
"#": null,
426+
}
427+
const triggerCharacters = new Set<CompletionsTriggerCharacter>(Object.keys(triggerCharactersMap))
428+
function getTrigger(prefix: string | undefined): CompletionsTriggerCharacter | undefined {
429+
if (prefix === undefined) return undefined
430+
if (!prefix) return undefined
431+
const c = prefix.slice(-1)
432+
if (triggerCharacters.has(c as CompletionsTriggerCharacter)) {
433+
return c as CompletionsTriggerCharacter
434+
}
435+
return undefined
436+
}

lib/typings/typings.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ namespace NodeJS {
1818
activateUvLoop: () => void
1919
}
2020
}
21+
22+
interface ObjectConstructor {
23+
keys<T>(o: T): Array<keyof T>
24+
}

0 commit comments

Comments
 (0)