config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

corfu-history.el (3583B)


      1 ;;; corfu-history.el --- Sorting by history for Corfu -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2022-2024 Free Software Foundation, Inc.
      4 
      5 ;; Author: Daniel Mendler <mail@daniel-mendler.de>
      6 ;; Maintainer: Daniel Mendler <mail@daniel-mendler.de>
      7 ;; Created: 2022
      8 ;; Version: 1.5
      9 ;; Package-Requires: ((emacs "28.1") (compat "30") (corfu "1.5"))
     10 ;; Homepage: https://github.com/minad/corfu
     11 
     12 ;; This file is part of GNU Emacs.
     13 
     14 ;; This program is free software: you can redistribute it and/or modify
     15 ;; it under the terms of the GNU General Public License as published by
     16 ;; the Free Software Foundation, either version 3 of the License, or
     17 ;; (at your option) any later version.
     18 
     19 ;; This program is distributed in the hope that it will be useful,
     20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22 ;; GNU General Public License for more details.
     23 
     24 ;; You should have received a copy of the GNU General Public License
     25 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     26 
     27 ;;; Commentary:
     28 
     29 ;; Enable `corfu-history-mode' to sort candidates by their history
     30 ;; position.  Maintain a list of recently selected candidates.  In order
     31 ;; to save the history across Emacs sessions, enable `savehist-mode' and
     32 ;; add `corfu-history' to `savehist-additional-variables'.
     33 ;;
     34 ;; (corfu-history-mode 1)
     35 ;; (savehist-mode 1)
     36 ;; (add-to-list 'savehist-additional-variables 'corfu-history)
     37 
     38 ;;; Code:
     39 
     40 (require 'corfu)
     41 (eval-when-compile
     42   (require 'cl-lib))
     43 
     44 (defvar corfu-history nil
     45   "History of Corfu candidates.
     46 The maximum length is determined by the variable `history-length'
     47 or the property `history-length' of `corfu-history'.")
     48 
     49 (defvar corfu-history--hash nil
     50   "Hash table of Corfu candidates.")
     51 
     52 (defun corfu-history--sort-predicate (x y)
     53   "Sorting predicate which compares X and Y."
     54   (or (< (cdr x) (cdr y))
     55       (and (= (cdr x) (cdr y))
     56            (corfu--length-string< (car x) (car y)))))
     57 
     58 (defun corfu-history--sort (cands)
     59   "Sort CANDS by history."
     60   (unless corfu-history--hash
     61     (setq corfu-history--hash (make-hash-table :test #'equal :size (length corfu-history)))
     62     (cl-loop for elem in corfu-history for index from 0 do
     63              (unless (gethash elem corfu-history--hash)
     64                (puthash elem index corfu-history--hash))))
     65   ;; Decorate each candidate with (index<<13) + length. This way we sort first by index and then by
     66   ;; length. We assume that the candidates are shorter than 2**13 characters and that the history is
     67   ;; shorter than 2**16 entries.
     68   (cl-loop for cand on cands do
     69            (setcar cand (cons (car cand)
     70                               (+ (ash (gethash (car cand) corfu-history--hash #xFFFF) 13)
     71                                  (length (car cand))))))
     72   (setq cands (sort cands #'corfu-history--sort-predicate))
     73   (cl-loop for cand on cands do (setcar cand (caar cand)))
     74   cands)
     75 
     76 ;;;###autoload
     77 (define-minor-mode corfu-history-mode
     78   "Update Corfu history and sort completions by history."
     79   :global t :group 'corfu
     80   (if corfu-history-mode
     81       (add-function :override corfu-sort-function #'corfu-history--sort)
     82     (remove-function corfu-sort-function #'corfu-history--sort)))
     83 
     84 (cl-defmethod corfu--insert :before (_status &context (corfu-history-mode (eql t)))
     85   (when (>= corfu--index 0)
     86     (add-to-history 'corfu-history
     87                     (substring-no-properties
     88                      (nth corfu--index corfu--candidates)))
     89     (setq corfu-history--hash nil)))
     90 
     91 (provide 'corfu-history)
     92 ;;; corfu-history.el ends here