Skip to content

Commit 77da398

Browse files
Add import of missing file on completion (#4124)
1 parent 6a6c735 commit 77da398

File tree

1 file changed

+56
-3
lines changed

1 file changed

+56
-3
lines changed

private/buf/buflsp/completion.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,47 @@ func typeReferencesToCompletionItems(
612612
}
613613
}
614614
}
615+
var lastImportLine uint32
616+
currentImportPaths := map[string]struct{}{}
617+
for currentFileImport := range seq.Values(current.ir.Imports()) {
618+
l := currentFileImport.Decl.Span().EndLoc().Line
619+
if l < 0 || l > math.MaxUint32 {
620+
continue // skip this import; exceptional case.
621+
}
622+
lastImportLine = max(uint32(l), lastImportLine)
623+
currentImportPaths[currentFileImport.Path()] = struct{}{}
624+
}
625+
var insertPosition protocol.Position
626+
if lastImportLine != 0 {
627+
// add an additionalTextEdit to the end of the current imports, which can then be tidied by
628+
// `buf format` to go in it's proper location.
629+
insertPosition = protocol.Position{
630+
Line: lastImportLine,
631+
Character: 0,
632+
}
633+
} else {
634+
// If lastImportLine is 0, we have no imports in this file; put it after `package`, if
635+
// package exists. Otherwise, after `syntax`, if it exists. Otherwise, balk.
636+
// NOTE: We simply want to add the import on the next line (which may not be how `buf
637+
// format` would format the file); we leave the overall file formatting to `buf format`.
638+
var line int
639+
switch {
640+
case !current.ir.AST().Package().IsZero():
641+
line = current.ir.AST().Package().Span().EndLoc().Line
642+
case !current.ir.AST().Syntax().IsZero():
643+
line = current.ir.AST().Syntax().Span().EndLoc().Line
644+
default:
645+
line = 0
646+
}
647+
if line < 0 || line > math.MaxUint32 {
648+
// Nothing to do; exceptional case.
649+
} else {
650+
insertPosition = protocol.Position{
651+
Line: uint32(line),
652+
Character: 0,
653+
}
654+
}
655+
}
615656
parentPrefix := string(parentFullName) + "."
616657
packagePrefix := string(current.ir.Package()) + "."
617658
return func(yield func(protocol.CompletionItem) bool) {
@@ -652,16 +693,28 @@ func typeReferencesToCompletionItems(
652693
if _, ok := symbol.ir.Deprecated().AsBool(); ok {
653694
isDeprecated = true
654695
}
696+
symbolFile := symbol.ir.File().Path()
697+
_, hasImport := currentImportPaths[symbolFile]
698+
var additionalTextEdits []protocol.TextEdit
699+
if !hasImport {
700+
additionalTextEdits = append(additionalTextEdits, protocol.TextEdit{
701+
NewText: "import " + `"` + symbolFile + `";` + "\n",
702+
Range: protocol.Range{
703+
Start: insertPosition,
704+
End: insertPosition,
705+
},
706+
})
707+
}
655708
if !yield(protocol.CompletionItem{
656709
Label: label,
657710
Kind: kind,
658711
TextEdit: &protocol.TextEdit{
659712
Range: editRange,
660713
NewText: label,
661714
},
662-
Deprecated: isDeprecated,
663-
Documentation: symbol.FormatDocs(),
664-
// TODO: If this type's file is not currently imported add an additional edit.
715+
Deprecated: isDeprecated,
716+
Documentation: symbol.FormatDocs(),
717+
AdditionalTextEdits: additionalTextEdits,
665718
}) {
666719
break
667720
}

0 commit comments

Comments
 (0)