]> code.delx.au - gnu-emacs-elpa/blob - packages/eldoc-eval/eldoc-eval.el
Merge commit '0cda39255827f283e7578cd469ae42daad9556a2' from js2-mode
[gnu-emacs-elpa] / packages / eldoc-eval / eldoc-eval.el
1 ;;; eldoc-eval.el --- Enable eldoc support when minibuffer is in use.
2
3 ;; Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
4
5 ;; Author: Thierry Volpiatto <thierry.volpiatto@gmail.com>
6 ;; Version: 0.1
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24 ;;
25 ;; This package enables eldoc support when minibuffer is in use.
26 ;;
27 ;; Eldoc info is shown by default in mode-line,
28 ;; but you can have eldoc info somewhere else by setting
29 ;; `eldoc-in-minibuffer-show-fn' to another function (e.g `tooltip-show').
30 ;;
31 ;; By default with this package `M-:' will use `pp-eval-expression'
32 ;; instead of `eval-expression'; you can change that by setting
33 ;; `eldoc-eval-preferred-function'.
34 ;;
35 ;; It also provides a convenient macro to enable eldoc support
36 ;; in your own functions using minibuffer or in your defadvices,
37 ;; that is `with-eldoc-in-minibuffer'.
38 ;;
39 ;; Users of own minibuffer frame will have to set
40 ;; `eldoc-in-minibuffer-own-frame-p' to non-nil.
41 ;;
42 ;; You can turn On/Off eldoc support in minibuffer any time
43 ;; with `eldoc-in-minibuffer-mode'.
44 ;;
45 ;;; Install:
46 ;; Add to .emacs:
47 ;;
48 ;; (autoload 'eldoc-in-minibuffer-mode "eldoc-eval")
49 ;; (eldoc-in-minibuffer-mode 1)
50
51
52 ;;; Code:
53 (require 'eldoc)
54
55 ;;; Minibuffer support.
56 ;; Enable displaying eldoc info in something else
57 ;; Than minibuffer when this one is in use.
58 ;;
59 (defgroup eldoc-eval nil
60 "Show eldoc infos in mode line while minibuffer is in use."
61 :group 'eldoc)
62
63 (defcustom eldoc-in-minibuffer-show-fn 'eldoc-show-in-mode-line
64 "A function to display eldoc info.
65 Should take one arg: the string to display"
66 :type 'function)
67
68 (defcustom eldoc-show-in-mode-line-delay 12
69 "The time we show eldoc when Emacs is idle."
70 :type 'number)
71
72 (defcustom eldoc-eval-preferred-function 'pp-eval-expression
73 "Preferred function to use with `M-:'."
74 :type 'function)
75
76 (defcustom eldoc-in-minibuffer-own-frame-p nil
77 "Whether minibuffer has its own frame or not."
78 :type 'boolean)
79
80 ;;; Compatibility with Emacs-24.4
81 ;; New implementation of eldoc in minibuffer that come
82 ;; with Emacs-24.4 show the eldoc info of current-buffer while
83 ;; minibuffer is in use, disable this and inline old Emacs behavior.
84 ;;
85 (defconst eldoc-eval--old-message-function
86 (and (boundp 'eldoc-message-function) eldoc-message-function))
87
88 (defadvice eldoc-display-message-no-interference-p
89 (after eldoc-eval activate)
90 (when eldoc-in-minibuffer-mode
91 (setq ad-return-value
92 (and ad-return-value
93 ;; Having this mode operate in an active minibuffer/echo area
94 ;; causes interference with what's going on there.
95 (not cursor-in-echo-area)
96 (not (eq (selected-window) (minibuffer-window)))))))
97
98 ;; Internal.
99 (defvar eldoc-active-minibuffers-list nil
100 "List of active minibuffers with eldoc enabled.")
101 (defvar eldoc-mode-line-rolling-flag nil)
102
103 (defun eldoc-store-minibuffer ()
104 "Store minibuffer buffer name in `eldoc-active-minibuffers-list'.
105 This function is called by each minibuffer started with eldoc support.
106 See `with-eldoc-in-minibuffer'."
107 (with-selected-window (minibuffer-window)
108 (push (current-buffer) eldoc-active-minibuffers-list)))
109
110 (defmacro with-eldoc-in-minibuffer (&rest body)
111 "Enable eldoc support for minibuffer input that runs in BODY."
112 (declare (indent 0) (debug t))
113 `(let ((timer (and eldoc-in-minibuffer-mode
114 (run-with-idle-timer
115 eldoc-idle-delay
116 'repeat #'eldoc-run-in-minibuffer))))
117 (unwind-protect
118 (minibuffer-with-setup-hook
119 ;; When minibuffer is activated in body, store it.
120 #'eldoc-store-minibuffer
121 ,@body)
122 (and timer (cancel-timer timer))
123 ;; Each time a minibuffer exits or aborts
124 ;; its buffer is removed from stack,
125 ;; assuming we can only exit the active minibuffer
126 ;; on top of stack.
127 (setq eldoc-active-minibuffers-list
128 (cdr eldoc-active-minibuffers-list)))))
129
130 (defun eldoc-current-buffer ()
131 "Return the current buffer prior to activating the minibuffer."
132 (with-selected-frame (last-nonminibuffer-frame)
133 (window-buffer
134 (cond (eldoc-in-minibuffer-own-frame-p
135 (selected-window))
136 ((fboundp 'window-in-direction)
137 (window-in-direction
138 'above (minibuffer-window)))
139 (t (minibuffer-selected-window))))))
140
141 (defun eldoc-show-in-mode-line (str)
142 "Display string STR in the mode-line next to minibuffer."
143 (let (mode-line-in-non-selected-windows)
144 (with-current-buffer (eldoc-current-buffer)
145 (make-local-variable 'mode-line-format)
146 (let ((mode-line-format (concat " " str)))
147 (eldoc-maybe-roll-message-in-mode-line mode-line-format))
148 (force-mode-line-update))))
149
150 (defun eldoc-maybe-roll-message-in-mode-line (str)
151 (let* ((max (window-width (get-buffer-window (eldoc-current-buffer))))
152 (len (length str))
153 (tmp-str str))
154 (if (and (> len max) eldoc-mode-line-rolling-flag)
155 (while (sit-for 0.3)
156 (setq tmp-str (substring tmp-str 2)
157 mode-line-format (concat tmp-str " [<]" str))
158 (force-mode-line-update nil)
159 (when (< (length tmp-str) 2) (setq tmp-str str)))
160 (force-mode-line-update nil)
161 (sit-for eldoc-show-in-mode-line-delay))))
162
163 (defun eldoc-mode-line-toggle-rolling ()
164 (interactive)
165 (if (and eldoc-in-minibuffer-mode
166 (minibuffer-window-active-p (selected-window)))
167 (setq eldoc-mode-line-rolling-flag (not eldoc-mode-line-rolling-flag))
168 (error "No active minibuffer found")))
169
170 (defvar eldoc-in-minibuffer-mode-map
171 (let ((map (make-sparse-keymap)))
172 ;; FIXME: Should we use [remap eval-expression] instead?
173 (define-key map (kbd "M-:") 'eldoc-eval-expression)
174 map))
175
176 ;;;###autoload
177 (define-minor-mode eldoc-in-minibuffer-mode
178 "Show eldoc for current minibuffer input."
179 :global t
180 (if eldoc-in-minibuffer-mode
181 (progn
182 (add-hook 'minibuffer-exit-hook
183 (lambda ()
184 (setq eldoc-mode-line-rolling-flag nil)))
185 (and (boundp 'eldoc-message-function)
186 (setq eldoc-message-function 'message))
187 (define-key minibuffer-local-map (kbd "C-@")
188 'eldoc-mode-line-toggle-rolling)
189 (setq eldoc-minor-mode-string " Eldoc-eval"))
190 (setq eldoc-minor-mode-string " Eldoc")
191 (and (boundp 'eldoc-message-function)
192 (setq eldoc-message-function eldoc-eval--old-message-function))
193 (define-key minibuffer-local-map (kbd "C-@") 'set-mark-command)))
194
195 (defun eldoc-run-in-minibuffer ()
196 (let ((buf (window-buffer (active-minibuffer-window))))
197 ;; If this minibuffer have been started with
198 ;;`with-eldoc-in-minibuffer' give it eldoc support
199 ;; and update mode-line, otherwise do nothing.
200 (condition-case err
201 (when (member buf eldoc-active-minibuffers-list)
202 (with-current-buffer buf
203 (let* ((sym (save-excursion
204 (unless (looking-back ")\\|\"")
205 (forward-char -1))
206 (eldoc-current-symbol)))
207 (info-fn (eldoc-fnsym-in-current-sexp))
208 (doc (or (eldoc-get-var-docstring sym)
209 (eldoc-get-fnsym-args-string
210 (car info-fn) (cadr info-fn)))))
211 (when doc (funcall eldoc-in-minibuffer-show-fn doc)))))
212 (scan-error nil)
213 (beginning-of-buffer nil)
214 (error (message "Eldoc in minibuffer error: %S" err)))))
215
216 ;;;###autoload
217 (defun eldoc-eval-expression ()
218 "Eval expression with eldoc support in mode-line."
219 (interactive)
220 (with-eldoc-in-minibuffer
221 (call-interactively eldoc-eval-preferred-function)))
222
223
224 (provide 'eldoc-eval)
225 ;;; eldoc-eval.el ends here