config

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

corfu-history.el (3562B)


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