@@ -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