[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/company 4ba6dcb874 22/24: Merge pull request #1488 from
From: |
ELPA Syncer |
Subject: |
[elpa] externals/company 4ba6dcb874 22/24: Merge pull request #1488 from company-mode/expand-common |
Date: |
Tue, 27 Aug 2024 00:57:45 -0400 (EDT) |
branch: externals/company
commit 4ba6dcb874ff6e1f77e79bd18c9f6079480b7af8
Merge: 1321e285a5 df4f6e9ea3
Author: Dmitry Gutov <dmitry@gutov.dev>
Commit: GitHub <noreply@github.com>
Merge pull request #1488 from company-mode/expand-common
company-complete-common: Generalized "expand common" behavior
---
NEWS.md | 5 +
company-capf.el | 10 +-
company-dabbrev-code.el | 46 +++++---
company-etags.el | 31 ++++--
company.el | 289 ++++++++++++++++++++++++++++++++++++------------
test/async-tests.el | 4 +-
test/capf-tests.el | 4 +-
test/core-tests.el | 110 ++++++++++++++----
8 files changed, 379 insertions(+), 120 deletions(-)
diff --git a/NEWS.md b/NEWS.md
index ab50446e29..d764e1c60d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,11 @@
# Next
+* `company-complete-common` now performs generalized ([expand common
+ part](https://github.com/company-mode/company-mode/pull/1488)) completion
when
+ the backend supports that. In particular, for `completion-at-point-functions`
+ it queries `completion-try-completion`. `company-dabbrev-code` and
+ `company-etags` also do that when `completion-styles` support is enabled.
* `company-dabbrev-other-buffers` and `company-dabbrev-code-other-buffers` can
now take a function as its value
(#[1485](https://github.com/company-mode/company-mode/issues/1485))
* Completion works in the middle of a symbol
diff --git a/company-capf.el b/company-capf.el
index 166c569b8a..b58c5678fc 100644
--- a/company-capf.el
+++ b/company-capf.el
@@ -19,7 +19,6 @@
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
-
;;; Commentary:
;;
;; The CAPF back-end provides a bridge to the standard
@@ -164,8 +163,17 @@ so we can't just use the preceding variable instead.")
(company--capf-post-completion arg))
(`adjust-boundaries
company-capf--current-boundaries)
+ (`expand-common
+ (company-capf--expand-common arg (car rest)))
))
+(defun company-capf--expand-common (prefix suffix)
+ (let* ((data company-capf--current-completion-data)
+ (table (nth 3 data))
+ (pred (plist-get (nthcdr 4 data) :predicate)))
+ (company--capf-expand-common prefix suffix table pred
+ company-capf--current-completion-metadata)))
+
(defun company-capf--annotation (arg)
(let* ((f (or (plist-get (nthcdr 4 company-capf--current-completion-data)
:annotation-function)
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 4a5be06cf2..e9dec1d566 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -114,6 +114,7 @@ comments or strings."
(candidates (company-dabbrev--candidates arg (car rest)))
(adjust-boundaries (and company-dabbrev-code-completion-styles
company-dabbrev--boundaries))
+ (expand-common (company-dabbrev-code--expand-common arg (car rest)))
(kind 'text)
(no-cache t)
(ignore-case company-dabbrev-code-ignore-case)
@@ -121,26 +122,37 @@ comments or strings."
(company--match-from-capf-face arg)))
(duplicates t)))
+(defun company-dabbrev-code--expand-common (prefix suffix)
+ (when company-dabbrev-code-completion-styles
+ (let ((completion-styles (if (listp company-dabbrev-code-completion-styles)
+ company-dabbrev-code-completion-styles
+ completion-styles)))
+ (company--capf-expand-common prefix suffix
+ (company-dabbrev-code--table prefix)))))
+
(defun company-dabbrev--candidates (prefix suffix)
- (let* ((case-fold-search company-dabbrev-code-ignore-case)
- (regexp (company-dabbrev-code--make-regexp prefix)))
+ (let* ((case-fold-search company-dabbrev-code-ignore-case))
(company-dabbrev-code--filter
prefix suffix
- (company-cache-fetch
- 'dabbrev-code-candidates
- (lambda ()
- (company-dabbrev--search
- regexp
- company-dabbrev-code-time-limit
- (pcase company-dabbrev-code-other-buffers
- (`t (list major-mode))
- (`code company-dabbrev-code-modes)
- ((pred functionp) (funcall company-dabbrev-code-other-buffers
(current-buffer)))
- (`all `all))
- (not company-dabbrev-code-everywhere)))
- :expire t
- :check-tag
- (cons regexp company-dabbrev-code-completion-styles)))))
+ (company-dabbrev-code--table prefix))))
+
+(defun company-dabbrev-code--table (prefix)
+ (let ((regexp (company-dabbrev-code--make-regexp prefix)))
+ (company-cache-fetch
+ 'dabbrev-code-candidates
+ (lambda ()
+ (company-dabbrev--search
+ regexp
+ company-dabbrev-code-time-limit
+ (pcase company-dabbrev-code-other-buffers
+ (`t (list major-mode))
+ (`code company-dabbrev-code-modes)
+ ((pred functionp) (funcall company-dabbrev-code-other-buffers
(current-buffer)))
+ (`all `all))
+ (not company-dabbrev-code-everywhere)))
+ :expire t
+ :check-tag
+ (cons regexp company-dabbrev-code-completion-styles))))
(defun company-dabbrev-code--filter (prefix suffix table)
(let ((completion-ignore-case company-dabbrev-code-ignore-case)
diff --git a/company-etags.el b/company-etags.el
index 9f5c9d4f46..34c68b814d 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -82,25 +82,35 @@ Set it to t or to a list of major modes."
company-etags-buffer-table)))
(defun company-etags--candidates (prefix suffix)
- (let ((tags-table-list (company-etags-buffer-table))
- (tags-file-name tags-file-name)
- (completion-ignore-case company-etags-ignore-case)
+ (let ((completion-ignore-case company-etags-ignore-case)
(completion-styles (if (listp company-etags-completion-styles)
company-etags-completion-styles
completion-styles))
- table)
- (and (or tags-file-name tags-table-list)
- (fboundp 'tags-completion-table)
- (setq table
- (save-excursion
- (visit-tags-table-buffer)
- (tags-completion-table)))
+ (table (company-etags--table)))
+ (and table
(if company-etags-completion-styles
(let ((res (company--capf-completions prefix suffix table)))
(setq company-etags--boundaries (assoc-default :boundaries res))
(assoc-default :completions res))
(all-completions prefix table)))))
+(defun company-etags--table ()
+ (let ((tags-table-list (company-etags-buffer-table))
+ (tags-file-name tags-file-name))
+ (and (or tags-file-name tags-table-list)
+ (fboundp 'tags-completion-table)
+ (save-excursion
+ (visit-tags-table-buffer)
+ (tags-completion-table)))))
+
+(defun company-etags--expand-common (prefix suffix)
+ (when company-etags-completion-styles
+ (let ((completion-styles (if (listp company-etags-completion-styles)
+ company-etags-completion-styles
+ completion-styles)))
+ (company--capf-expand-common prefix suffix
+ (company-etags--table)))))
+
;;;###autoload
(defun company-etags (command &optional arg &rest rest)
"`company-mode' completion backend for etags."
@@ -116,6 +126,7 @@ Set it to t or to a list of major modes."
(candidates (company-etags--candidates arg (car rest)))
(adjust-boundaries (and company-etags-completion-styles
company-etags--boundaries))
+ (expand-common (company-etags--expand-common arg (car rest)))
(no-cache company-etags-completion-styles)
(location (let ((tags-table-list (company-etags-buffer-table)))
(when (fboundp 'find-tag-noselect)
diff --git a/company.el b/company.el
index ddad6422d6..ccc57a68f7 100644
--- a/company.el
+++ b/company.el
@@ -397,8 +397,8 @@ return value should be a list of candidates that match the
prefix.
Non-prefix matches are also supported (candidates that don't start with the
prefix, but match it in some backend-defined way). Backends that use this
-feature must disable cache (return t to `no-cache') and might also want to
-respond to `match'.
+feature must disable cache (return t in response to `no-cache') and might
+also want to handle `match'.
Optional commands
=================
@@ -473,6 +473,14 @@ is suffix (previously returned by the `prefix' command).
Return a
cons (NEW-PREFIX . NEW-SUFFIX) where both parts correspond to the
completion candidate.
+`expand-common': The first argument is prefix and the second argument is
+suffix. Return a cons (NEW-PREFIX . NEW-SUFFIX) that denote an edit in the
+current buffer which would be performed by `company-complete-common'. It
+should try to make the combined length of the prefix and suffix longer,
+while ensuring that the completions for the new inputs are the same.
+Othewise return the original inputs. If there are no matching completions,
+return the symbol `no-match'.
+
The backend should return nil for all commands it does not support or
does not know about. It should also be callable interactively and use
`company-begin-backend' to start itself in that case.
@@ -1235,6 +1243,20 @@ MAX-LEN is how far back to try to match the
IDLE-BEGIN-AFTER-RE regexp."
(:boundaries . ,(cons (substring prefix base-size)
(substring suffix 0 (cdr bounds)))))))
+(defun company--capf-expand-common (prefix suffix table &optional pred
metadata)
+ (let* ((res
+ (completion-try-completion (concat prefix suffix)
+ table pred (length prefix) metadata)))
+ (cond
+ ((null res)
+ 'no-match)
+ ((memq res '(t nil))
+ (cons prefix suffix))
+ (t
+ (cons
+ (substring (car res) 0 (cdr res))
+ (substring (car res) (cdr res)))))))
+
(defvar company--cache (make-hash-table :test #'equal :size 10))
(cl-defun company-cache-fetch (key
@@ -1314,15 +1336,12 @@ be recomputed when this value changes."
collect b))
(separate (memq :separate backends)))
- (when (eq command 'prefix)
- (setq backends (butlast backends (length (member :with backends)))))
-
- (setq backends (cl-delete-if #'keywordp backends))
+ (unless (eq command 'prefix)
+ (setq backends (cl-delete-if #'keywordp backends)))
(pcase command
(`candidates
(company--multi-backend-adapter-candidates backends
- (car args)
(or
company--multi-min-prefix 0)
separate))
(`set-min-prefix (setq company--multi-min-prefix (car args)))
@@ -1355,53 +1374,158 @@ be recomputed when this value changes."
(setq value t))
(cl-return value)))))
(`prefix (company--multi-prefix backends))
+ (`adjust-boundaries
+ (defvar company-point)
+ (let ((arg (car args)))
+ (when (> (length arg) 0)
+ (let* ((backend (or (get-text-property 0 'company-backend arg)
+ (car backends)))
+ (entity (company--force-sync backend '(prefix) backend))
+ (prefix (company--prefix-str entity))
+ (suffix (company--suffix-str entity)))
+ ;; XXX: Working around the stuff in
+ ;; company-preview--refresh-prefix.
+ (when (> (point) company-point)
+ (setq prefix (substring prefix
+ 0
+ (- (length prefix)
+ (- (point) company-point)))))
+ (setq args (list arg prefix suffix))
+ (or
+ (apply backend command args)
+ (cons prefix suffix))))))
+ (`expand-common
+ (apply #'company--multi-expand-common
+ backends
+ (or company--multi-min-prefix 0)
+ args))
(_
(let ((arg (car args)))
(when (> (length arg) 0)
(let ((backend (or (get-text-property 0 'company-backend arg)
(car backends))))
- (when (eq command 'adjust-boundaries)
- (let ((entity (company--force-sync backend '(prefix) backend)))
- (setq args (list arg
- (company--prefix-str entity)
- (company--suffix-str entity)))))
(apply backend command args))))))))
(defun company--multi-prefix (backends)
- (let (res len)
- (dolist (backend backends)
- (let* ((prefix (company--force-sync backend '(prefix) backend))
- (prefix-len (company--prefix-len prefix)))
- (when (stringp (company--prefix-str prefix))
- (cond
- ((not res)
- (setq res prefix
- len (company--prefix-len prefix)))
- ((and prefix-len
- (not (eq len t))
- (equal (company--prefix-str res)
- (company--prefix-str prefix))
- (or (eq prefix-len t)
- (> prefix-len (or len (length (company--prefix-str
prefix))))))
- (setq len prefix-len
- res prefix))))))
- res))
+ (let* ((backends-after-with (cdr (member :with backends)))
+ prefix suffix len)
-(defun company--multi-backend-adapter-candidates (backends prefix min-length
separate)
+ (dolist (backend backends)
+ (let* ((entity (and
+ (not (keywordp backend))
+ (company--force-sync backend '(prefix) backend)))
+ (new-len (company--prefix-len entity)))
+ (when (stringp (company--prefix-str entity))
+ (or (not backends-after-with)
+ (unless (memq backend backends-after-with)
+ (setq backends-after-with nil)))
+ (when (or
+ (null prefix)
+ (> (length (company--prefix-str entity))
+ (length prefix)))
+ (setq prefix (company--prefix-str entity)))
+ (when (> (length (company--suffix-str entity))
+ (length suffix))
+ (setq suffix (company--suffix-str entity)))
+ (when (or (eq t new-len)
+ (and new-len
+ (not (eq t len))
+ (or (not len) (> new-len len))))
+ (setq len new-len)))))
+ (unless backends-after-with
+ (list prefix suffix len))))
+
+(defun company--multi-expand-common (backends min-length prefix suffix)
+ (let ((tuples
+ (cl-loop for backend in backends
+ for bp = (let ((company-backend backend))
+ (company-call-backend 'prefix))
+ for expansion =
+ (when (company--good-prefix-p bp min-length)
+ (let ((inhibit-redisplay t)
+ (company-backend backend))
+ (company--expand-common (company--prefix-str bp)
+ (company--suffix-str bp))))
+ when (consp expansion)
+ collect
+ (list backend bp expansion)))
+ replacements)
+ (dolist (tuple tuples)
+ (cl-assert (string-suffix-p (company--prefix-str (nth 1 tuple))
+ prefix))
+ (cl-assert (string-prefix-p (company--suffix-str (nth 1 tuple))
+ suffix)))
+ ;; We try to find the smallest possible edit for each backend's expansion
+ ;; (minimum prefix and suffix, beyond which the area is unchanged).
+ (setq replacements
+ (mapcar
+ (lambda (tuple)
+ (let* ((backend-prefix (company--prefix-str (nth 1 tuple)))
+ (backend-suffix (company--suffix-str (nth 1 tuple)))
+ (bplen (length backend-prefix))
+ (bslen (length backend-suffix))
+ (beg 0)
+ (end 0)
+ (rep-suffix-len (length (cdr (nth 2 tuple))))
+ (max-beg (min bplen (length (car (nth 2 tuple)))))
+ (max-end (min bslen rep-suffix-len)))
+ (while (and (< beg max-beg)
+ (= (aref backend-prefix beg)
+ (aref (car (nth 2 tuple)) beg)))
+ (cl-incf beg))
+ (while (and (< end max-end)
+ (= (aref suffix (- bslen end 1))
+ (aref (cdr (nth 2 tuple))
+ (- rep-suffix-len end 1))))
+ (cl-incf end))
+ (list (- bplen beg)
+ (substring (car (nth 2 tuple)) beg)
+ (- bslen end)
+ (substring (cdr (nth 2 tuple)) 0 (- rep-suffix-len end))
+ (nth 0 tuple))))
+ tuples))
+ (setq replacements (sort replacements
+ (lambda (t1 t2) (< (- (length (nth 1 t1)) (nth 0
t1))
+ (- (length (nth 1 t2)) (nth 0
t2))))))
+ (or
+ (let ((choice (car replacements)))
+ ;; See if every replacement is similar enough to the one we selected:
+ ;; same suffix and beg/end and a prefix that starts with the proposed.
+ ;;
+ ;; More advanced checks seem possible, but with some backends reacting
to
+ ;; buffer contents (not just string arguments) it seems we'd need to
+ ;; change the buffer contents first, then fetch `candidates' for each,
+ ;; and revert at the end. Might be error-prone.
+ (and
+ choice
+ (cl-every
+ (lambda (replacement)
+ (and
+ (= (car replacement) (car choice))
+ (= (nth 2 replacement) (nth 2 choice))
+ (equal (nth 3 replacement) (nth 3 choice))
+ (string-prefix-p (nth 1 choice) (nth 1 replacement))))
+ (cdr replacements))
+ ;; Proposed edit applied to the group's prefix and suffix.
+ (cons (concat (substring prefix 0 (- (length prefix) (nth 0 choice)))
+ (nth 1 choice))
+ (concat (nth 3 choice)
+ (substring suffix (nth 2 choice))))))
+ (and (null replacements) 'no-match)
+ ;; Didn't find anything suitable - return entity parts unchanged.
+ (cons prefix suffix))))
+
+(defun company--multi-backend-adapter-candidates (backends min-length separate)
(let* (backend-prefix suffix
(pairs (cl-loop for backend in backends
when (let ((bp (let ((company-backend backend))
- (company-call-backend 'prefix))))
- (and
- ;; It's important that the lengths match.
- (equal (company--prefix-str bp) prefix)
- ;; One might override min-length, another not.
- (if (company--good-prefix-p bp min-length)
- (setq backend-prefix (company--prefix-str
bp)
- suffix (company--suffix-str bp))
- t
- (push backend
company--multi-uncached-backends)
- nil)))
+ (company-call-backend 'prefix))))
+ ;; One might override min-length, another not.
+ (if (company--good-prefix-p bp min-length)
+ (setq backend-prefix (company--prefix-str
bp)
+ suffix (company--suffix-str bp))
+ (push backend
company--multi-uncached-backends)
+ nil))
collect (cons (funcall backend 'candidates
backend-prefix suffix)
(company--multi-candidates-mapper
backend
@@ -1647,9 +1771,8 @@ update if FORCE-UPDATE."
(setq company-common
(if (cdr company-candidates)
(let ((common (try-completion "" company-candidates)))
- (when (string-prefix-p company-prefix common
- completion-ignore-case)
- common))
+ (and (stringp common)
+ common))
(car company-candidates)))))
(defun company-calculate-candidates (prefix ignore-case suffix)
@@ -2928,6 +3051,46 @@ For use in the `select-mouse' frontend action.
`let'-bound.")
(let ((result (nth company-selection company-candidates)))
(company-finish result))))
+(defun company--expand-common (prefix suffix)
+ (let ((expansion (company-call-backend 'expand-common prefix suffix)))
+ (unless expansion
+ ;; Backend doesn't implement this, try emulating.
+ (let* (;; XXX: We could also filter/group `company-candidates'.
+ (candidates (company-call-backend 'candidates prefix suffix))
+ ;; Assuming that boundaries don't vary between completions here.
+ ;; If they do, the backend should have a custom `expand-common'.
+ (boundaries-prefix (car (company--boundaries)))
+ (completion-ignore-case (company-call-backend 'ignore-case))
+ (trycmp (try-completion boundaries-prefix candidates))
+ (common (if (eq trycmp t) (car candidates) trycmp))
+ (max-len (when (and common
+ (cl-every (lambda (s) (string-suffix-p
+ suffix s
+ completion-ignore-case))
+ candidates))
+ (-
+ (apply #'min
+ (mapcar #'length candidates))
+ (length suffix))))
+ (common (if max-len
+ (substring common 0
+ (min max-len (length common)))
+ common)))
+ (setq expansion
+ (cond
+ ((null candidates)
+ 'no-match)
+ ((string-prefix-p boundaries-prefix common t)
+ (cons (concat
+ (substring prefix
+ 0
+ (- (length prefix)
+ (length boundaries-prefix)))
+ common)
+ suffix))
+ (t (cons prefix suffix))))))
+ expansion))
+
(defun company-complete-common ()
"Insert the common part of all candidates."
(interactive)
@@ -2935,22 +3098,19 @@ For use in the `select-mouse' frontend action.
`let'-bound.")
(if (and (not (cdr company-candidates))
(equal company-common (car company-candidates)))
(company-complete-selection)
- ;; FIXME: Poor man's completion-try-completion.
- (let* ((max-len (when (and company-common
- (cl-every (lambda (s) (string-suffix-p
company-suffix s))
- company-candidates))
- (apply #'min
- (mapcar
- (lambda (s) (- (length s) (length
company-suffix)))
- company-candidates))))
- (company-common (if max-len
- (substring company-common 0
- (min max-len (length
company-common)))
- company-common))
- (company-suffix ""))
- (company--insert-candidate company-common
- (or (car (company--boundaries))
- company-prefix))))))
+ (let ((expansion (company--expand-common company-prefix
+ company-suffix)))
+ (when (eq expansion 'no-match)
+ (user-error "No matches for the current input"))
+ (unless (equal (car expansion) company-prefix)
+ (if (eq (company-call-backend 'ignore-case) 'keep-prefix)
+ (insert (substring (car expansion) (length company-prefix)))
+ (delete-region (- (point) (length company-prefix)) (point))
+ (insert (car expansion))))
+ (unless (equal (cdr expansion) company-suffix)
+ (save-excursion
+ (delete-region (point) (+ (point) (length company-suffix)))
+ (insert (cdr expansion))))))))
(defun company-complete-common-or-cycle (&optional arg)
"Insert the common part of all candidates, or select the next one.
@@ -3510,13 +3670,6 @@ If SHOW-VERSION is non-nil, show the version in the echo
area."
(defun company--common-or-matches (value &optional suffix)
(let ((matches (company-call-backend 'match value)))
- (when (and matches
- company-common
- (listp matches)
- (= 1 (length matches))
- (= 0 (caar matches))
- (> (length company-common) (cdar matches)))
- (setq matches nil))
(when (integerp matches)
(setq matches `((0 . ,matches))))
(or matches
diff --git a/test/async-tests.el b/test/async-tests.el
index b4d16ab62e..942fdc7f19 100644
--- a/test/async-tests.el
+++ b/test/async-tests.el
@@ -128,7 +128,7 @@
(lambda (command)
(should (eq command 'prefix))
"foo"))))
- (should (equal "foo" (company-call-backend-raw 'prefix))))
+ (should (equal '("foo" nil 3) (company-call-backend-raw 'prefix))))
(let ((company-backend (list (lambda (_command)
(cons :async
(lambda (cb)
@@ -137,7 +137,7 @@
(lambda () (funcall cb "bar"))))))
(lambda (_command)
"foo"))))
- (should (equal "bar" (company-call-backend-raw 'prefix))))))
+ (should (equal '("bar" nil 3) (company-call-backend-raw 'prefix))))))
(ert-deftest company-multi-backend-merges-deferred-candidates ()
(with-temp-buffer
diff --git a/test/capf-tests.el b/test/capf-tests.el
index f1e446b9e9..06437c92a6 100644
--- a/test/capf-tests.el
+++ b/test/capf-tests.el
@@ -84,8 +84,8 @@
(company--equal-including-properties
render
#("with-timeout-suspend"
- 0 12 (face (company-tooltip-common company-tooltip)) ; "with"
- 12 20 (face company-tooltip)))))))
+ 0 7 (face (company-tooltip-common company-tooltip)) ; "with"
+ 7 20 (face company-tooltip)))))))
;; Re. "perfect" highlighting of the non-prefix in company-capf matches, it is
diff --git a/test/core-tests.el b/test/core-tests.el
index 76e7a7bcff..0f8230f9ee 100644
--- a/test/core-tests.el
+++ b/test/core-tests.el
@@ -109,9 +109,9 @@
company-candidates-cache
company-common)
(company-update-candidates '("abc" "def-abc"))
- (should (null company-common))
+ (should (equal company-common ""))
(company-update-candidates '("abc" "abe-c"))
- (should (null company-common))
+ (should (equal company-common "ab"))
(company-update-candidates '("abcd" "abcde" "abcdf"))
(should (equal "abcd" company-common))))
@@ -128,22 +128,34 @@
(company-call-backend 'set-min-prefix 1)
(should (equal (company-call-backend 'candidates "z") '("a" "b" "c"
"d")))))
-(ert-deftest company-multi-backend-filters-backends-by-prefix ()
+(ert-deftest company-multi-backend-with-empty-prefixes ()
(let ((company-backend
(list (lambda (command &optional _ &rest _r)
(cl-case command
- (prefix (cons "z" t))
+ (prefix "")
(candidates '("a" "b"))))
(lambda (command &optional _ &rest _r)
(cl-case command
- (prefix "t")
- (candidates '("c" "d"))))
- (lambda (command &optional _ &rest _r)
+ (prefix "")
+ (candidates '("c" "d")))))))
+ (should (equal (company-call-backend 'prefix) '("" nil 0)))))
+
+(ert-deftest company-multi-backend-dispatches-separate-prefix-to-backends ()
+ (let ((company-backend
+ (list (lambda (command &optional arg &rest _r)
(cl-case command
- (prefix "z")
- (candidates '("e" "f")))))))
+ (prefix (cons "z" t))
+ (candidates
+ (should (equal arg "z"))
+ '("a" "b"))))
+ (lambda (command &optional arg &rest _r)
+ (cl-case command
+ (prefix "t")
+ (candidates
+ (should (equal arg "t"))
+ '("c" "d")))))))
(company-call-backend 'set-min-prefix 1)
- (should (equal (company-call-backend 'candidates "z") '("a" "b" "e"
"f")))))
+ (should (equal (company-call-backend 'candidates "z") '("a" "b" "c"
"d")))))
(ert-deftest company-multi-backend-remembers-candidate-backend ()
(let ((company-backend
@@ -190,7 +202,7 @@
(let ((company-backend (list 'ignore 'ignore :with secundo)))
(should (null (company-call-backend 'prefix))))
(let ((company-backend (list 'ignore primo :with secundo)))
- (should (equal "a" (company-call-backend 'prefix)))
+ (should (equal '("a" nil 1) (company-call-backend 'prefix)))
(company-call-backend 'set-min-prefix 1)
(should (equal '("abb" "abc" "abd" "acc" "acd")
(company-call-backend 'candidates "a"))))))
@@ -233,7 +245,7 @@
(let ((company-backend (list one two tri)))
(should (equal '("bb" "ab")
(company-call-backend 'candidates "a"))))
- (company-call-backend 'set-min-prefix 0)
+ (company-call-backend 'set-min-prefix 1)
(let ((company-backend (list one two tri)))
(should (equal '("aa" "ca" "ba" "bb" "ab")
(company-call-backend 'candidates "a"))))))
@@ -285,17 +297,17 @@
(let ((company-backend (list one tri fur)))
(should
(equal
- '("aa" . 3)
+ '("aa" nil 3)
(company-call-backend 'prefix))))
(let ((company-backend (list one two tri fur)))
(should
(equal
- '("aa" . t)
+ '("aa" nil t)
(company-call-backend 'prefix))))
(let ((company-backend (list one fiv)))
(should
(equal
- "aa"
+ '("aa" nil 2)
(company-call-backend 'prefix))))))
(ert-deftest company-multi-backend-supports-different-suffixes ()
@@ -319,7 +331,7 @@
'("a3")))))
(company-backend (list one two tri)))
(should
- (equal '("a" "b")
+ (equal '("a" "b" 1)
(company-call-backend 'prefix)))
(should
(equal '("a1b" "a2" "a3")
@@ -333,23 +345,81 @@
'("a1b")))))
(tri (lambda (command &rest args)
(cl-case command
- (prefix '("a" "bcd"))
+ (prefix '("aa" "bcd"))
(adjust-boundaries
(should (equal args
- '("a3" "a" "bcd")))
+ '("a3" "aa" "bcd")))
(cons "a" "bc"))
(candidates
'("a3")))))
(company-backend (list one tri))
+ (company-point (point))
(candidates (company-call-backend 'candidates "a" "")))
(should
- (equal '("a" "")
+ (equal '("aa" "bcd" 2)
(company-call-backend 'prefix)))
(should
(equal (cons "a" "bc")
(company-call-backend 'adjust-boundaries
(car (member "a3" candidates))
- "a" "")))))
+ "aa" "bcd")))
+ (should
+ (equal (cons "a" "")
+ (company-call-backend 'adjust-boundaries
+ (car (member "a1b" candidates))
+ "aa" "bcd")))))
+
+(ert-deftest company-multi-backend-combines-expand-common ()
+ (let* ((one (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("a" ""))
+ (expand-common (cons "ab" "")))))
+ (two (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("aa" "bcd"))
+ (expand-common (cons "aab" "bcd")))))
+ (tri (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("aa" "bcd"))
+ (expand-common 'no-match))))
+ (company-backend (list one two tri))
+ (company-point (point)))
+ (company-call-backend 'set-min-prefix 1)
+ (should
+ (equal '("aab" . "bcd")
+ (company-call-backend 'expand-common "aa" "bcd")))))
+
+(ert-deftest company-multi-backend-expand-common-returns-no-match ()
+ (let* ((one (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("a" ""))
+ (expand-common 'no-match))))
+ (two (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("aa" "bcd"))
+ (expand-common 'no-match))))
+ (company-backend (list one two))
+ (company-point (point)))
+ (company-call-backend 'set-min-prefix 1)
+ (should
+ (equal 'no-match
+ (company-call-backend 'expand-common "aa" "bcd")))))
+
+(ert-deftest company-multi-backend-expand-common-keeps-current ()
+ (let* ((one (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("a" ""))
+ (expand-common (cons "ab" "")))))
+ (two (lambda (command &rest _args)
+ (cl-case command
+ (prefix '("a" ""))
+ (expand-common (cons "ac" "")))))
+ (company-backend (list one two))
+ (company-point (point)))
+ (company-call-backend 'set-min-prefix 1)
+ (should
+ (equal '("a" . "")
+ (company-call-backend 'expand-common "a" "")))))
(ert-deftest company-begin-backend-failure-doesnt-break-company-backends ()
(with-temp-buffer
- [elpa] externals/company de19f899d1 15/24: Add possible return value `no-match` to `expand-common`, (continued)
- [elpa] externals/company de19f899d1 15/24: Add possible return value `no-match` to `expand-common`, ELPA Syncer, 2024/08/27
- [elpa] externals/company a79bfd7cea 19/24: Fix multi-backend completion right after a trigger char, ELPA Syncer, 2024/08/27
- [elpa] externals/company 39a4aee31c 16/24: Delete piece of code unused since 36aae5183, ELPA Syncer, 2024/08/27
- [elpa] externals/company 225d27d392 17/24: Update one test (1) and fix another (2), ELPA Syncer, 2024/08/27
- [elpa] externals/company 64a3787db7 14/24: Copy edit, ELPA Syncer, 2024/08/27
- [elpa] externals/company df4f6e9ea3 21/24: company--common-or-matches: Synchronize with 'match' more, ELPA Syncer, 2024/08/27
- [elpa] externals/company 8a4872a81b 23/24: company-capf--current-boundaries only for matching completions, ELPA Syncer, 2024/08/27
- [elpa] externals/company e1d331a64e 24/24: [ci skip] Remove parens, ELPA Syncer, 2024/08/27
- [elpa] externals/company 36aae5183a 13/24: company--multi-expand-common: Simplify the compatibility check, ELPA Syncer, 2024/08/27
- [elpa] externals/company 71fad0b38a 06/24: Delete a no-op line, ELPA Syncer, 2024/08/27
- [elpa] externals/company 4ba6dcb874 22/24: Merge pull request #1488 from company-mode/expand-common,
ELPA Syncer <=
- [elpa] externals/company 82e7f81dcb 07/24: Support complete-common in backends with boundaries and no `expand-common`, ELPA Syncer, 2024/08/27
- [elpa] externals/company cb3b67122d 01/24: company-complete-common: Generalized "expand common" behavior, ELPA Syncer, 2024/08/27
- [elpa] externals/company 7b849c0c6f 18/24: Mo tests and some fixes, ELPA Syncer, 2024/08/27
- [elpa] externals/company b2b9b19f9a 20/24: Update the NEWS entry, ELPA Syncer, 2024/08/27
- [elpa] externals/company 4647272f62 08/24: Improve the default `expand-common` implementation to support boundaries, ELPA Syncer, 2024/08/27
- [elpa] externals/company ed4a93f576 10/24: company--multi-expand-common: Analyze each backend's completions separately, ELPA Syncer, 2024/08/27