Skip to content

Commit 06b5873

Browse files
Fix Symbol completion priority and cursor positioning
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
1 parent c39f1bb commit 06b5873

File tree

7 files changed

+50
-20
lines changed

7 files changed

+50
-20
lines changed

src/services/completions.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,10 +1730,16 @@ function createCompletionEntry(
17301730
}
17311731
// We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790.
17321732
// Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro.
1733-
else if ((useBraces || insertQuestionDot) && propertyAccessToConvert) {
1734-
insertText = useBraces ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` : name;
1735-
if (insertQuestionDot || propertyAccessToConvert.questionDotToken) {
1736-
insertText = `?.${insertText}`;
1733+
else if ((useBraces || insertQuestionDot) && propertyAccessToConvert) {
1734+
if (useBraces && preferences.includeCompletionsWithSnippetText) {
1735+
// For symbol completions, position cursor inside brackets for better UX
1736+
insertText = needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}$0]` : `[${name}$0]`;
1737+
isSnippet = true;
1738+
} else {
1739+
insertText = useBraces ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` : name;
1740+
}
1741+
if (insertQuestionDot || propertyAccessToConvert.questionDotToken) {
1742+
insertText = `?.${insertText}`;
17371743
}
17381744

17391745
const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) ||
@@ -3848,9 +3854,13 @@ function getCompletionData(
38483854
// If this is nested like for `namespace N { export const sym = Symbol(); }`, we'll add the completion for `N`.
38493855
const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker);
38503856
const firstAccessibleSymbolId = firstAccessibleSymbol && getSymbolId(firstAccessibleSymbol);
3851-
if (firstAccessibleSymbolId && addToSeen(seenPropertySymbols, firstAccessibleSymbolId)) {
3852-
const index = symbols.length;
3853-
symbols.push(firstAccessibleSymbol);
3857+
if (firstAccessibleSymbolId && addToSeen(seenPropertySymbols, firstAccessibleSymbolId)) {
3858+
const index = symbols.length;
3859+
symbols.push(firstAccessibleSymbol);
3860+
3861+
// Symbol completions should have lower priority since they represent computed property access
3862+
symbolToSortTextMap[getSymbolId(firstAccessibleSymbol)] = SortText.GlobalsOrKeywords;
3863+
38543864
const moduleSymbol = firstAccessibleSymbol.parent;
38553865
if (
38563866
!moduleSymbol ||

tests/baselines/reference/completionsUniqueSymbol2.baseline

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"name": "a",
5757
"kind": "const",
5858
"kindModifiers": "",
59-
"sortText": "11",
59+
"sortText": "15",
6060
"insertText": "[a]",
6161
"replacementSpan": {
6262
"start": 344,
@@ -210,7 +210,7 @@
210210
"name": "b",
211211
"kind": "const",
212212
"kindModifiers": "",
213-
"sortText": "11",
213+
"sortText": "15",
214214
"insertText": "[b]",
215215
"replacementSpan": {
216216
"start": 344,

tests/cases/fourslash/completionForComputedStringProperties.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
//// declare const a: A;
99
//// a[|./**/|]
1010

11-
verify.completions({
12-
marker: "",
13-
exact: [
14-
{ name: "p1" },
15-
{ name: "p2", insertText: '[p2]', replacementSpan: test.ranges()[0] },
16-
],
17-
preferences: { includeInsertTextCompletions: true },
11+
verify.completions({
12+
marker: "",
13+
exact: [
14+
{ name: "p1" },
15+
{ name: "p2", insertText: '[p2]', sortText: completion.SortText.GlobalsOrKeywords, replacementSpan: test.ranges()[0] },
16+
],
17+
preferences: { includeInsertTextCompletions: true },
1818
});

tests/cases/fourslash/completionsSymbolMembers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
verify.completions(
1515
{
1616
marker: "i",
17-
exact: { name: "s", insertText: "[s]", replacementSpan: test.ranges()[0] },
17+
exact: { name: "s", insertText: "[s]", sortText: completion.SortText.GlobalsOrKeywords, replacementSpan: test.ranges()[0] },
1818
preferences: { includeInsertTextCompletions: true },
1919
},
2020
{
2121
marker: "j",
22-
exact: { name: "N", insertText: "[N]", replacementSpan: test.ranges()[1] },
22+
exact: { name: "N", insertText: "[N]", sortText: completion.SortText.GlobalsOrKeywords, replacementSpan: test.ranges()[1] },
2323
preferences: { includeInsertTextCompletions: true },
2424
}
2525
);

tests/cases/fourslash/completionsUniqueSymbol1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717

1818
verify.completions({
1919
marker: "",
20-
exact: { name: "M", insertText: "[M]", replacementSpan: test.ranges()[0] },
20+
exact: { name: "M", insertText: "[M]", sortText: completion.SortText.GlobalsOrKeywords, replacementSpan: test.ranges()[0] },
2121
preferences: { includeInsertTextCompletions: true },
2222
});

tests/cases/fourslash/completionsUniqueSymbol_import.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ verify.completions({
2424
marker: "",
2525
exact: [
2626
"n",
27-
{ name: "publicSym", source: "/a", insertText: "[publicSym]", replacementSpan: test.ranges()[0], hasAction: true },
27+
{ name: "publicSym", source: "/a", insertText: "[publicSym]", sortText: completion.SortText.GlobalsOrKeywords, replacementSpan: test.ranges()[0], hasAction: true },
2828
],
2929
preferences: {
3030
includeInsertTextCompletions: true,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////declare const Symbol: (s: string) => symbol;
4+
////const mySymbol = Symbol("test");
5+
////interface TestInterface {
6+
//// [mySymbol]: string;
7+
//// normalProperty: number;
8+
////}
9+
////const obj: TestInterface = {} as any;
10+
////obj./*completions*/
11+
12+
// Test new behavior: Symbol completions should have lower priority and better cursor positioning
13+
verify.completions({
14+
marker: "completions",
15+
includes: [
16+
{ name: "normalProperty", sortText: completion.SortText.LocationPriority },
17+
{ name: "mySymbol", sortText: completion.SortText.GlobalsOrKeywords, insertText: "[mySymbol$0]", isSnippet: true } // Now with snippet cursor positioning
18+
],
19+
preferences: { includeInsertTextCompletions: true, includeCompletionsWithSnippetText: true }
20+
});

0 commit comments

Comments
 (0)