@@ -66,6 +66,12 @@ type LastCompletion = {
66
66
completionList : AppCompletionList < CompletionResolveInfo > | null ;
67
67
} ;
68
68
69
+ interface CommitCharactersOptions {
70
+ checkCommitCharacters : boolean ;
71
+ defaultCommitCharacters ?: string [ ] ;
72
+ isNewIdentifierLocation ?: boolean ;
73
+ }
74
+
69
75
export class CompletionsProviderImpl implements CompletionsProvider < CompletionResolveInfo > {
70
76
constructor (
71
77
private readonly lsAndTsDocResolver : LSAndTSDocResolver ,
@@ -237,10 +243,8 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
237
243
} ,
238
244
formatSettings
239
245
) ;
240
- const addCommitCharacters =
241
- // replicating VS Code behavior https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/src/languageFeatures/completions.ts
242
- response ?. isNewIdentifierLocation !== true &&
243
- ( ! tsDoc . parserError || isInScript ( position , tsDoc ) ) ;
246
+
247
+ const commitCharactersOptions = this . getCommitCharactersOptions ( response , tsDoc , position ) ;
244
248
let completions = response ?. entries || [ ] ;
245
249
246
250
const customCompletions = eventAndSlotLetCompletions . concat ( tagCompletions ?? [ ] ) ;
@@ -289,7 +293,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
289
293
fileUrl ,
290
294
position ,
291
295
isCompletionInTag ,
292
- addCommitCharacters ,
296
+ commitCharactersOptions ,
293
297
asStore ,
294
298
existingImports
295
299
) ;
@@ -376,6 +380,27 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
376
380
}
377
381
378
382
const completionList = CompletionList . create ( completionItems , ! ! tsDoc . parserError ) ;
383
+ if (
384
+ commitCharactersOptions . checkCommitCharacters &&
385
+ commitCharactersOptions . defaultCommitCharacters ?. length
386
+ ) {
387
+ const clientSupportsItemsDefault = this . configManager
388
+ . getClientCapabilities ( )
389
+ ?. textDocument ?. completion ?. completionList ?. itemDefaults ?. includes (
390
+ 'commitCharacters'
391
+ ) ;
392
+
393
+ if ( clientSupportsItemsDefault ) {
394
+ completionList . itemDefaults = {
395
+ commitCharacters : commitCharactersOptions . defaultCommitCharacters
396
+ } ;
397
+ } else {
398
+ completionList . items . forEach ( ( item ) => {
399
+ item . commitCharacters ??= commitCharactersOptions . defaultCommitCharacters ;
400
+ } ) ;
401
+ }
402
+ }
403
+
379
404
this . lastCompletion = { key : document . getFilePath ( ) || '' , position, completionList } ;
380
405
381
406
return completionList ;
@@ -578,6 +603,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
578
603
sortText : '-1' ,
579
604
detail : info . name + ': ' + info . type ,
580
605
documentation : info . doc && { kind : MarkupKind . Markdown , value : info . doc } ,
606
+ commitCharacters : [ ] ,
581
607
textEdit : defaultTextEditRange
582
608
? TextEdit . replace ( this . cloneRange ( defaultTextEditRange ) , name )
583
609
: undefined
@@ -623,7 +649,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
623
649
uri : string ,
624
650
position : Position ,
625
651
isCompletionInTag : boolean ,
626
- addCommitCharacters : boolean ,
652
+ commitCharactersOptions : CommitCharactersOptions ,
627
653
asStore : boolean ,
628
654
existingImports : Set < string >
629
655
) : AppCompletionItem < CompletionResolveInfo > | null {
@@ -669,7 +695,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
669
695
label,
670
696
insertText,
671
697
kind : scriptElementKindToCompletionItemKind ( comp . kind ) ,
672
- commitCharacters : addCommitCharacters ? this . commitCharacters : undefined ,
698
+ commitCharacters : this . getCommitCharacters ( comp , commitCharactersOptions ) ,
673
699
// Make sure svelte component and runes take precedence
674
700
sortText : isRunesCompletion || isSvelteComp ? '-1' : comp . sortText ,
675
701
preselect : isRunesCompletion || isSvelteComp ? true : comp . isRecommended ,
@@ -734,6 +760,60 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionRe
734
760
} ;
735
761
}
736
762
763
+ private getCommitCharactersOptions (
764
+ response : ts . CompletionInfo | undefined ,
765
+ tsDoc : SvelteDocumentSnapshot ,
766
+ position : Position
767
+ ) : CommitCharactersOptions {
768
+ if ( ( ! isInScript ( position , tsDoc ) && tsDoc . parserError ) || ! response ) {
769
+ return {
770
+ checkCommitCharacters : false
771
+ } ;
772
+ }
773
+
774
+ const isNewIdentifierLocation = response . isNewIdentifierLocation ;
775
+ let defaultCommitCharacters = response . defaultCommitCharacters ;
776
+ if ( ! isNewIdentifierLocation ) {
777
+ // This actually always exists although it's optional in the type, at least in ts 5.6,
778
+ // so our commit characters are mostly fallback for older ts versions
779
+ if ( defaultCommitCharacters ) {
780
+ // this is controlled by a vscode setting that isn't available in the ts server so it isn't added to the language service
781
+ defaultCommitCharacters ?. push ( '(' ) ;
782
+ } else {
783
+ defaultCommitCharacters = this . commitCharacters ;
784
+ }
785
+ }
786
+
787
+ return {
788
+ checkCommitCharacters : true ,
789
+ defaultCommitCharacters,
790
+ isNewIdentifierLocation
791
+ } ;
792
+ }
793
+
794
+ private getCommitCharacters ( entry : ts . CompletionEntry , options : CommitCharactersOptions ) {
795
+ // https://github.com/microsoft/vscode/blob/d012408e88ffabd6456c367df4d343654da2eb10/extensions/typescript-language-features/src/languageFeatures/completions.ts#L504
796
+ if ( ! options . checkCommitCharacters ) {
797
+ return undefined ;
798
+ }
799
+
800
+ const commitCharacters = entry . commitCharacters ;
801
+ // Ambient JS word based suggestions
802
+ const skipCommitCharacters =
803
+ entry . kind === ts . ScriptElementKind . warning ||
804
+ entry . kind === ts . ScriptElementKind . string ;
805
+
806
+ if ( commitCharacters ) {
807
+ if ( ! options . isNewIdentifierLocation && ! skipCommitCharacters ) {
808
+ return commitCharacters . concat ( '(' ) ;
809
+ }
810
+
811
+ return commitCharacters ;
812
+ }
813
+
814
+ return skipCommitCharacters ? [ ] : undefined ;
815
+ }
816
+
737
817
private isExistingSvelteComponentImport (
738
818
snapshot : SvelteDocumentSnapshot ,
739
819
name : string ,
0 commit comments