Skip to content

Commit 8bcbf99

Browse files
committed
added typdefs to completions + improved completion computation
1 parent 4df3f27 commit 8bcbf99

File tree

1 file changed

+100
-111
lines changed

1 file changed

+100
-111
lines changed

handlers/completion.go

Lines changed: 100 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -21,112 +21,88 @@ import (
2121

2222
func CreateTextDocumentCompletion(dm *documents.DocumentManager) protocol.TextDocumentCompletionFunc {
2323
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-
3324
var docModule *ast.Module
3425
// Get the current Document
3526
if d, ok := dm.Get(params.TextDocument.URI); ok {
3627
docModule = d.Module
3728
}
3829

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+
4041
visitor := &tableVisitor{
4142
Table: docModule.Ast.Symbols,
4243
tempTable: docModule.Ast.Symbols,
4344
pos: params.Position,
44-
isDotCompletion: isDotCompletion,
45+
isDotCompletion: params.Context.TriggerKind == protocol.CompletionTriggerKindTriggerCharacter && *params.Context.TriggerCharacter == ".",
4546
}
4647
ast.VisitModule(docModule, visitor)
4748

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+
4859
table := visitor.Table
49-
varItems := make(map[string]protocol.CompletionItem)
50-
aliases := make([]ast.Alias, 0)
60+
varItems := make(map[string]struct{}, 16)
5161
for table != nil {
5262
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+
}
5867

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{
6273
Kind: ptr(protocol.CompletionItemKindVariable),
6374
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(),
7675
})
7776
}
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)
7890
}
7991
}
8092
table = table.Enclosing
8193
}
8294

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-
12695
return items, nil
12796
})
12897
}
12998

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+
130106
func decideCapitalization(index int, document string) bool {
131107
if index-1 == 0 {
132108
return true
@@ -255,6 +231,41 @@ func init() {
255231
}
256232
}
257233

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+
258269
type tableVisitor struct {
259270
Table *ast.SymbolTable
260271
tempTable *ast.SymbolTable
@@ -299,10 +310,11 @@ func (t *tableVisitor) VisitIdent(ident *ast.Ident) ast.VisitResult {
299310
}
300311

301312
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
306318
}
307319

308320
var (
@@ -319,9 +331,10 @@ func (vis *importVisitor) ShouldVisit(node ast.Node) bool {
319331

320332
func (vis *importVisitor) VisitImportStmt(imprt *ast.ImportStmt) ast.VisitResult {
321333
if helper.IsInRange(imprt.FileName.Range, protocol.Position(vis.pos)) {
334+
vis.didVisit = true
322335
// clear the items, because we want no keywords and variables if we
323336
// are in an import path
324-
*vis.items = make([]protocol.CompletionItem, 0, len(dudenPaths))
337+
vis.items = make([]protocol.CompletionItem, 0, len(dudenPaths))
325338

326339
incompletePath := filepath.Dir(ast.TrimStringLit(&imprt.FileName))
327340

@@ -330,7 +343,7 @@ func (vis *importVisitor) VisitImportStmt(imprt *ast.ImportStmt) ast.VisitResult
330343
}
331344

332345
searchPath := filepath.Join(filepath.Dir(vis.modPath), incompletePath)
333-
if vis.triggerChar != nil && *vis.triggerChar == "/" && incompletePath == "Duden" {
346+
if vis.isSlashCompletion && incompletePath == "Duden" {
334347
searchPath = ddppath.Duden
335348
}
336349

@@ -347,39 +360,15 @@ func (vis *importVisitor) VisitImportStmt(imprt *ast.ImportStmt) ast.VisitResult
347360
}
348361

349362
if path := getRelevantEntryName(entry); path != "" {
350-
if vis.triggerChar != nil && *vis.triggerChar != "/" {
363+
if vis.isSlashCompletion {
351364
path = incompletePath + "/" + path
352365
}
353366
finalPath := strings.TrimPrefix(path, "./")
354-
*vis.items = append(*vis.items, pathToCompletionItem(finalPath))
367+
vis.items = append(vis.items, pathToCompletionItem(finalPath))
355368
}
356369
}
357370
}
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
383372
}
384373

385374
func pathToCompletionItem(path string) protocol.CompletionItem {
@@ -394,8 +383,8 @@ func pathToCompletionItem(path string) protocol.CompletionItem {
394383
}
395384
}
396385

397-
func addDudenPaths(items *[]protocol.CompletionItem) {
386+
func addDudenPaths(items []protocol.CompletionItem) {
398387
for _, path := range dudenPaths {
399-
*items = append(*items, pathToCompletionItem(path))
388+
items = append(items, pathToCompletionItem(path))
400389
}
401390
}

0 commit comments

Comments
 (0)