From 118c8dd62096f583cd874cd023cdece9f129dd1d Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 3 Jul 2022 14:54:27 +0200 Subject: [PATCH 1/3] (fix) better component completions in certain cases The new transformation shows global completions on components in some situations. This extra logic should fix that. --- .../typescript/ComponentInfoProvider.ts | 14 ++- .../typescript/features/CompletionProvider.ts | 95 +++++++++++++++---- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/packages/language-server/src/plugins/typescript/ComponentInfoProvider.ts b/packages/language-server/src/plugins/typescript/ComponentInfoProvider.ts index a114f645a..ae9a59133 100644 --- a/packages/language-server/src/plugins/typescript/ComponentInfoProvider.ts +++ b/packages/language-server/src/plugins/typescript/ComponentInfoProvider.ts @@ -8,7 +8,8 @@ export type ComponentPartInfo = ReturnType; export interface ComponentInfoProvider { getEvents(): ComponentPartInfo; getSlotLets(slot?: string): ComponentPartInfo; - getProps(propName: string): ts.CompletionEntry[]; + getProps(): ComponentPartInfo; + getProp(propName: string): ts.CompletionEntry[]; } export class JsOrTsComponentInfoProvider implements ComponentInfoProvider { @@ -45,7 +46,16 @@ export class JsOrTsComponentInfoProvider implements ComponentInfoProvider { return this.mapPropertiesOfType(slotLetsType); } - getProps(propName: string): ts.CompletionEntry[] { + getProps() { + const props = this.getType('$$prop_def'); + if (!props) { + return []; + } + + return this.mapPropertiesOfType(props); + } + + getProp(propName: string): ts.CompletionEntry[] { const props = this.getType('$$prop_def'); if (!props) { return []; diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index dd27474d9..29a8cbc59 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -3,6 +3,7 @@ import { CancellationToken, CompletionContext, CompletionItem, + CompletionItemKind, CompletionList, CompletionTriggerKind, MarkupContent, @@ -197,6 +198,32 @@ export class CompletionsProviderImpl implements CompletionsProvider 500 && + svelteNode?.type === 'InlineComponent' && + [' ', ' >', ' /'].includes( + document.getText().substring(originalOffset - 1, originalOffset + 1) + ) + ) { + // Very likely false global completions inside component start tag -> narrow + const props = + componentInfo + ?.getProps() + .map((entry) => + this.componentInfoToCompletionEntry( + entry, + '', + CompletionItemKind.Field, + document, + wordRange + ) + ) || []; + return CompletionList.create( + [...eventAndSlotLetCompletions, ...props], + !!tsDoc.parserError + ); + } + const existingImports = this.getExistingImports(document); const wordRangeStartPosition = document.positionAt(wordRange.start); const completionItems = completions @@ -255,33 +282,59 @@ export class CompletionsProviderImpl implements CompletionsProvider> { if (componentInfo === null) { return []; } + return [ + ...componentInfo + .getEvents() + .map((event) => + this.componentInfoToCompletionEntry( + event, + 'on:', + undefined, + document, + wordRange + ) + ), + ...componentInfo + .getSlotLets() + .map((slot) => + this.componentInfoToCompletionEntry( + slot, + 'let:', + undefined, + document, + wordRange + ) + ) + ]; + } + + private componentInfoToCompletionEntry( + info: ComponentPartInfo[0], + prefix: string, + kind: CompletionItemKind | undefined, + doc: Document, + wordRange: { start: number; end: number } + ): AppCompletionItem { const { start, end } = wordRange; - const events = componentInfo.getEvents().map((event) => mapToCompletionEntry(event, 'on:')); - const slotLets = componentInfo - .getSlotLets() - .map((slot) => mapToCompletionEntry(slot, 'let:')); - return [...events, ...slotLets]; - - function mapToCompletionEntry(info: ComponentPartInfo[0], prefix: string) { - const slotName = prefix + info.name; - return { - label: slotName, - sortText: '-1', - detail: info.name + ': ' + info.type, - documentation: info.doc && { kind: MarkupKind.Markdown, value: info.doc }, - textEdit: - start !== end - ? TextEdit.replace(toRange(doc.getText(), start, end), slotName) - : undefined - }; - } + const name = prefix + info.name; + return { + label: name, + kind: kind, + sortText: '-1', + detail: info.name + ': ' + info.type, + documentation: info.doc && { kind: MarkupKind.Markdown, value: info.doc }, + textEdit: + start !== end + ? TextEdit.replace(toRange(doc.getText(), start, end), name) + : undefined + }; } private toCompletionItem( @@ -677,7 +730,7 @@ export class CompletionsProviderImpl implements CompletionsProvider ({ + return componentInfo.getProp(jsxAttribute.name.getText()).map((item) => ({ ...item, replacementSpan })); From 8a1789d04c2ec49dae51165c4d0874da3f0c76be Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 3 Jul 2022 15:07:04 +0200 Subject: [PATCH 2/3] tests, lint --- .../typescript/features/CompletionProvider.ts | 2 +- .../typescript/features/CompletionProvider.test.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index 29a8cbc59..1d600ff07 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -326,7 +326,7 @@ export class CompletionsProviderImpl implements CompletionsProvider Date: Mon, 4 Jul 2022 12:16:20 +0200 Subject: [PATCH 3/3] filter wrong element global completions --- .../plugins/typescript/features/CompletionProvider.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts index 1d600ff07..544a24c15 100644 --- a/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CompletionProvider.ts @@ -198,6 +198,15 @@ export class CompletionsProviderImpl implements CompletionsProvider 500 && + svelteNode?.type === 'Element' && + completions[0].kind !== ts.ScriptElementKind.memberVariableElement + ) { + // False global completions inside element start tag + return null; + } + if ( completions.length > 500 && svelteNode?.type === 'InlineComponent' &&