feat: completion snippets#3949
Conversation
f981cd0 to
07b3ca6
Compare
There was a problem hiding this comment.
Pull request overview
Adds snippet-aware completion behavior to the Go-based TypeScript language service port (tsgo), including new user preference flags, richer completion items (snippets/label details/additional edits), and updated fourslash conversion + generated tests to validate the new completion shapes.
Changes:
- Implement snippet-based completion entries for class member stubs, object-literal method stubs, and import-statement completions (including label details and additional text edits where applicable).
- Add new
UserPreferencesflags controlling snippet text and label-details behavior, and thread them through completion generation. - Update fourslash harness + conversion scripts and regenerate/add tests to cover the new completion item shapes and preferences.
Reviewed changes
Copilot reviewed 60 out of 84 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| internal/ls/utilities.go | Fix single-quote quote() output to include surrounding quotes (used by snippet generation). |
| internal/ls/string_completions.go | Update completion item construction for new additionalTextEdits parameter. |
| internal/ls/lsutil/userpreferences.go | Add snippet/label-details completion preference flags and clean up struct tags/comments. |
| internal/ls/completions.go | Main implementation of snippet completions (class member stubs, object-literal method stubs, import statement completions), plus new sort text helpers and completion item plumbing. |
| internal/ls/codeactions_missingmemberfixer.go | Extend missing-member fixer to support abstract context and safer auto-import symbol handling. |
| internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go | Update call site for new missing-member fixer signature. |
| internal/ls/change/trackerimpl.go | Export GetFormatCodeSettingsForWriting for reuse by snippet formatting paths. |
| internal/ls/autoimport/view.go | Add a nil-safe/availability-checked export lookup helper for auto-import views. |
| internal/ls/autoimport/import_adder.go | Make auto-import export lookup resilient when the view index isn’t available by falling back to the direct export. |
| internal/ls/autoimport/extract.go | Exclude pattern ambient modules from ambient module export extraction. |
| internal/fourslash/tests/completionClassMembersAfterConstAssertionInitializer_test.go | Update expected completion to include inserted text for a class member. |
| internal/fourslash/fourslash.go | Improve preference override handling during tests; adjust strictness/normalization in completion comparisons; set CRLF for Strada server tests. |
| internal/fourslash/_scripts/unparsedTests.txt | Update parsing error messages to reflect improved conversion handling for sources/sortText. |
| internal/fourslash/_scripts/failingTests.txt | Remove several tests from failing list as conversions/expectations are now supported. |
| internal/fourslash/_scripts/convertFourslash.mts | Extend converter to handle format options, completion sources, labelDetails, preferences, and object-literal sortText helpers. |
| internal/checker/nodecopy.go | Preserve qualifier symbol links when copying import() type nodes. |
| internal/fourslash/tests/gen/jsxTagNameCompletionWithExistingJsxInitializer_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementUnclosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxTagNameCompletionUnderElementClosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxTagNameCompletionUnclosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxTagNameCompletionClosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxAttributeSnippetCompletionUnclosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxAttributeSnippetCompletionClosed_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxAttributeSnippetCompletionAfterTypeArgs_test.go | Regenerated: pass snippet-enabled user preferences for JSX attribute snippet behavior. |
| internal/fourslash/tests/gen/jsxAttributeCompletionStyleNoSnippet_test.go | Regenerated: set preferences to explicitly disable snippet text. |
| internal/fourslash/tests/gen/jsxAttributeCompletionStyleNone_test.go | Regenerated: include snippet-text preference alongside none style. |
| internal/fourslash/tests/gen/jsxAttributeCompletionStyleDefault_test.go | Regenerated: include snippet-text preference. |
| internal/fourslash/tests/gen/jsxAttributeCompletionStyleBraces_test.go | Regenerated: include snippet-text preference and braces style. |
| internal/fourslash/tests/gen/jsxAttributeCompletionStyleAuto_test.go | Regenerated: include snippet-text preference and auto style. |
| internal/fourslash/tests/gen/importStatementCompletions_semicolons_test.go | New/regenerated: verify snippet import statement completions respect semicolon preference. |
| internal/fourslash/tests/gen/importStatementCompletions_quotes_test.go | New/regenerated: verify snippet import statement completions respect quote preference. |
| internal/fourslash/tests/gen/importStatementCompletions_pnpmTransitive_test.go | New/regenerated: verify import statement completions with pnpm transitive layout. |
| internal/fourslash/tests/gen/importStatementCompletions_pnpm1_test.go | New/regenerated: verify import statement completions with pnpm layout. |
| internal/fourslash/tests/gen/importStatementCompletions_noSnippet_test.go | New/regenerated: verify non-snippet import statement completion shape. |
| internal/fourslash/tests/gen/importStatementCompletions_noPatternAmbient_test.go | New/regenerated: verify pattern ambient modules are excluded from import statement completions. |
| internal/fourslash/tests/gen/importStatementCompletions_js2_test.go | New/regenerated: verify import statement completions in JS (variant). |
| internal/fourslash/tests/gen/importStatementCompletions_js_test.go | New/regenerated: verify import statement completions in JS. |
| internal/fourslash/tests/gen/importStatementCompletions_esModuleInterop2_test.go | New/regenerated: verify import statement completions with esModuleInterop (variant). |
| internal/fourslash/tests/gen/importStatementCompletions_esModuleInterop1_test.go | New/regenerated: verify import statement completions with esModuleInterop. |
| internal/fourslash/tests/gen/completionsOverridingProperties3_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingProperties2_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingProperties1_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethodDefaultExported_test.go | New/regenerated: validate class member stub completion with default-exported return types and import edits. |
| internal/fourslash/tests/gen/completionsOverridingMethodCrash2_test.go | New/regenerated: regression coverage for previous crash scenario with snippet class member completions. |
| internal/fourslash/tests/gen/completionsOverridingMethodCrash1_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod9_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod8_test.go | New/regenerated: validate class member snippet completion + apply code action updates. |
| internal/fourslash/tests/gen/completionsOverridingMethod7_test.go | New/regenerated: validate abstract overload completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod6_test.go | New/regenerated: validate modifier handling and excludes/includes across scenarios. |
| internal/fourslash/tests/gen/completionsOverridingMethod5_test.go | New/regenerated: validate abstract vs non-abstract stub generation. |
| internal/fourslash/tests/gen/completionsOverridingMethod4_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod3_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod22_test.go | New/regenerated: validate $-prefixed member completion with import edits. |
| internal/fourslash/tests/gen/completionsOverridingMethod21_test.go | New/regenerated: validate async modifier handling in overrides. |
| internal/fourslash/tests/gen/completionsOverridingMethod20_test.go | New/regenerated: validate completion when typing partial identifier with async modifier. |
| internal/fourslash/tests/gen/completionsOverridingMethod2_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod19_test.go | New/regenerated: validate robustness when non-modifier identifiers are present in modifier positions. |
| internal/fourslash/tests/gen/completionsOverridingMethod18_test.go | New/regenerated: validate decorator preservation in generated member stubs. |
| internal/fourslash/tests/gen/completionsOverridingMethod17_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod14_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod12_test.go | New/regenerated: validate accessor override stub completion for abstract/override scenarios. |
| internal/fourslash/tests/gen/completionsOverridingMethod11_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod10_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod1_test.go | Regenerated: set snippet preferences for class member snippet completion behavior. |
| internal/fourslash/tests/gen/completionsOverridingMethod0_test.go | New/regenerated: broad baseline coverage for override stub completions. |
| internal/fourslash/tests/gen/completionsObjectLiteralMethod5_test.go | New/regenerated: validate object-literal method snippet insertion + sortText ordering. |
| internal/fourslash/tests/gen/completionsObjectLiteralMethod4_test.go | New/regenerated: validate this parameter handling in object-literal method snippets. |
| internal/fourslash/tests/gen/completionsObjectLiteralMethod3_test.go | New/regenerated: validate union/intersection and optional member behavior for object-literal method snippets. |
| internal/fourslash/tests/gen/completionsObjectLiteralMethod2_test.go | New/regenerated: validate cross-file type references for object-literal method snippets. |
| internal/fourslash/tests/gen/completionsObjectLiteralMethod1_test.go | New/regenerated: validate overload/quoted names and labelDetails behavior for object-literal method snippets. |
| internal/fourslash/tests/gen/completionsJsxExpression_test.go | Regenerated: set snippet-text preference for JSX expression completions. |
| internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go | Regenerated: set class member snippet preference for import-type-node cases. |
| internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go | Regenerated: set class member snippet preference for import-type-node cases. |
| internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_test.go | Regenerated: set class member snippet preference for import-type-node cases. |
| internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go | Regenerated: set class member snippet preference for import-type-node cases. |
| internal/fourslash/tests/gen/completionEntryClassMembersWithInferredFunctionReturnType1_test.go | Regenerated: set class member snippet preference for inferred return types. |
| internal/fourslash/tests/gen/completionCloneQuestionToken_test.go | Regenerated: set class member snippet preference for optional members. |
| internal/fourslash/tests/gen/completionClassMemberSnippetCrossFileNodeReuse1_test.go | New/regenerated: validate snippet generation without cross-file node reuse issues. |
| internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go | Regenerated: set class member snippet preference in auto-import augmentation scenarios. |
| internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go | Regenerated: set class member snippet preference in auto-import augmentation scenarios. |
| internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go | Regenerated: set class member snippet preference in auto-import augmentation scenarios. |
| internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go | Regenerated: set class member snippet preference in auto-import augmentation scenarios. |
| internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go | Regenerated: set class member snippet preference for export-equals-with-default scenarios. |
| internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go | Regenerated: set class member snippet preference for ambient merged module scenarios. |
Files not reviewed (24)
- internal/fourslash/tests/gen/autoImportCompletionAmbientMergedModule1_test.go: Language not supported
- internal/fourslash/tests/gen/autoImportCompletionExportEqualsWithDefault1_test.go: Language not supported
- internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation1_test.go: Language not supported
- internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation2_test.go: Language not supported
- internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation3_test.go: Language not supported
- internal/fourslash/tests/gen/autoImportCompletionExportListAugmentation4_test.go: Language not supported
- internal/fourslash/tests/gen/completionClassMemberSnippetCrossFileNodeReuse1_test.go: Language not supported
- internal/fourslash/tests/gen/completionCloneQuestionToken_test.go: Language not supported
- internal/fourslash/tests/gen/completionEntryClassMembersWithInferredFunctionReturnType1_test.go: Language not supported
- internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter1_test.go: Language not supported
- internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter2_test.go: Language not supported
- internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter3_test.go: Language not supported
- internal/fourslash/tests/gen/completionsClassMemberImportTypeNodeParameter4_test.go: Language not supported
- internal/fourslash/tests/gen/completionsJsxExpression_test.go: Language not supported
- internal/fourslash/tests/gen/completionsObjectLiteralMethod1_test.go: Language not supported
- internal/fourslash/tests/gen/completionsObjectLiteralMethod2_test.go: Language not supported
- internal/fourslash/tests/gen/completionsObjectLiteralMethod3_test.go: Language not supported
- internal/fourslash/tests/gen/completionsObjectLiteralMethod4_test.go: Language not supported
- internal/fourslash/tests/gen/completionsObjectLiteralMethod5_test.go: Language not supported
- internal/fourslash/tests/gen/completionsOverridingMethod0_test.go: Language not supported
- internal/fourslash/tests/gen/completionsOverridingMethod10_test.go: Language not supported
- internal/fourslash/tests/gen/completionsOverridingMethod11_test.go: Language not supported
- internal/fourslash/tests/gen/completionsOverridingMethod12_test.go: Language not supported
- internal/fourslash/tests/gen/completionsOverridingMethod14_test.go: Language not supported
…yuk/typescript-go into feat/completion-snippets
…o feat/completion-snippets
…o feat/completion-snippets
…yuk/typescript-go into feat/completion-snippets
|
|
||
| func (f *missingMemberFixer) shouldAddOverrideKeyword(declaration *ast.Node) bool { | ||
| return declaration != nil && f.program.Options().NoImplicitOverride.IsTrue() && ast.HasAbstractModifier(declaration) | ||
| return declaration != nil && f.program.Options().NoImplicitOverride.IsTrue() && ast.IsClassElement(declaration) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Hmm, yeah, the original code seems wrong, but shouldn't we be checking that the declaration comes from a class? Since it could also come from an interface. I don't think IsClassElement does that, despite the name.
There was a problem hiding this comment.
I've changed to check the parent class context
…o feat/completion-snippets
effa665 to
b686dd4
Compare
| originalSortText := core.OrElse(symbolToSortTextMap[symbolId], SortTextLocationPriority) | ||
| symbolToSortTextMap[symbolId] = ObjectLiteralPropertySortText(originalSortText, displayName) | ||
| } | ||
| entry := l.getEntryForObjectLiteralMethodCompletion(ctx, typeChecker, member, objectLikeContainer, file) |
There was a problem hiding this comment.
Shouldn't we opt out if we're in a JS file?
| NewLine: core.GetNewLineKind(l.FormatOptions().NewLineCharacter), | ||
| Target: l.GetProgram().Options().GetEmitScriptTarget(), | ||
| }, printer.PrintHandlers{}, nil /*emitContext*/) | ||
| return strings.TrimSuffix(signaturePrinter.Emit(methodSignature, file), ";") |
There was a problem hiding this comment.
Can you add a comment for a todo here? like // !!! OmitTrailingSemicolon printer option so we know this is a temporary thing because we don't have that option yet.
There was a problem hiding this comment.
I added support for OmitTrailingSemicolon. Not sure if that’s appropriate for this PR, though.
| } | ||
|
|
||
| func (l *LanguageService) getEntryForObjectLiteralMethodCompletion(ctx context.Context, typeChecker *checker.Checker, symbol *ast.Symbol, enclosingDeclaration *ast.Node, file *ast.SourceFile) *symbolOriginInfoObjectLiteralMethod { | ||
| method := l.createObjectLiteralMethod(typeChecker, symbol, enclosingDeclaration, file) |
There was a problem hiding this comment.
I think related to my comment on skipping for JS files, we seem to be missing stuff that is in collectObjectLiteralMethodSymbols in Strada, like the isObjectLiteralMethodSymbol check.
| return factory.NewModifierList(nodes) | ||
| } | ||
|
|
||
| func addClassMemberSnippet(text string, newLine string) string { |
There was a problem hiding this comment.
I don't know that I like this. I may need to think about how we should do snippets in Corsa.
There was a problem hiding this comment.
I added support for snippet elements and removed the string-based snippet normalization.
| } | ||
| view, err := l.getPreparedAutoImportView(file) | ||
| if err != nil { | ||
| view = l.getCurrentAutoImportView(file) |
There was a problem hiding this comment.
I think this needs to return an error, like we do for exhaustive case completions, so that we then redo the completion requests with the autoimport view.
c1bed17 to
1871214
Compare
…o feat/completion-snippets
1871214 to
cb13b5f
Compare
Fixes #2279