]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve elisp CAPF sorting
authorEshel Yaron <me@eshelyaron.com>
Tue, 4 Mar 2025 15:05:47 +0000 (16:05 +0100)
committerEshel Yaron <me@eshelyaron.com>
Tue, 4 Mar 2025 15:05:47 +0000 (16:05 +0100)
lisp/minibuffer.el
lisp/progmodes/elisp-mode.el

index 35723faf1851238a6007152a74312b96ffefc1ab..323efca2d42337d25eb065cc9978670bb0c597fc 100644 (file)
@@ -3398,6 +3398,40 @@ obey `completion-styles').")
            (setq res nil))))
     res))
 
+(defun completion-at-point-function-with-frecency-sorting
+    (capf &optional num-ts)
+  (let ((cache (make-hash-table :test #'equal))
+        (num-ts (or num-ts 64)))
+    (lambda ()
+      (let ((res (ignore-errors (funcall capf))))
+        (and (consp res)
+             (not (functionp res))
+             (seq-let (beg end table &rest plist) res
+               (let* ((pred (plist-get plist :predicate))
+                      (completion-extra-properties plist)
+                      (md (completion-metadata (buffer-substring beg end) table pred))
+                      (sf (completion-metadata-get md 'sort-function)))
+                 `( ,beg ,end
+                    ,(completion-table-with-metadata
+                      table
+                      `((sort-function
+                         . ,(lambda (completions)
+                              (sort (if sf (funcall sf completions) completions)
+                                    :key (let ((now (float-time)))
+                                           (lambda (c)
+                                             (if-let ((ts (gethash c cache)))
+                                                 (- (log (- now (car ts))) (length ts))
+                                               1.0e+INF)))
+                                    :in-place t)))))
+                    ,@(plist-put
+                       (copy-sequence plist)
+                       :exit-function
+                       (lambda (str _sts)
+                         (let* ((str (substring-no-properties str))
+                                (ts (gethash str cache)))
+                           (setf (gethash str cache)
+                                 (cons (float-time) (take num-ts ts))))))))))))))
+
 (defun completion-at-point ()
   "Perform completion on the text around point.
 The completion method is determined by `completion-at-point-functions'."
index bce12f3576561356ab8c9cb3623dba20bd6d3199..4ca5fe07060e066199f90226d91cb1507b550025 100644 (file)
@@ -652,7 +652,7 @@ be used instead.
   (setq-local project-vc-external-roots-function #'elisp-load-path-roots)
   (setq-local syntax-propertize-function #'elisp-mode-syntax-propertize)
   (add-hook 'completion-at-point-functions
-            #'elisp-completion-at-point nil 'local)
+            #'elisp-capf nil 'local)
   (add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
   (add-hook 'flymake-diagnostic-functions
               #'elisp-flymake-byte-compile nil t)
@@ -799,6 +799,21 @@ in `completion-at-point-functions' (which see)."
 (defun elisp--shorthand-aware-boundp (sym)
   (boundp (intern-soft (symbol-name sym))))
 
+(defun elisp--sort-completions (completions)
+  (sort completions
+        (lambda (l r)
+          (let ((li (string-match "--" l))
+                (ri (string-match "--" r)))
+            (if li
+                (and ri
+                     (or (< (length l) (length r))
+                         (and (= (length l) (length r))
+                              (string< l r))))
+              (or ri
+                  (< (length l) (length r))
+                  (and (= (length l) (length r))
+                       (string< l r))))))))
+
 (defun elisp-completion-at-point ()
   (with-syntax-table emacs-lisp-mode-syntax-table
     (when-let ((pos (point))
@@ -845,7 +860,13 @@ in `completion-at-point-functions' (which see)."
                (beg-end (bounds-of-thing-at-point 'symbol))
                (beg (car beg-end))
               (end (cdr beg-end)))
-      (list beg end (elisp--completion-local-symbols) :predicate predicate :exclusive 'no))))
+      (list beg end (elisp--completion-local-symbols)
+            :predicate predicate :exclusive 'no
+            :sort-function #'elisp--sort-completions))))
+
+(defalias 'elisp-capf
+  (completion-at-point-function-with-frecency-sorting
+   #'elisp-completion-at-point))
 
 (defun elisp--company-kind (str)
   (let ((sym (intern-soft str)))