Skip to content

Commit

Permalink
use commit characters from typescript when possible
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonlyu123 committed Oct 26, 2024
1 parent fe1314f commit 8be6336
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 10 deletions.
21 changes: 20 additions & 1 deletion packages/language-server/src/plugins/PluginHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,22 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
});
}

let itemDefaults: CompletionList['itemDefaults'];
if (completions.length === 1) {
itemDefaults = completions[0]?.result.itemDefaults;
} else {
// don't apply items default to the result of other plugins
for (const completion of completions) {
const itemDefaults = completion.result.itemDefaults;
if (!itemDefaults) {
continue;
}
completion.result.items.forEach((item) => {
item.commitCharacters ??= itemDefaults.commitCharacters;
});
}
}

let flattenedCompletions = flatten(
completions.map((completion) => completion.result.items)
);
Expand All @@ -194,7 +210,10 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
);
}

return CompletionList.create(flattenedCompletions, isIncomplete);
const result = CompletionList.create(flattenedCompletions, isIncomplete);
result.itemDefaults = itemDefaults;

return result;
}

async resolveCompletion(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ type LastCompletion = {
completionList: AppCompletionList<CompletionResolveInfo> | null;
};

interface CommitCharactersOptions {
checkCommitCharacters: boolean;
defaultCommitCharacters?: string[];
isNewIdentifierLocation?: boolean;
}

export class CompletionsProviderImpl implements CompletionsProvider<CompletionResolveInfo> {
constructor(
private readonly lsAndTsDocResolver: LSAndTSDocResolver,
Expand Down Expand Up @@ -237,10 +243,8 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
},
formatSettings
);
const addCommitCharacters =
// replicating VS Code behavior https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/src/languageFeatures/completions.ts
response?.isNewIdentifierLocation !== true &&
(!tsDoc.parserError || isInScript(position, tsDoc));

const commitCharactersOptions = this.getCommitCharactersOptions(response, tsDoc, position);
let completions = response?.entries || [];

const customCompletions = eventAndSlotLetCompletions.concat(tagCompletions ?? []);
Expand Down Expand Up @@ -289,7 +293,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
fileUrl,
position,
isCompletionInTag,
addCommitCharacters,
commitCharactersOptions,
asStore,
existingImports
);
Expand Down Expand Up @@ -376,6 +380,27 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
}

const completionList = CompletionList.create(completionItems, !!tsDoc.parserError);
if (
commitCharactersOptions.checkCommitCharacters &&
commitCharactersOptions.defaultCommitCharacters?.length
) {
const clientSupportsItemsDefault = this.configManager
.getClientCapabilities()
?.textDocument?.completion?.completionList?.itemDefaults?.includes(
'commitCharacters'
);

if (clientSupportsItemsDefault) {
completionList.itemDefaults = {
commitCharacters: commitCharactersOptions.defaultCommitCharacters
};
} else {
completionList.items.forEach((item) => {
item.commitCharacters ??= commitCharactersOptions.defaultCommitCharacters;
});
}
}

this.lastCompletion = { key: document.getFilePath() || '', position, completionList };

return completionList;
Expand Down Expand Up @@ -578,6 +603,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
sortText: '-1',
detail: info.name + ': ' + info.type,
documentation: info.doc && { kind: MarkupKind.Markdown, value: info.doc },
commitCharacters: [],
textEdit: defaultTextEditRange
? TextEdit.replace(this.cloneRange(defaultTextEditRange), name)
: undefined
Expand Down Expand Up @@ -623,7 +649,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
uri: string,
position: Position,
isCompletionInTag: boolean,
addCommitCharacters: boolean,
commitCharactersOptions: CommitCharactersOptions,
asStore: boolean,
existingImports: Set<string>
): AppCompletionItem<CompletionResolveInfo> | null {
Expand Down Expand Up @@ -669,7 +695,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
label,
insertText,
kind: scriptElementKindToCompletionItemKind(comp.kind),
commitCharacters: addCommitCharacters ? this.commitCharacters : undefined,
commitCharacters: this.getCommitCharacters(comp, commitCharactersOptions),
// Make sure svelte component and runes take precedence
sortText: isRunesCompletion || isSvelteComp ? '-1' : comp.sortText,
preselect: isRunesCompletion || isSvelteComp ? true : comp.isRecommended,
Expand Down Expand Up @@ -734,6 +760,60 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
};
}

private getCommitCharactersOptions(
response: ts.CompletionInfo | undefined,
tsDoc: SvelteDocumentSnapshot,
position: Position
): CommitCharactersOptions {
if ((!isInScript(position, tsDoc) && tsDoc.parserError) || !response) {
return {
checkCommitCharacters: false
};
}

const isNewIdentifierLocation = response.isNewIdentifierLocation;
let defaultCommitCharacters = response.defaultCommitCharacters;
if (!isNewIdentifierLocation) {
// This actually always exists although it's optional in the type, at least in ts 5.6,
// so our commit characters are mostly fallback for older ts versions
if (defaultCommitCharacters) {
// this is controlled by a vscode setting that isn't available in the ts server so it isn't added to the language service
defaultCommitCharacters?.push('(');
} else {
defaultCommitCharacters = this.commitCharacters;
}
}

return {
checkCommitCharacters: true,
defaultCommitCharacters,
isNewIdentifierLocation
};
}

private getCommitCharacters(entry: ts.CompletionEntry, options: CommitCharactersOptions) {
// https://github.com/microsoft/vscode/blob/d012408e88ffabd6456c367df4d343654da2eb10/extensions/typescript-language-features/src/languageFeatures/completions.ts#L504
if (!options.checkCommitCharacters) {
return undefined;
}

const commitCharacters = entry.commitCharacters;
// Ambient JS word based suggestions
const skipCommitCharacters =
entry.kind === ts.ScriptElementKind.warning ||
entry.kind === ts.ScriptElementKind.string;

if (commitCharacters) {
if (!options.isNewIdentifierLocation && !skipCommitCharacters) {
return commitCharacters.concat('(');
}

return commitCharacters;
}

return skipCommitCharacters ? [] : undefined;
}

private isExistingSvelteComponentImport(
snapshot: SvelteDocumentSnapshot,
name: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('CompletionProviderImpl', function () {
uri: pathToUrl(filePath),
text: ts.sys.readFile(filePath) || ''
});
return { completionProvider, document, docManager };
return { completionProvider, document, docManager, lsConfigManager };
}

it('provides completions', async () => {
Expand Down Expand Up @@ -170,6 +170,34 @@ describe('CompletionProviderImpl', function () {
});
}

it('provide completion with items default when supported', async () => {
const { completionProvider, document, lsConfigManager } = setup('completions.svelte');

lsConfigManager.updateClientCapabilities({
textDocument: {
completion: {
completionList: {
itemDefaults: ['commitCharacters']
}
}
}
});

const completions = await completionProvider.getCompletions(
document,
Position.create(0, 49),
{
triggerKind: CompletionTriggerKind.TriggerCharacter,
triggerCharacter: '.'
}
);

assert.deepStrictEqual(completions?.itemDefaults?.commitCharacters, ['.', ',', ';', '(']);

const first = completions!.items[0];
assert.strictEqual(first.commitCharacters, undefined);
});

it('provides event completions', async () => {
const { completionProvider, document } = setup('component-events-completion.svelte');

Expand All @@ -191,6 +219,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(eventCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'aa: CustomEvent<boolean>',
documentation: '',
label: 'on:aa',
Expand All @@ -199,6 +228,7 @@ describe('CompletionProviderImpl', function () {
textEdit: undefined
},
{
commitCharacters: [],
detail: 'ab: MouseEvent',
documentation: {
kind: 'markdown',
Expand All @@ -210,6 +240,7 @@ describe('CompletionProviderImpl', function () {
textEdit: undefined
},
{
commitCharacters: [],
detail: 'ac: any',
documentation: '',
label: 'on:ac',
Expand Down Expand Up @@ -309,6 +340,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(eventCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'aa: CustomEvent<boolean>',
documentation: '',
label: 'on:aa',
Expand All @@ -329,6 +361,7 @@ describe('CompletionProviderImpl', function () {
}
},
{
commitCharacters: [],
detail: 'ab: MouseEvent',
documentation: {
kind: 'markdown',
Expand All @@ -352,6 +385,7 @@ describe('CompletionProviderImpl', function () {
}
},
{
commitCharacters: [],
detail: 'ac: any',
documentation: '',
label: 'on:ac',
Expand Down Expand Up @@ -389,6 +423,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(eventCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'c: CustomEvent<boolean>',
documentation: {
kind: 'markdown',
Expand Down Expand Up @@ -417,6 +452,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(eventCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'event1: CustomEvent<null>',
documentation: '',
label: 'on:event1',
Expand All @@ -437,6 +473,7 @@ describe('CompletionProviderImpl', function () {
}
},
{
commitCharacters: [],
detail: 'event2: CustomEvent<string>',
documentation: {
kind: 'markdown',
Expand Down Expand Up @@ -477,6 +514,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(eventCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'event1: CustomEvent<string> | CustomEvent<number>',
label: 'on:event1',
sortText: '-1',
Expand Down Expand Up @@ -1101,6 +1139,7 @@ describe('CompletionProviderImpl', function () {

assert.deepStrictEqual(slotLetCompletions, <CompletionItem[]>[
{
commitCharacters: [],
detail: 'let1: boolean',
documentation: '',
label: 'let:let1',
Expand All @@ -1121,6 +1160,7 @@ describe('CompletionProviderImpl', function () {
}
},
{
commitCharacters: [],
detail: 'let2: string',
documentation: {
kind: 'markdown',
Expand Down Expand Up @@ -1290,7 +1330,7 @@ describe('CompletionProviderImpl', function () {
insertText: undefined,
insertTextFormat: undefined,
labelDetails: undefined,
commitCharacters: ['.', ',', ';', '('],
commitCharacters: [],
textEdit: {
newText: '@hi',
range: {
Expand Down

0 comments on commit 8be6336

Please sign in to comment.