@@ -96,7 +96,7 @@ func completionItemsForDeclPath(ctx context.Context, file *file, declPath []ast.
9696 case ast .DeclKindPackage :
9797 return completionItemsForPackage (ctx , file , decl .AsPackage ())
9898 case ast .DeclKindImport :
99- return completionItemsForImport (ctx , file )
99+ return completionItemsForImport (ctx , file , decl . AsImport (), position )
100100 default :
101101 file .lsp .logger .DebugContext (ctx , "completion: unknown declaration type" , slog .String ("kind" , decl .Kind ().String ()))
102102 return nil
@@ -208,19 +208,69 @@ func completionItemsForDef(ctx context.Context, file *file, declPath []ast.DeclA
208208// completionItemsForImport returns completion items for import declarations.
209209//
210210// Suggest all importable files.
211- func completionItemsForImport (ctx context.Context , file * file ) []protocol.CompletionItem {
211+ func completionItemsForImport (ctx context.Context , file * file , declImport ast. DeclImport , position protocol. Position ) []protocol.CompletionItem {
212212 file .lsp .logger .DebugContext (ctx , "completion: import declaration" , slog .Int ("importable_count" , len (file .importToFile )))
213213
214- items := make ([]protocol.CompletionItem , 0 , len (file .importToFile ))
214+ positionLocation := file .file .InverseLocation (int (position .Line )+ 1 , int (position .Character )+ 1 , positionalEncoding )
215+ offset := positionLocation .Offset
216+
217+ importPathSpan := declImport .ImportPath ().Span ()
218+ start , end := importPathSpan .Start , importPathSpan .End
219+ importPathText := importPathSpan .Text ()
220+
221+ // Break on newlines to split an unintended capture.
222+ if index := strings .IndexByte (importPathText , '\n' ); index != - 1 {
223+ end = start + index
224+ importPathText = importPathText [:index ]
225+ }
226+
227+ if start > offset || offset > end {
228+ file .lsp .logger .Debug ("completion: outside import expr range" ,
229+ slog .String ("import" , importPathText ),
230+ slog .Int ("start" , start ),
231+ slog .Int ("offset" , offset ),
232+ slog .Int ("end" , end ),
233+ slog .Int ("line" , int (position .Line )),
234+ slog .Int ("character" , int (position .Character )),
235+ )
236+ return nil
237+ }
238+
239+ index := offset - start
240+ prefix := importPathText [:index ]
241+ suffix := importPathText [index :]
242+
243+ var items []protocol.CompletionItem
215244 for importPath := range file .importToFile {
245+ suggest := fmt .Sprintf ("%q" , importPath )
246+ if ! strings .HasPrefix (suggest , prefix ) {
247+ file .lsp .logger .Debug ("completion: skipping on prefix" ,
248+ slog .String ("import" , importPathText ),
249+ slog .String ("prefix" , prefix ),
250+ slog .String ("suggest" , suggest ),
251+ )
252+ continue
253+ }
254+ if ! strings .HasSuffix (suggest , suffix ) {
255+ file .lsp .logger .Debug ("completion: skipping on suffix" ,
256+ slog .String ("import" , importPathText ),
257+ slog .String ("suffix" , prefix ),
258+ slog .String ("suggest" , suggest ),
259+ )
260+ continue
261+ }
216262 items = append (items , protocol.CompletionItem {
217- Label : " \" " + importPath + " \" ;" ,
263+ Label : importPath ,
218264 Kind : protocol .CompletionItemKindFile ,
265+ TextEdit : & protocol.TextEdit {
266+ Range : protocol.Range {
267+ Start : position ,
268+ End : position ,
269+ },
270+ NewText : suggest [len (prefix ) : len (suggest )- len (suffix )],
271+ },
219272 })
220273 }
221- slices .SortFunc (items , func (a , b protocol.CompletionItem ) int {
222- return strings .Compare (strings .ToLower (a .Label ), strings .ToLower (b .Label ))
223- })
224274 return items
225275}
226276
0 commit comments