branch: externals/cape commit 28a2a1655026ae68ed9180db6527694334c5d1d4 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
cape-dict-limit: New customizable variable --- CHANGELOG.org | 3 +++ cape.el | 86 ++++++++++++++++++++++++++++++++++------------------------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index d1fd28f518..ad51cf12d9 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -5,6 +5,9 @@ * Changelog - =cape-dict=: Always use grep, remove =cape-dict-use-grep=. +- =cape-dict=: Add =cape-dict-limit=. +- Generalize =cape--cached-table=. The candidate computation function must return + a pair of a predicate function and the list of candidates. * Version 0.16 (2023-07-02) diff --git a/cape.el b/cape.el index 149d75f885..5ecb3030b8 100644 --- a/cape.el +++ b/cape.el @@ -62,6 +62,10 @@ :group 'matching :prefix "cape-") +(defcustom cape-dict-limit 100 + "Maximal number of completion candidates returned by `cape-dict'." + :type '(choice (const nil) natnum)) + (defcustom cape-dict-file "/usr/share/dict/words" "Path to dictionary word list file. This variable can also be a list of paths or @@ -214,16 +218,16 @@ SORT should be nil to disable sorting." metadata (complete-with-action action table str pred)))))) -(defun cape--cached-table (beg end fun valid) +(defun cape--cached-table (beg end fun) "Create caching completion table. BEG and END are the input bounds. FUN is the function which -computes the candidates. VALID is a function taking the old and -new input string. It should return nil if the cached candidates -became invalid." - (let ((input 'init) - (beg (copy-marker beg)) +computes the candidates. FUN must return a pair of a predicate +function function and the list of candidates. The predicate is +passed new input and must return non-nil if the candidates are +still valid." + (let ((beg (copy-marker beg)) (end (copy-marker end t)) - (table nil)) + valid table) (lambda (str pred action) ;; Bail out early for `metadata' and `boundaries'. This is a pointless ;; move because of caching, but we do it anyway in the hope that the @@ -232,13 +236,13 @@ became invalid." ;; `all-completions' must surely be most expensive, so nobody will suspect ;; a thing. (unless (or (eq action 'metadata) (eq (car-safe action) 'boundaries)) - (let ((new-input (buffer-substring-no-properties beg end))) - (when (or (eq input 'init) - (not (or (string-match-p "\\s-" new-input) ;; Support Orderless - (funcall valid input new-input)))) - (let ((new-table (funcall fun new-input)) - (throw-on-input nil)) ;; No interrupt during state update - (setq table new-table input new-input)))) + (let ((input (buffer-substring-no-properties beg end))) + (when (or (not valid) + (not (or (string-match-p "\\s-" input) ;; Support Orderless + (funcall valid input)))) + (pcase-let ((`(,new-valid . ,new-table) (funcall fun input)) + (throw-on-input nil)) ;; No interrupt during state update + (setq table new-table valid new-valid)))) (complete-with-action action table str pred))))) ;;;; Capfs @@ -439,11 +443,13 @@ If INTERACTIVE is nil the function acts like a Capf." (let ((dabbrev-check-other-buffers (not (null cape-dabbrev-check-other-buffers))) (dabbrev-check-all-buffers (eq cape-dabbrev-check-other-buffers t))) (dabbrev--reset-global-variables)) - (cl-loop with min-len = (+ cape-dabbrev-min-length (length input)) - with ic = (cape--case-fold-p dabbrev-case-fold-search) - for w in (dabbrev--find-all-expansions input ic) - if (>= (length w) min-len) collect - (cape--case-replace (and ic dabbrev-case-replace) input w)))) + (cons + (apply-partially #'string-prefix-p input) + (cl-loop with min-len = (+ cape-dabbrev-min-length (length input)) + with ic = (cape--case-fold-p dabbrev-case-fold-search) + for w in (dabbrev--find-all-expansions input ic) + if (>= (length w) min-len) collect + (cape--case-replace (and ic dabbrev-case-replace) input w))))) (defun cape--dabbrev-bounds () "Return bounds of abbreviation." @@ -483,8 +489,7 @@ See the user options `cape-dabbrev-min-length' and `(,(car bounds) ,(cdr bounds) ,(cape--table-with-properties (completion-table-case-fold - (cape--cached-table (car bounds) (cdr bounds) - #'cape--dabbrev-list #'string-prefix-p) + (cape--cached-table (car bounds) (cdr bounds) #'cape--dabbrev-list) (not (cape--case-fold-p dabbrev-case-fold-search))) :category 'cape-dabbrev) ,@cape--dabbrev-properties)))) @@ -500,18 +505,25 @@ See the user options `cape-dabbrev-min-length' and (defun cape--dict-list (input) "Return all words from `cape-dict-file' matching INPUT." (unless (equal input "") - (cape--case-replace-list - cape-dict-case-replace input - (let ((inhibit-message t) - (message-log-max nil)) - (apply #'process-lines-ignore-status - "grep" - (concat "-Fh" (and (cape--case-fold-p cape-dict-case-fold) "i")) - input - (ensure-list - (if (functionp cape-dict-file) - (funcall cape-dict-file) - cape-dict-file))))))) + (let* ((inhibit-message t) + (message-log-max nil) + (files (ensure-list + (if (functionp cape-dict-file) + (funcall cape-dict-file) + cape-dict-file))) + (words + (apply #'process-lines-ignore-status + "grep" + (concat "-Fh" + (and (cape--case-fold-p cape-dict-case-fold) "i") + (and cape-dict-limit (format "m%d" cape-dict-limit))) + input files))) + (cons + (apply-partially + (if (and cape-dict-limit (length= words cape-dict-limit)) + #'equal #'string-search) + input) + (cape--case-replace-list cape-dict-case-replace input words))))) ;;;###autoload (defun cape-dict (&optional interactive) @@ -525,7 +537,7 @@ If INTERACTIVE is nil the function acts like a Capf." `(,beg ,end ,(cape--table-with-properties (completion-table-case-fold - (cape--cached-table beg end #'cape--dict-list #'string-search) + (cape--cached-table beg end #'cape--dict-list) (not (cape--case-fold-p cape-dict-case-fold))) :category 'cape-dict) ,@cape--dict-properties)))) @@ -764,6 +776,8 @@ changed. The function `cape-company-to-capf' is experimental." (initial-input (if (stringp prefix) prefix (car-safe prefix)))) (let* ((end (point)) (beg (- end (length initial-input))) (dups (cape--company-call backend 'duplicates)) + (valid (if (cape--company-call backend 'no-cache initial-input) + #'equal (or valid #'string-prefix-p))) candidates) (list beg end (funcall @@ -776,9 +790,7 @@ changed. The function `cape-company-to-capf' is experimental." (lambda (input) (setq candidates (cape--company-call backend 'candidates input)) (when dups (setq candidates (delete-dups candidates))) - candidates) - (if (cape--company-call backend 'no-cache initial-input) - #'equal (or valid #'string-prefix-p))) + (cons (apply-partially valid input) candidates))) :category backend :sort (not (cape--company-call backend 'sorted)))) :exclusive 'no