summaryrefslogtreecommitdiff
path: root/extensions/corfu-echo.el
blob: 824d9cb3a4bb92488ff0e2b9af637fc4b0ea53ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
;;; corfu-echo.el --- Show candidate documentation in echo area -*- lexical-binding: t -*-

;; Copyright (C) 2021-2022  Free Software Foundation, Inc.

;; Author: Daniel Mendler <mail@daniel-mendler.de>
;; Maintainer: Daniel Mendler <mail@daniel-mendler.de>
;; Created: 2022
;; Version: 0.1
;; Package-Requires: ((emacs "27.1") (corfu "0.31"))
;; Homepage: https://github.com/minad/corfu

;; This file is part of GNU Emacs.

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; Show candidate documentation in echo area. Enable `corfu-echo-mode'.

;;; Code:

(require 'corfu)
(eval-when-compile
  (require 'subr-x))

(defface corfu-echo
  '((t :inherit completions-annotations))
  "Face used for echo area messages."
  :group 'corfu-faces)

(defcustom corfu-echo-delay '(1.0 . 0.5)
  "Show documentation string in the echo area after that number of seconds.
Set to t for an instant message. The value can be a pair of two
floats to specify initial and subsequent delay."
  :type '(choice (const :tag "Never" nil)
                 (const :tag "Instant" t)
                 (number :tag "Delay in seconds")
                 (cons :tag "Two Delays"
                       (choice :tag "Initial   " number)
                       (choice :tag "Subsequent" number)))
  :group 'corfu)

(defvar-local corfu-echo--timer nil
  "Echo area message timer.")

(defvar-local corfu-echo--message nil
  "Last echo message.")

(defun corfu-echo--refresh ()
  "Refresh message to avoid flicker."
  (corfu-echo--cancel corfu-echo--message))

(defun corfu-echo--cancel (&optional msg)
  "Cancel echo timer and refresh MSG."
  (when corfu-echo--timer
    (cancel-timer corfu-echo--timer)
    (setq corfu-echo--timer nil))
  (corfu-echo--show msg)
  (unless corfu-echo--message
    (kill-local-variable 'corfu-echo--timer)
    (kill-local-variable 'corfu-echo--message)))

(defun corfu-echo--show (msg)
  "Show MSG in echo area."
  (when (or msg corfu-echo--message)
    (setq msg (or msg "")
          corfu-echo--message msg)
    (corfu--message "%s" (if (text-property-not-all 0 (length msg) 'face nil msg)
                             msg
                           (propertize msg 'face 'corfu-echo)))))

(defun corfu-echo--exhibit (&rest _)
  "Show documentation string of current candidate in echo area."
  (if-let* ((delay (if (consp corfu-echo-delay)
                       (funcall (if corfu-echo--message #'cdr #'car)
                                corfu-echo-delay)
                     corfu-echo-delay))
            (fun (plist-get corfu--extra :company-docsig))
            (cand (and (>= corfu--index 0)
                       (nth corfu--index corfu--candidates))))
      (if (or (eq delay t) (<= delay 0))
          (corfu-echo--show (funcall fun cand))
        (corfu-echo--cancel)
        (setq corfu-echo--timer
              (run-at-time delay nil
                           (lambda ()
                             (corfu-echo--show (funcall fun cand))))))
    (corfu-echo--cancel)))

;;;###autoload
(define-minor-mode corfu-echo-mode
  "Show candidate documentation in echo area."
  :global t :group 'corfu
  (cond
   (corfu-echo-mode
    (advice-add #'corfu--pre-command :before #'corfu-echo--refresh)
    (advice-add #'corfu--exhibit :after #'corfu-echo--exhibit)
    (advice-add #'corfu--teardown :before #'corfu-echo--cancel))
   (t
    (advice-remove #'corfu--pre-command #'corfu-echo--refresh)
    (advice-remove #'corfu--exhibit #'corfu-echo--exhibit)
    (advice-remove #'corfu--teardown #'corfu-echo--cancel))))

(provide 'corfu-echo)
;;; corfu-echo.el ends here