@@ -21,112 +21,88 @@ import (
21
21
22
22
func CreateTextDocumentCompletion (dm * documents.DocumentManager ) protocol.TextDocumentCompletionFunc {
23
23
return RecoverAnyErr (func (context * glsp.Context , params * protocol.CompletionParams ) (any , error ) {
24
- // Add all types
25
- items := make ([]protocol.CompletionItem , 0 )
26
- for _ , s := range ddpTypes {
27
- items = append (items , protocol.CompletionItem {
28
- Kind : ptr (protocol .CompletionItemKindClass ),
29
- Label : s ,
30
- })
31
- }
32
-
33
24
var docModule * ast.Module
34
25
// Get the current Document
35
26
if d , ok := dm .Get (params .TextDocument .URI ); ok {
36
27
docModule = d .Module
37
28
}
38
29
39
- isDotCompletion := params .Context .TriggerKind == protocol .CompletionTriggerKindTriggerCharacter && * params .Context .TriggerCharacter == "."
30
+ // in case of import completion we need nothing else
31
+ importVisitor := & importVisitor {
32
+ pos : params .Position ,
33
+ modPath : docModule .FileName ,
34
+ isSlashCompletion : params .Context .TriggerKind == protocol .CompletionTriggerKindTriggerCharacter && * params .Context .TriggerCharacter == "/" ,
35
+ }
36
+ ast .VisitModule (docModule , importVisitor )
37
+ if importVisitor .didVisit {
38
+ return importVisitor .items , nil
39
+ }
40
+
40
41
visitor := & tableVisitor {
41
42
Table : docModule .Ast .Symbols ,
42
43
tempTable : docModule .Ast .Symbols ,
43
44
pos : params .Position ,
44
- isDotCompletion : isDotCompletion ,
45
+ isDotCompletion : params . Context . TriggerKind == protocol . CompletionTriggerKindTriggerCharacter && * params . Context . TriggerCharacter == "." ,
45
46
}
46
47
ast .VisitModule (docModule , visitor )
47
48
49
+ items := make ([]protocol.CompletionItem , 0 , len (ddpTypes )+ 53 )
50
+
51
+ // in case of dot completions we don't need anything else
52
+ if visitor .isDotCompletion {
53
+ items = appendDotCompletion (items , visitor .ident , params .Position )
54
+ return items , nil
55
+ }
56
+
57
+ items = appendDDPTypes (items )
58
+
48
59
table := visitor .Table
49
- varItems := make (map [string ]protocol.CompletionItem )
50
- aliases := make ([]ast.Alias , 0 )
60
+ varItems := make (map [string ]struct {}, 16 )
51
61
for table != nil {
52
62
for name := range table .Declarations {
53
- if _ , ok := varItems [name ]; ! ok {
54
- decl , _ , _ := table .LookupDecl (name )
55
- if decl .GetRange ().Start .IsBehind (helper .FromProtocolPosition (params .Position )) {
56
- continue
57
- }
63
+ decl , _ , _ := table .LookupDecl (name )
64
+ if decl .GetRange ().Start .IsBehind (helper .FromProtocolPosition (params .Position )) {
65
+ continue
66
+ }
58
67
59
- switch decl := decl .(type ) {
60
- case * ast.VarDecl :
61
- varItems [name ] = protocol.CompletionItem {
68
+ switch decl := decl .(type ) {
69
+ case * ast.VarDecl :
70
+ if _ , ok := varItems [name ]; ! ok {
71
+ varItems [name ] = struct {}{}
72
+ items = append (items , protocol.CompletionItem {
62
73
Kind : ptr (protocol .CompletionItemKindVariable ),
63
74
Label : name ,
64
- }
65
- case * ast.FuncDecl :
66
- for _ , a := range decl .Aliases {
67
- aliases = append (aliases , a )
68
- }
69
- case * ast.StructDecl :
70
- for _ , a := range decl .Aliases {
71
- aliases = append (aliases , a )
72
- }
73
- items = append (items , protocol.CompletionItem {
74
- Kind : ptr (protocol .CompletionItemKindClass ),
75
- Label : decl .Name (),
76
75
})
77
76
}
77
+ case * ast.FuncDecl :
78
+ for _ , a := range decl .Aliases {
79
+ items = append (items , aliasToCompletionItem (a )... )
80
+ }
81
+ case * ast.StructDecl :
82
+ for _ , a := range decl .Aliases {
83
+ items = append (items , aliasToCompletionItem (a )... )
84
+ }
85
+ items = appendTypeName (items , decl )
86
+ case * ast.TypeAliasDecl :
87
+ items = appendTypeName (items , decl )
88
+ case * ast.TypeDefDecl :
89
+ items = appendTypeName (items , decl )
78
90
}
79
91
}
80
92
table = table .Enclosing
81
93
}
82
94
83
- ident := visitor .ident
84
- if isDotCompletion && ident != nil && ident .Declaration != nil && ddptypes .IsStruct (ident .Declaration .Type ) {
85
- structType := ident .Declaration .Type .(* ddptypes.StructType )
86
- for _ , field := range structType .Fields {
87
- items = append (items , protocol.CompletionItem {
88
- Kind : ptr (protocol .CompletionItemKindField ),
89
- Label : field .Name ,
90
- SortText : ptr ("0" ),
91
- TextEdit : protocol.TextEdit {
92
- NewText : fmt .Sprintf ("%s von %s" , field .Name , ident .Declaration .Name ()),
93
- Range : protocol.Range {
94
- Start : helper .ToProtocolPosition (ident .GetRange ().Start ),
95
- End : protocol.Position {
96
- Line : params .Position .Line ,
97
- Character : params .Position .Character ,
98
- },
99
- },
100
- },
101
- FilterText : ptr (fmt .Sprintf ("%s.%s" , ident .Declaration .Name (), field .Name )),
102
- })
103
- }
104
- }
105
-
106
- for _ , v := range varItems {
107
- items = append (items , v )
108
- }
109
-
110
- for _ , alias := range aliases {
111
- items = append (items , aliasToCompletionItem (alias )... )
112
- }
113
-
114
- // must be here at the end because it might clear previous items
115
- triggerChar := (* string )(nil )
116
- if params .Context != nil {
117
- triggerChar = params .Context .TriggerCharacter
118
- }
119
- ast .VisitModule (docModule , & importVisitor {
120
- pos : params .Position ,
121
- items : & items ,
122
- modPath : docModule .FileName ,
123
- triggerChar : triggerChar ,
124
- })
125
-
126
95
return items , nil
127
96
})
128
97
}
129
98
99
+ func appendTypeName (items []protocol.CompletionItem , decl ast.Declaration ) []protocol.CompletionItem {
100
+ return append (items , protocol.CompletionItem {
101
+ Kind : ptr (protocol .CompletionItemKindClass ),
102
+ Label : decl .Name (),
103
+ })
104
+ }
105
+
130
106
func decideCapitalization (index int , document string ) bool {
131
107
if index - 1 == 0 {
132
108
return true
@@ -255,6 +231,41 @@ func init() {
255
231
}
256
232
}
257
233
234
+ func appendDDPTypes (items []protocol.CompletionItem ) []protocol.CompletionItem {
235
+ for _ , s := range ddpTypes {
236
+ items = append (items , protocol.CompletionItem {
237
+ Kind : ptr (protocol .CompletionItemKindClass ),
238
+ Label : s ,
239
+ })
240
+ }
241
+ return items
242
+ }
243
+
244
+ func appendDotCompletion (items []protocol.CompletionItem , ident * ast.Ident , pos protocol.Position ) []protocol.CompletionItem {
245
+ if ident != nil && ident .Declaration != nil && ddptypes .IsStruct (ident .Declaration .Type ) {
246
+ structType := ident .Declaration .Type .(* ddptypes.StructType )
247
+ for _ , field := range structType .Fields {
248
+ items = append (items , protocol.CompletionItem {
249
+ Kind : ptr (protocol .CompletionItemKindField ),
250
+ Label : field .Name ,
251
+ SortText : ptr ("0" ),
252
+ TextEdit : protocol.TextEdit {
253
+ NewText : fmt .Sprintf ("%s von %s" , field .Name , ident .Declaration .Name ()),
254
+ Range : protocol.Range {
255
+ Start : helper .ToProtocolPosition (ident .GetRange ().Start ),
256
+ End : protocol.Position {
257
+ Line : pos .Line ,
258
+ Character : pos .Character ,
259
+ },
260
+ },
261
+ },
262
+ FilterText : ptr (fmt .Sprintf ("%s.%s" , ident .Declaration .Name (), field .Name )),
263
+ })
264
+ }
265
+ }
266
+ return items
267
+ }
268
+
258
269
type tableVisitor struct {
259
270
Table * ast.SymbolTable
260
271
tempTable * ast.SymbolTable
@@ -299,10 +310,11 @@ func (t *tableVisitor) VisitIdent(ident *ast.Ident) ast.VisitResult {
299
310
}
300
311
301
312
type importVisitor struct {
302
- pos protocol.Position
303
- items * []protocol.CompletionItem
304
- modPath string
305
- triggerChar * string
313
+ pos protocol.Position
314
+ items []protocol.CompletionItem
315
+ modPath string
316
+ isSlashCompletion bool
317
+ didVisit bool
306
318
}
307
319
308
320
var (
@@ -319,9 +331,10 @@ func (vis *importVisitor) ShouldVisit(node ast.Node) bool {
319
331
320
332
func (vis * importVisitor ) VisitImportStmt (imprt * ast.ImportStmt ) ast.VisitResult {
321
333
if helper .IsInRange (imprt .FileName .Range , protocol .Position (vis .pos )) {
334
+ vis .didVisit = true
322
335
// clear the items, because we want no keywords and variables if we
323
336
// are in an import path
324
- * vis .items = make ([]protocol.CompletionItem , 0 , len (dudenPaths ))
337
+ vis .items = make ([]protocol.CompletionItem , 0 , len (dudenPaths ))
325
338
326
339
incompletePath := filepath .Dir (ast .TrimStringLit (& imprt .FileName ))
327
340
@@ -330,7 +343,7 @@ func (vis *importVisitor) VisitImportStmt(imprt *ast.ImportStmt) ast.VisitResult
330
343
}
331
344
332
345
searchPath := filepath .Join (filepath .Dir (vis .modPath ), incompletePath )
333
- if vis .triggerChar != nil && * vis . triggerChar == "/" && incompletePath == "Duden" {
346
+ if vis .isSlashCompletion && incompletePath == "Duden" {
334
347
searchPath = ddppath .Duden
335
348
}
336
349
@@ -347,39 +360,15 @@ func (vis *importVisitor) VisitImportStmt(imprt *ast.ImportStmt) ast.VisitResult
347
360
}
348
361
349
362
if path := getRelevantEntryName (entry ); path != "" {
350
- if vis .triggerChar != nil && * vis . triggerChar != "/" {
363
+ if vis .isSlashCompletion {
351
364
path = incompletePath + "/" + path
352
365
}
353
366
finalPath := strings .TrimPrefix (path , "./" )
354
- * vis .items = append (* vis .items , pathToCompletionItem (finalPath ))
367
+ vis .items = append (vis .items , pathToCompletionItem (finalPath ))
355
368
}
356
369
}
357
370
}
358
- // module could not be parsed yet, return
359
- if imprt .Module == nil {
360
- return ast .VisitRecurse
361
- }
362
-
363
- // module could be parsed, complete symbol imports
364
- for _ , ident := range imprt .ImportedSymbols {
365
- if ! helper .IsInRange (ident .Range , vis .pos ) {
366
- continue
367
- }
368
-
369
- * vis .items = make ([]protocol.CompletionItem , 0 , len (imprt .Module .PublicDecls ))
370
- for name , decl := range imprt .Module .PublicDecls {
371
- kind := ptr (protocol .CompletionItemKindFunction )
372
- if _ , ok := decl .(* ast.VarDecl ); ok {
373
- kind = ptr (protocol .CompletionItemKindVariable )
374
- }
375
- * vis .items = append (* vis .items , protocol.CompletionItem {
376
- Kind : kind ,
377
- Label : name ,
378
- })
379
- }
380
- break
381
- }
382
- return ast .VisitRecurse
371
+ return ast .VisitBreak
383
372
}
384
373
385
374
func pathToCompletionItem (path string ) protocol.CompletionItem {
@@ -394,8 +383,8 @@ func pathToCompletionItem(path string) protocol.CompletionItem {
394
383
}
395
384
}
396
385
397
- func addDudenPaths (items * []protocol.CompletionItem ) {
386
+ func addDudenPaths (items []protocol.CompletionItem ) {
398
387
for _ , path := range dudenPaths {
399
- * items = append (* items , pathToCompletionItem (path ))
388
+ items = append (items , pathToCompletionItem (path ))
400
389
}
401
390
}
0 commit comments