Skip to content

Commit

Permalink
Add first completion target with multiple matches (#59)
Browse files Browse the repository at this point in the history
When a completion target has multiple matches, such as when editing Go code that uses generated Protobuf packages that have the same method name at multiple levels of hierarchy, insert the first match always, and display the rest in an Acme window called `/LSP/Completions` similar to `/LSP/Diagnostics`.

This behaviour can be triggered by passing `-E` to `L comp` instead of `-e`. The existing behaviour for `-e` is preserved as is.

Closes #56
  • Loading branch information
farhaven committed Jul 9, 2023
1 parent 4288b27 commit c6ffdf3
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 10 deletions.
20 changes: 17 additions & 3 deletions cmd/L/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ attempt to find the focused window ID by connecting to acmefocused
List of sub-commands:
comp [-e]
comp [-e] [-E]
Print candidate completions at the cursor position. If
-e (edit) flag is given and there is only one candidate,
the completion is applied instead of being printed.
the completion is applied instead of being printed. If
-E (Edit) flag is given, the first matching candidate is
applied, and all matches will be displayed in a dedicated
Acme window named /LSP/Completions.
def [-p]
Find where the symbol at the cursor position is defined
Expand Down Expand Up @@ -206,7 +209,18 @@ func run(cfg *config.Config, args []string) error {
switch args[0] {
case "comp":
args = args[1:]
return rc.Completion(ctx, len(args) > 0 && args[0] == "-e")

var kind acmelsp.CompletionKind
if len(args) > 0 {
switch args[0] {
case "-e":
kind = acmelsp.CompleteInsertOnlyMatch
case "-E":
kind = acmelsp.CompleteInsertFirstMatch
}
}

return rc.Completion(ctx, kind)
case "def":
args = args[1:]
return rc.Definition(ctx, len(args) > 0 && args[0] == "-p")
Expand Down
2 changes: 1 addition & 1 deletion cmd/Lone/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func run(cfg *config.Config, args []string) error {

switch args[0] {
case "comp":
err = rc.Completion(ctx, false)
err = rc.Completion(ctx, acmelsp.CompleteNoEdit)
case "def":
err = rc.Definition(ctx, false)
case "fmt":
Expand Down
2 changes: 1 addition & 1 deletion internal/lsp/acmelsp/assist.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (w *outputWin) Update(fw *focusWin, server proxy.Server, cmd string) {
w.Clear()
switch cmd {
case "comp":
err := rc.Completion(ctx, false)
err := rc.Completion(ctx, CompleteNoEdit)
if err != nil {
dprintf("Completion failed: %v\n", err)
}
Expand Down
46 changes: 41 additions & 5 deletions internal/lsp/acmelsp/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ func (rc *RemoteCmd) DidChange(ctx context.Context) error {
})
}

func (rc *RemoteCmd) Completion(ctx context.Context, edit bool) error {
type CompletionKind int

const (
CompleteNoEdit CompletionKind = iota
CompleteInsertOnlyMatch
CompleteInsertFirstMatch
)

func (rc *RemoteCmd) Completion(ctx context.Context, kind CompletionKind) error {
w, err := acmeutil.OpenWin(rc.winid)
if err != nil {
return err
Expand All @@ -90,7 +98,8 @@ func (rc *RemoteCmd) Completion(ctx context.Context, edit bool) error {
if err != nil {
return err
}
if edit && len(result.Items) == 1 {

if (kind == CompleteInsertFirstMatch && len(result.Items) >= 1) || (kind == CompleteInsertOnlyMatch && len(result.Items) == 1) {
textEdit := result.Items[0].TextEdit
if textEdit == nil {
// TODO(fhs): Use insertText or label instead.
Expand All @@ -99,14 +108,41 @@ func (rc *RemoteCmd) Completion(ctx context.Context, edit bool) error {
if err := text.Edit(w, []protocol.TextEdit{*textEdit}); err != nil {
return fmt.Errorf("failed to apply completion edit: %v", err)
}
return nil

if len(result.Items) == 1 {
return nil
}
}

var sb strings.Builder

if len(result.Items) == 0 {
fmt.Fprintf(rc.Stderr, "no completion\n")
fmt.Fprintf(&sb, "no completion\n")
}

for _, item := range result.Items {
fmt.Fprintf(rc.Stdout, "%v %v\n", item.Label, item.Detail)
fmt.Fprintf(&sb, "%v\t%v\n", item.Label, item.Detail)
}

if kind == CompleteInsertFirstMatch {
cw, err := acmeutil.Hijack("/LSP/Completions")
if err != nil {
cw, err = acmeutil.NewWin()
if err != nil {
return err
}

cw.Name("/LSP/Completions")
}

defer cw.Win.Ctl("clean")

cw.Clear()
cw.PrintTabbed(sb.String())
} else {
fmt.Println(sb.String())
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions internal/lsp/text/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func Edit(f File, edits []protocol.TextEdit) error {
q1 := off.LineToOffset(int(e.Range.End.Line), int(e.Range.End.Character))
f.WriteAt(q0, q1, []byte(e.NewText))
}

return nil
}

Expand Down

0 comments on commit c6ffdf3

Please sign in to comment.