@@ -256,7 +256,8 @@ const (
256
256
// true otherwise.
257
257
type uniqueNamesMap = map [string ]bool
258
258
259
- type literalValue any // string | jsnum.Number | PseudoBigInt
259
+ // string | jsnum.Number | PseudoBigInt
260
+ type literalValue any
260
261
261
262
type globalsSearch int
262
263
@@ -276,7 +277,7 @@ func (l *LanguageService) getCompletionsAtPosition(
276
277
clientOptions * lsproto.CompletionClientCapabilities ,
277
278
) * lsproto.CompletionList {
278
279
_ , previousToken := getRelevantTokens (position , file )
279
- if context .TriggerCharacter != nil && ! isInString (file , position , previousToken ) && ! isValidTrigger (file , * context .TriggerCharacter , previousToken , position ) {
280
+ if context .TriggerCharacter != nil && ! IsInString (file , position , previousToken ) && ! isValidTrigger (file , * context .TriggerCharacter , previousToken , position ) {
280
281
return nil
281
282
}
282
283
@@ -294,7 +295,19 @@ func (l *LanguageService) getCompletionsAtPosition(
294
295
295
296
// !!! see if incomplete completion list and continue or clean
296
297
297
- // !!! string literal completions
298
+ stringCompletions := l .getStringLiteralCompletions (
299
+ ctx ,
300
+ file ,
301
+ position ,
302
+ previousToken ,
303
+ compilerOptions ,
304
+ program ,
305
+ preferences ,
306
+ clientOptions ,
307
+ )
308
+ if stringCompletions != nil {
309
+ return stringCompletions
310
+ }
298
311
299
312
if previousToken != nil && ast .IsBreakOrContinueStatement (previousToken .Parent ) &&
300
313
(previousToken .Kind == ast .KindBreakKeyword ||
@@ -1479,10 +1492,11 @@ func (l *LanguageService) completionInfoFromData(
1479
1492
clientOptions * lsproto.CompletionClientCapabilities ,
1480
1493
) * lsproto.CompletionList {
1481
1494
keywordFilters := data .keywordFilters
1482
- symbols := data .symbols
1483
1495
isNewIdentifierLocation := data .isNewIdentifierLocation
1484
1496
contextToken := data .contextToken
1485
1497
literals := data .literals
1498
+ typeChecker , done := program .GetTypeCheckerForFile (ctx , file )
1499
+ defer done ()
1486
1500
1487
1501
// Verify if the file is JSX language variant
1488
1502
if ast .GetLanguageVariant (file .ScriptKind ) == core .LanguageVariantJSX {
@@ -1498,17 +1512,31 @@ func (l *LanguageService) completionInfoFromData(
1498
1512
if caseClause != nil &&
1499
1513
(contextToken .Kind == ast .KindCaseKeyword ||
1500
1514
ast .IsNodeDescendantOf (contextToken , caseClause .Expression ())) {
1501
- // !!! switch completions
1515
+ tracker := newCaseClauseTracker (typeChecker , caseClause .Parent .AsCaseBlock ().Clauses .Nodes )
1516
+ literals = core .Filter (literals , func (literal literalValue ) bool {
1517
+ return ! tracker .hasValue (literal )
1518
+ })
1519
+ data .symbols = core .Filter (data .symbols , func (symbol * ast.Symbol ) bool {
1520
+ if symbol .ValueDeclaration != nil && ast .IsEnumMember (symbol .ValueDeclaration ) {
1521
+ value := typeChecker .GetConstantValue (symbol .ValueDeclaration )
1522
+ if value != nil && tracker .hasValue (value ) {
1523
+ return false
1524
+ }
1525
+ }
1526
+ return true
1527
+ })
1502
1528
}
1503
1529
1504
1530
isChecked := isCheckedFile (file , compilerOptions )
1505
- if isChecked && ! isNewIdentifierLocation && len (symbols ) == 0 && keywordFilters == KeywordCompletionFiltersNone {
1531
+ if isChecked && ! isNewIdentifierLocation && len (data . symbols ) == 0 && keywordFilters == KeywordCompletionFiltersNone {
1506
1532
return nil
1507
1533
}
1508
1534
1535
+ optionalReplacementSpan := l .getOptionalReplacementSpan (data .location , file )
1509
1536
uniqueNames , sortedEntries := l .getCompletionEntriesFromSymbols (
1510
1537
ctx ,
1511
1538
data ,
1539
+ optionalReplacementSpan ,
1512
1540
nil , /*replacementToken*/
1513
1541
position ,
1514
1542
file ,
@@ -1570,6 +1598,7 @@ func (l *LanguageService) completionInfoFromData(
1570
1598
func (l * LanguageService ) getCompletionEntriesFromSymbols (
1571
1599
ctx context.Context ,
1572
1600
data * completionDataData ,
1601
+ optionalReplacementSpan * lsproto.Range ,
1573
1602
replacementToken * ast.Node ,
1574
1603
position int ,
1575
1604
file * ast.SourceFile ,
@@ -1584,7 +1613,6 @@ func (l *LanguageService) getCompletionEntriesFromSymbols(
1584
1613
typeChecker , done := program .GetTypeCheckerForFile (ctx , file )
1585
1614
defer done ()
1586
1615
isMemberCompletion := isMemberCompletionKind (data .completionKind )
1587
- optionalReplacementSpan := getOptionalReplacementSpan (data .location , file )
1588
1616
// Tracks unique names.
1589
1617
// Value is set to false for global variables or completions from external module exports, because we can have multiple of those;
1590
1618
// true otherwise. Based on the order we add things we will always see locals first, then globals, then module exports.
@@ -1708,7 +1736,7 @@ func (l *LanguageService) createCompletionItem(
1708
1736
preferences * UserPreferences ,
1709
1737
clientOptions * lsproto.CompletionClientCapabilities ,
1710
1738
isMemberCompletion bool ,
1711
- optionalReplacementSpan * core. TextRange ,
1739
+ optionalReplacementSpan * lsproto. Range ,
1712
1740
) * lsproto.CompletionItem {
1713
1741
contextToken := data .contextToken
1714
1742
var insertText string
@@ -3110,12 +3138,11 @@ func getJSCompletionEntries(
3110
3138
return sortedEntries
3111
3139
}
3112
3140
3113
- func getOptionalReplacementSpan (location * ast.Node , file * ast.SourceFile ) * core. TextRange {
3141
+ func ( l * LanguageService ) getOptionalReplacementSpan (location * ast.Node , file * ast.SourceFile ) * lsproto. Range {
3114
3142
// StringLiteralLike locations are handled separately in stringCompletions.ts
3115
3143
if location != nil && location .Kind == ast .KindIdentifier {
3116
3144
start := astnav .GetStartOfNode (location , file , false /*includeJSDoc*/ )
3117
- textRange := core .NewTextRange (start , location .End ())
3118
- return & textRange
3145
+ return l .createLspRangeFromBounds (start , location .End (), file )
3119
3146
}
3120
3147
return nil
3121
3148
}
@@ -3934,7 +3961,7 @@ func (l *LanguageService) getJsxClosingTagCompletion(
3934
3961
tagName := jsxClosingElement .Parent .AsJsxElement ().OpeningElement .TagName ()
3935
3962
closingTag := tagName .Text ()
3936
3963
fullClosingTag := closingTag + core .IfElse (hasClosingAngleBracket , "" , ">" )
3937
- optionalReplacementSpan := core . NewTextRange (jsxClosingElement .TagName (). Pos (), jsxClosingElement . TagName (). End () )
3964
+ optionalReplacementSpan := l . createLspRangeFromNode (jsxClosingElement .TagName (), file )
3938
3965
defaultCommitCharacters := getDefaultCommitCharacters (false /*isNewIdentifierLocation*/ )
3939
3966
3940
3967
item := l .createLSPCompletionItem (
@@ -3945,7 +3972,7 @@ func (l *LanguageService) getJsxClosingTagCompletion(
3945
3972
ScriptElementKindClassElement ,
3946
3973
core.Set [ScriptElementKindModifier ]{}, /*kindModifiers*/
3947
3974
nil , /*replacementSpan*/
3948
- & optionalReplacementSpan ,
3975
+ optionalReplacementSpan ,
3949
3976
nil , /*commitCharacters*/
3950
3977
nil , /*labelDetails*/
3951
3978
file ,
@@ -3975,7 +4002,7 @@ func (l *LanguageService) createLSPCompletionItem(
3975
4002
elementKind ScriptElementKind ,
3976
4003
kindModifiers core.Set [ScriptElementKindModifier ],
3977
4004
replacementSpan * lsproto.Range ,
3978
- optionalReplacementSpan * core. TextRange ,
4005
+ optionalReplacementSpan * lsproto. Range ,
3979
4006
commitCharacters * []string ,
3980
4007
labelDetails * lsproto.CompletionItemLabelDetails ,
3981
4008
file * ast.SourceFile ,
@@ -4001,8 +4028,11 @@ func (l *LanguageService) createLSPCompletionItem(
4001
4028
} else {
4002
4029
// Ported from vscode ts extension.
4003
4030
if optionalReplacementSpan != nil && ptrIsTrue (clientOptions .CompletionItem .InsertReplaceSupport ) {
4004
- insertRange := l .createLspRangeFromBounds (optionalReplacementSpan .Pos (), position , file )
4005
- replaceRange := l .createLspRangeFromBounds (optionalReplacementSpan .Pos (), optionalReplacementSpan .End (), file )
4031
+ insertRange := & lsproto.Range {
4032
+ Start : optionalReplacementSpan .Start ,
4033
+ End : l .createLspPosition (position , file ),
4034
+ }
4035
+ replaceRange := optionalReplacementSpan
4006
4036
textEdit = & lsproto.TextEditOrInsertReplaceEdit {
4007
4037
InsertReplaceEdit : & lsproto.InsertReplaceEdit {
4008
4038
NewText : core .IfElse (insertText == "" , name , insertText ),
@@ -4085,11 +4115,10 @@ func (l *LanguageService) createLSPCompletionItem(
4085
4115
// !!! adjust label like vscode does
4086
4116
}
4087
4117
4118
+ // Client assumes plain text by default.
4088
4119
var insertTextFormat * lsproto.InsertTextFormat
4089
4120
if isSnippet {
4090
4121
insertTextFormat = ptrTo (lsproto .InsertTextFormatSnippet )
4091
- } else {
4092
- insertTextFormat = ptrTo (lsproto .InsertTextFormatPlainText )
4093
4122
}
4094
4123
4095
4124
return & lsproto.CompletionItem {
0 commit comments