emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/company 909ae49665 4/5: Merge pull request #1411 from c


From: ELPA Syncer
Subject: [elpa] externals/company 909ae49665 4/5: Merge pull request #1411 from company-mode/drop-keep-prefix
Date: Sat, 14 Oct 2023 21:57:38 -0400 (EDT)

branch: externals/company
commit 909ae49665dbb5b435e8939af2c1e7b55123c1b1
Merge: 88f0b4d792 8469032b02
Author: Dmitry Gutov <dmitry@gutov.dev>
Commit: GitHub <noreply@github.com>

    Merge pull request #1411 from company-mode/drop-keep-prefix
    
    Add explicit caching mechanism (for backends) and fold the `keep-prefix` 
logic inside
---
 NEWS.md            |  7 +++++++
 company-dabbrev.el | 49 ++++++++++++++++++++++++++++---------------------
 company-ispell.el  | 42 ++++++++++++++++++++++++++----------------
 company.el         | 40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 101 insertions(+), 37 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index ef62ce9eea..c12124deb2 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,13 @@
 
 # Next
 
+* The backend command `keep-prefix` is being phased out.  The built-in backends
+  implement it internally now, which resolved a number of sharp edges (mostly)
+  around "grouped" backends.  To make that easier, several helpers were added,
+  such as `company-cache-fetch` and `company-substitute-prefix`
+  ([#1411](https://github.com/company-mode/company-mode/pull/1411)).  And
+  `company-ispell` uses the cache to keep the currently selected dictionary
+  loaded in memory between completions.
 * The "length override" behavior in grouped backends now acts on each backend
   separately ([#1405](https://github.com/company-mode/company-mode/pull/1405)).
 
diff --git a/company-dabbrev.el b/company-dabbrev.el
index b7434de393..968b86cde6 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -1,6 +1,6 @@
 ;;; company-dabbrev.el --- dabbrev-like company-mode completion backend  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 2009-2011, 2013-2018, 2021  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013-2018, 2021-2023  Free Software Foundation, 
Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -70,10 +70,7 @@ candidate is inserted, even some of its characters have 
different case."
 
 The value of nil means keep them as-is.
 `case-replace' means use the value of `case-replace'.
-Any other value means downcase.
-
-If you set this value to nil, you may also want to set
-`company-dabbrev-ignore-case' to any value other than `keep-prefix'."
+Any other value means downcase."
   :type '(choice
           (const :tag "Keep as-is" nil)
           (const :tag "Downcase" t)
@@ -177,8 +174,26 @@ This variable affects both `company-dabbrev' and 
`company-dabbrev-code'."
                        1)))
 
 (defun company-dabbrev--filter (prefix candidates)
-  (let ((completion-ignore-case company-dabbrev-ignore-case))
-    (all-completions prefix candidates)))
+  (let* ((completion-ignore-case company-dabbrev-ignore-case)
+         (filtered (all-completions prefix candidates))
+         (lp (length prefix)))
+    (if (and (eq company-dabbrev-ignore-case 'keep-prefix)
+             (not (= lp 0)))
+        (company-substitute-prefix prefix filtered)
+      filtered)))
+
+(defun company-dabbrev--fetch ()
+  (let ((words (company-dabbrev--search (company-dabbrev--make-regexp)
+                                        company-dabbrev-time-limit
+                                        (pcase company-dabbrev-other-buffers
+                                          (`t (list major-mode))
+                                          (`all `all))))
+        (downcase-p (if (eq company-dabbrev-downcase 'case-replace)
+                        case-replace
+                      company-dabbrev-downcase)))
+    (if downcase-p
+        (mapcar 'downcase words)
+      words)))
 
 ;;;###autoload
 (defun company-dabbrev (command &optional arg &rest _ignored)
@@ -188,21 +203,13 @@ This variable affects both `company-dabbrev' and 
`company-dabbrev-code'."
     (interactive (company-begin-backend 'company-dabbrev))
     (prefix (company-dabbrev--prefix))
     (candidates
-     (let* ((case-fold-search company-dabbrev-ignore-case)
-            (words (company-dabbrev--search (company-dabbrev--make-regexp)
-                                            company-dabbrev-time-limit
-                                            (pcase 
company-dabbrev-other-buffers
-                                              (`t (list major-mode))
-                                              (`all `all))))
-            (downcase-p (if (eq company-dabbrev-downcase 'case-replace)
-                            case-replace
-                          company-dabbrev-downcase)))
-       (setq words (company-dabbrev--filter arg words))
-       (if downcase-p
-           (mapcar 'downcase words)
-         words)))
+     (company-dabbrev--filter
+      arg
+      (company-cache-fetch 'dabbrev-candidates #'company-dabbrev--fetch
+                           :expire t)))
     (kind 'text)
-    (ignore-case company-dabbrev-ignore-case)
+    (no-cache t)
+    (ignore-case (and company-dabbrev-ignore-case t))
     (duplicates t)))
 
 (provide 'company-dabbrev)
diff --git a/company-ispell.el b/company-ispell.el
index 3cb7c5d693..b4a9ca1539 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -1,6 +1,6 @@
 ;;; company-ispell.el --- company-mode completion backend using Ispell
 
-;; Copyright (C) 2009-2011, 2013-2016, 2018, 2021  Free Software Foundation, 
Inc.
+;; Copyright (C) 2009-2011, 2013-2016, 2018, 2021, 2023  Free Software 
Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -33,30 +33,35 @@
   "Completion backend using Ispell."
   :group 'company)
 
+(defun company--set-dictionary (symbol value)
+  (set-default-toplevel-value symbol value)
+  (company-cache-delete 'ispell-candidates))
+
 (defcustom company-ispell-dictionary nil
   "Dictionary to use for `company-ispell'.
 If nil, use `ispell-complete-word-dict'."
   :type '(choice (const :tag "default (nil)" nil)
-                 (file :tag "dictionary" t)))
+                 (file :tag "dictionary" t))
+  :set #'company--set-dictionary)
 
 (defvar company-ispell-available 'unknown)
 
-(defalias 'company-ispell--lookup-words
-  (if (fboundp 'ispell-lookup-words)
-      'ispell-lookup-words
-    'lookup-words))
-
 (defun company-ispell-available ()
   (when (eq company-ispell-available 'unknown)
     (condition-case err
         (progn
-          (company-ispell--lookup-words "WHATEVER")
+          (ispell-lookup-words "WHATEVER")
           (setq company-ispell-available t))
       (error
        (message "Company-Ispell: %s" (error-message-string err))
        (setq company-ispell-available nil))))
   company-ispell-available)
 
+(defun company--ispell-dict ()
+  (or company-ispell-dictionary
+      ispell-complete-word-dict
+      ispell-alternate-dictionary))
+
 ;;;###autoload
 (defun company-ispell (command &optional arg &rest ignored)
   "`company-mode' completion backend using Ispell."
@@ -66,18 +71,23 @@ If nil, use `ispell-complete-word-dict'."
     (prefix (when (company-ispell-available)
               (company-grab-word)))
     (candidates
-     (let ((words (company-ispell--lookup-words
-                   arg
-                   (or company-ispell-dictionary ispell-complete-word-dict)))
-           (completion-ignore-case t))
+     (let* ((dict (company--ispell-dict))
+            (all-words
+             (company-cache-fetch 'ispell-candidates
+                                  (lambda () (ispell-lookup-words "" dict))
+                                  :check-tag dict))
+            (completion-ignore-case t))
        (if (string= arg "")
            ;; Small optimization.
-           words
-         ;; Work around issue #284.
-         (all-completions arg words))))
+           all-words
+         (company-substitute-prefix
+          arg
+          ;; Work around issue #284.
+          (all-completions arg all-words)))))
     (kind 'text)
+    (no-cache t)
     (sorted t)
-    (ignore-case 'keep-prefix)))
+    (ignore-case t)))
 
 (provide 'company-ispell)
 ;;; company-ispell.el ends here
diff --git a/company.el b/company.el
index a87ececc89..4209051113 100644
--- a/company.el
+++ b/company.el
@@ -1133,6 +1133,42 @@ matches IDLE-BEGIN-AFTER-RE, return it wrapped in a 
cons."
         (car (setq ppss (cdr ppss)))
         (nth 3 ppss))))
 
+(defun company-substitute-prefix (prefix strings)
+  (let ((len (length prefix)))
+    (mapcar
+     (lambda (s)
+       (if (eq t (compare-strings prefix 0 len s 0 len))
+           s
+         (concat prefix (substring s len))))
+     strings)))
+
+(defvar company--cache (make-hash-table :test #'equal :size 10))
+
+(cl-defun company-cache-fetch (key
+                               fetcher
+                               &key expire &key check-tag)
+  "Fetch the value assigned to KEY in the cache.
+When not found, or when found to be stale, calls FETCHER to compute the
+result.  When EXPIRE is non-nil, the value will be deleted at the end of
+completion.  CHECK-TAG, when present, is saved as well, and the entry will
+be recomputed when this value changes."
+  ;; We could make EXPIRE accept a time value as well.
+  (let ((res (gethash key company--cache 'none))
+        value)
+    (if (and (not (eq res 'none))
+             (or (not check-tag)
+                 (equal check-tag (assoc-default :check-tag res))))
+        (assoc-default :value res)
+      (setq res (list (cons :value (setq value (funcall fetcher)))))
+      (if expire (push '(:expire . t) res))
+      (if check-tag (push `(:check-tag . ,check-tag) res))
+      (puthash key res company--cache)
+      value)))
+
+(defun company-cache-delete (key)
+  "Delete KEY from cache."
+  (remhash key company--cache))
+
 (defun company-call-backend (&rest args)
   (company--force-sync #'company-call-backend-raw args company-backend))
 
@@ -2208,6 +2244,10 @@ For more details see `company-insertion-on-trigger' and
           company--multi-uncached-backends nil
           company--multi-min-prefix nil
           company-point nil)
+    (maphash (lambda (k v)
+               (when (assoc-default :expire v)
+                 (remhash k company--cache)))
+             company--cache)
     (when company-timer
       (cancel-timer company-timer))
     (company-echo-cancel t)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]