corfu-info.el (4681B)
1 ;;; corfu-info.el --- Show candidate information in separate buffer -*- 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 ;; This Corfu extension provides commands to show additional information to the 29 ;; candidates in a separate buffer. The commands `corfu-info-location' and 30 ;; `corfu-info-documentation' are bound by default in the `corfu-map' to M-g and 31 ;; M-h respectively. 32 33 ;;; Code: 34 35 (require 'corfu) 36 (eval-when-compile 37 (require 'subr-x)) 38 39 (defun corfu-info--restore-on-next-command () 40 "Restore window configuration before next command." 41 (let ((config (current-window-configuration)) 42 (other other-window-scroll-buffer) 43 (restore (make-symbol "corfu--restore"))) 44 (fset restore 45 (lambda () 46 (setq other-window-scroll-buffer other) 47 (unless (memq this-command '(scroll-other-window scroll-other-window-down)) 48 (when (memq this-command '(corfu-quit corfu-reset)) 49 (setq this-command #'ignore)) 50 (remove-hook 'pre-command-hook restore) 51 (set-window-configuration config)))) 52 (add-hook 'pre-command-hook restore))) 53 54 (defun corfu-info--display-buffer (buffer name) 55 "Display BUFFER and return window displaying the buffer. 56 Make the buffer persistent with NAME if non-nil." 57 (if name 58 (unless (buffer-local-value 'buffer-file-name buffer) 59 (if-let ((old (get-buffer name))) 60 (setq buffer (prog1 old (kill-buffer buffer))) 61 (with-current-buffer buffer 62 (rename-buffer name)))) 63 (corfu-info--restore-on-next-command)) 64 (setq other-window-scroll-buffer buffer) 65 (display-buffer buffer t)) 66 67 ;;;###autoload 68 (defun corfu-info-documentation (&optional arg) 69 "Show documentation of current candidate. 70 If called with a prefix ARG, the buffer is persistent." 71 (interactive "P") 72 ;; Company support, taken from `company.el', see `company-show-doc-buffer'. 73 (when (< corfu--index 0) 74 (user-error "No candidate selected")) 75 (let ((cand (nth corfu--index corfu--candidates))) 76 (if-let ((extra (nth 4 completion-in-region--data)) 77 (fun (plist-get extra :company-doc-buffer)) 78 (res (funcall fun cand))) 79 (set-window-start (corfu-info--display-buffer 80 (get-buffer (or (car-safe res) res)) 81 (and arg (format "*corfu doc: %s*" cand))) 82 (or (cdr-safe res) (point-min))) 83 (user-error "No documentation available for `%s'" cand)))) 84 85 ;;;###autoload 86 (defun corfu-info-location (&optional arg) 87 "Show location of current candidate. 88 If called with a prefix ARG, the buffer is persistent." 89 (interactive "P") 90 ;; Company support, taken from `company.el', see `company-show-location'. 91 (when (< corfu--index 0) 92 (user-error "No candidate selected")) 93 (let ((cand (nth corfu--index corfu--candidates))) 94 (if-let ((extra (nth 4 completion-in-region--data)) 95 (fun (plist-get extra :company-location)) 96 ;; BUG: company-location may throw errors if location is not found 97 (loc (ignore-errors (funcall fun cand)))) 98 (with-selected-window 99 (corfu-info--display-buffer 100 (or (and (bufferp (car loc)) (car loc)) 101 (find-file-noselect (car loc) t)) 102 (and arg (format "*corfu loc: %s*" cand))) 103 (without-restriction 104 (goto-char (point-min)) 105 (when-let ((pos (cdr loc))) 106 (if (bufferp (car loc)) 107 (goto-char pos) 108 (forward-line (1- pos)))) 109 (set-window-start nil (point)))) 110 (user-error "No location available for `%s'" cand)))) 111 112 (provide 'corfu-info) 113 ;;; corfu-info.el ends here