branch: externals/drepl commit 00da350c03025e6fb094977a612214c05bcc97a8 Author: Augusto Stoffel <arstof...@gmail.com> Commit: Augusto Stoffel <arstof...@gmail.com>
Adjust completion prefixes This is necessary when Emacs and the REPL disagree about the completion bounds. --- README.org | 5 +++-- drepl-usql/drepl-usql.go | 19 ++++++++----------- drepl.el | 30 +++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/README.org b/README.org index 7908ea81ea..983869aa99 100644 --- a/README.org +++ b/README.org @@ -119,8 +119,9 @@ Parameters: completion. Response: -- =candidates= (optional): A list of objects, each containing the - following attributes. +- =prefix= (optional): The portion of code that is being completed. +- =candidates= (optional): A list of completion candidates, either + strings or objects containing the following attributes: - =text=: The completed text, including the existing prefix. - =annot=: Annotation text to be displayed next to the candidate in the completion UI. diff --git a/drepl-usql/drepl-usql.go b/drepl-usql/drepl-usql.go index cae1bac715..e0671495a8 100644 --- a/drepl-usql/drepl-usql.go +++ b/drepl-usql/drepl-usql.go @@ -133,27 +133,23 @@ func (l *Dline) CheckInput(code string) (status string, prompt string) { return status, prompt } -type Candidate struct { - Text string `json:"text"` -} - -func (l *Dline) Complete(code string, pos int) []Candidate { +func (l *Dline) Complete(code string, pos int) (string, []string) { if l.completer == nil || len(code) < pos { - return nil + return "", nil } coder := []rune(code) candr, i := l.completer.Do(coder, pos) start := pos - i if start < 0 { - return nil + return "", nil } prefix := coder[start:pos] - cands := make([]Candidate, 0, len(candr)) + cands := make([]string, 0, len(candr)) for _, c := range candr { c = append(prefix, c...) - cands = append(cands, Candidate{string(c)}) + cands = append(cands, string(c)) } - return cands + return string(prefix), cands } // Next returns the next line of runes (excluding '\n') from the input. @@ -180,9 +176,10 @@ func (l *Dline) Next() ([]rune, error) { "prompt": prompt, }) case "complete": - cands := l.Complete(msg.Code, msg.Pos) + prefix, cands := l.Complete(msg.Code, msg.Pos) l.SendMsg(map[string]any{ "id": msg.Id, + "prefix": prefix, "candidates": cands, }) default: diff --git a/drepl.el b/drepl.el index e32e10a8f7..9c05ef332b 100644 --- a/drepl.el +++ b/drepl.el @@ -353,10 +353,26 @@ interactively." :code code :pos pos)))) (when (listp response) - (mapcar (lambda (c) - (let-alist c - (propertize .text 'drepl--annot .annot))) - (alist-get 'candidates response))))) + (cons + (alist-get 'prefix response) + (mapcar (lambda (c) + (or (and (stringp c) c) + (let-alist c + (propertize .text 'drepl--annot .annot)))) + (alist-get 'candidates response)))))) + +(defun drepl--adjust-candidates (ours theirs cands) + "Adjust completion candidate prefixes. +OURS is the completion prefix computed by Emacs. +THEIRS is the completion prefix computed by the REPL. +CANDS is the candidate list computed by the REPL." + (let ((d (- (length theirs) (length ours)))) + (cond ((or (not theirs) (zerop d)) cands) + ((cl-plusp d) + (mapcar (lambda (s) (substring s d)) cands)) + ((cl-minusp d) + (let ((p (substring ours 0 (abs d)))) + (mapcar (lambda (s) (concat p s)) cands)))))) (defun drepl--complete () "Function intended for use as a member of `completion-at-point-functions'." @@ -367,8 +383,12 @@ interactively." (cdr comint-last-prompt) (point-max))) (pos (- (point) (cdr comint-last-prompt))) - (cands (when (>= pos 0) + (reply (when (>= pos 0) (drepl--completion-cadidates repl code pos))) + (cands (drepl--adjust-candidates + (buffer-substring-no-properties (car bounds) (cdr bounds)) + (car reply) + (cdr reply))) (metadata '(metadata (category . drepl) (annotation-function . drepl--capf-annotate)))