Avoiding autodoc interfering with an active minibuffer
[geiser.git] / elisp / geiser-autodoc.el
blob1befb74aa59b299b438d56293eb11e77496afd30
1 ;; geiser-autodoc.el -- autodoc mode
3 ;; Copyright (C) 2009, 2010 Jose Antonio Ortega Ruiz
5 ;; This program is free software; you can redistribute it and/or
6 ;; modify it under the terms of the Modified BSD License. You should
7 ;; have received a copy of the license along with this program. If
8 ;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>.
10 ;; Start date: Sun Feb 08, 2009 19:44
14 (require 'geiser-eval)
15 (require 'geiser-syntax)
16 (require 'geiser-custom)
17 (require 'geiser-base)
19 (require 'eldoc)
22 ;;; Customization:
24 (defgroup geiser-autodoc nil
25 "Options for displaying autodoc strings in the echo area."
26 :group 'geiser)
28 (geiser-custom--defface autodoc-current-arg
29 'bold geiser-autodoc "highlighting current argument in autodoc messages")
31 (geiser-custom--defface autodoc-identifier
32 'font-lock-function-name-face
33 geiser-autodoc "highlighting procedure name in autodoc messages")
35 (geiser-custom--defcustom geiser-autodoc-delay 0.3
36 "Delay before autodoc messages are fetched and displayed, in seconds."
37 :type 'number
38 :group 'geiser-autodoc)
40 (geiser-custom--defcustom geiser-autodoc-display-module-p t
41 "Whether to display procedure module in autodoc strings."
42 :type 'boolean
43 :group 'geiser-autodoc)
45 (geiser-custom--defcustom geiser-autodoc-identifier-format "%s:%s"
46 "Format for displaying module and procedure or variable name, in that order,
47 when `geiser-autodoc-display-module-p' is on."
48 :type 'string
49 :group 'geiser-autodoc)
52 ;;; Procedure arguments:
54 (make-variable-buffer-local
55 (defvar geiser-autodoc--cached-signatures nil))
57 (defsubst geiser-autodoc--clean-cache ()
58 (setq geiser-autodoc--cached-signatures nil))
60 (defun geiser-autodoc--save-signatures (ret)
61 (let ((res (geiser-eval--retort-result ret)))
62 (when res
63 (dolist (item res)
64 (push (cons (format "%s" (car item)) (cdr item))
65 geiser-autodoc--cached-signatures))
66 (let ((str (geiser-autodoc--autodoc (geiser-syntax--scan-sexps)
67 geiser-autodoc--cached-signatures)))
68 (when str (eldoc-message str))))))
70 (defun geiser-autodoc--get-signatures (funs)
71 (when funs
72 (let ((missing) (cached))
73 (if (not geiser-autodoc--cached-signatures)
74 (setq missing funs)
75 (dolist (f funs)
76 (let ((cf (assoc f geiser-autodoc--cached-signatures)))
77 (if cf (push cf cached) (push f missing)))))
78 (when missing
79 (let ((m (format "'(%s)" (mapconcat 'identity missing " "))))
80 (geiser-eval--send `(:eval (:ge autodoc (:scm ,m)))
81 'geiser-autodoc--save-signatures)))
82 cached)))
84 (defun geiser-autodoc--sanitize-args (args)
85 (cond ((null args) nil)
86 ((listp args)
87 (cons (car args) (geiser-autodoc--sanitize-args (cdr args))))
88 (t '("..."))))
90 (defun geiser-autodoc--format-arg (a)
91 (cond ((and (listp a) (geiser-syntax--keywordp (car a)))
92 (if (and (cdr a) (listp (cdr a)))
93 (format "(#%s %s)" (car a) (geiser-syntax--display (cadr a)))
94 (format "(#%s)" (car a))))
95 (t (geiser-syntax--display a))))
97 (defun geiser-autodoc--insert-arg-group (args current &optional pos)
98 (when args (insert " "))
99 (dolist (a (geiser-autodoc--sanitize-args args))
100 (let ((p (point)))
101 (insert (geiser-autodoc--format-arg a))
102 (when (or (and (numberp pos)
103 (numberp current)
104 (setq current (1+ current))
105 (= (1+ pos) current))
106 (and (geiser-syntax--keywordp current)
107 (listp a)
108 (geiser-syntax--symbol-eq current (car a))))
109 (put-text-property p (point)
110 'face 'geiser-font-lock-autodoc-current-arg)
111 (setq pos nil current nil)))
112 (insert " "))
113 (when args (backward-char))
114 current)
116 (defun geiser-autodoc--insert-args (args pos prev)
117 (let ((cpos 1)
118 (reqs (cdr (assoc "required" args)))
119 (opts (mapcar (lambda (a)
120 (if (and (symbolp a)
121 (not (equal (symbol-name a) "...")))
122 (list a)
124 (cdr (assoc "optional" args))))
125 (keys (cdr (assoc "key" args))))
126 (setq cpos
127 (geiser-autodoc--insert-arg-group reqs
128 cpos
129 (and (not (zerop pos)) pos)))
130 (setq cpos (geiser-autodoc--insert-arg-group opts cpos pos))
131 (geiser-autodoc--insert-arg-group keys prev nil)))
133 (defsubst geiser-autodoc--id-name (proc module)
134 (let ((str (if module
135 (format geiser-autodoc-identifier-format module proc)
136 (format "%s" proc))))
137 (propertize str 'face 'geiser-font-lock-autodoc-identifier)))
139 (defun geiser-autodoc--str* (full-signature)
140 (let ((geiser-font-lock-autodoc-current-arg 'default))
141 (geiser-autodoc--str (list (car full-signature)) full-signature)))
143 (defsubst geiser-autodoc--value-str (proc module value)
144 (let ((name (geiser-autodoc--id-name proc module)))
145 (if value (format "%s => %s" name value) name)))
147 (defun geiser-autodoc--str (desc signature)
148 (let ((proc (car desc))
149 (args (cdr (assoc "args" signature)))
150 (module (cdr (assoc "module" signature))))
151 (if (not args)
152 (geiser-autodoc--value-str proc module (cdr (assoc "value" signature)))
153 (save-current-buffer
154 (set-buffer (geiser-syntax--font-lock-buffer))
155 (erase-buffer)
156 (insert (format "(%s" (geiser-autodoc--id-name proc module)))
157 (let ((pos (or (cadr desc) 0))
158 (prev (car (cddr desc))))
159 (dolist (a args)
160 (when (not (member a (cdr (member a args))))
161 (geiser-autodoc--insert-args a pos prev)
162 (insert " |"))))
163 (delete-char -2)
164 (insert ")")
165 (buffer-substring (point-min) (point))))))
167 (defun geiser-autodoc--autodoc (path &optional signs)
168 (let ((signs (or signs (geiser-autodoc--get-signatures (mapcar 'car path))))
169 (p (car path))
170 (s))
171 (while (and p (not s))
172 (unless (setq s (cdr (assoc (car p) signs)))
173 (setq p (car path))
174 (setq path (cdr path))))
175 (when s (geiser-autodoc--str p s))))
178 ;;; Autodoc function:
180 (make-variable-buffer-local
181 (defvar geiser-autodoc--inhibit-function nil))
183 (defsubst geiser-autodoc--inhibit ()
184 (and geiser-autodoc--inhibit-function
185 (funcall geiser-autodoc--inhibit-function)))
187 (defun geiser-autodoc--eldoc-function ()
188 (condition-case e
189 (and (not (geiser-autodoc--inhibit))
190 (geiser-autodoc--autodoc (geiser-syntax--scan-sexps)))
191 (error (format "Autodoc not available (%s)" (error-message-string e)))))
194 ;;; Autodoc mode:
196 (make-variable-buffer-local
197 (defvar geiser-autodoc-mode-string " A"
198 "Modeline indicator for geiser-autodoc-mode"))
200 (define-minor-mode geiser-autodoc-mode
201 "Toggle Geiser's Autodoc mode.
202 With no argument, this command toggles the mode.
203 Non-null prefix argument turns on the mode.
204 Null prefix argument turns off the mode.
206 When Autodoc mode is enabled, a synopsis of the word at point is
207 displayed in the minibuffer."
208 :init-value nil
209 :lighter geiser-autodoc-mode-string
210 :group 'geiser-autodoc
212 (set (make-local-variable 'eldoc-documentation-function)
213 (when geiser-autodoc-mode 'geiser-autodoc--eldoc-function))
214 (set (make-local-variable 'eldoc-minor-mode-string) nil)
215 (set (make-local-variable 'eldoc-idle-delay) geiser-autodoc-delay)
216 (eldoc-mode geiser-autodoc-mode)
217 (message "Geiser Autodoc %s" (if geiser-autodoc-mode "enabled" "disabled")))
219 (defadvice eldoc-display-message-no-interference-p
220 (after geiser-autodoc--message-ok-p)
221 (when geiser-autodoc-mode
222 (setq ad-return-value
223 (and ad-return-value
224 ;; Display arglist only when the minibuffer is
225 ;; inactive, e.g. not on `C-x C-f'. Lifted from slime.
226 (not (active-minibuffer-window)))))
227 ad-return-value)
231 (provide 'geiser-autodoc)
232 ;;; geiser-autodoc.el ends here