geiser-racket moved to individual package
[geiser.git] / elisp / geiser-autodoc.el
blob0eea73e138cb5435fd23b473b2a5c5a1663259e1
1 ;;; geiser-autodoc.el -- autodoc mode
3 ;; Copyright (C) 2009, 2010, 2011, 2012, 2015, 2016 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
13 ;;; Code:
15 (require 'geiser-eval)
16 (require 'geiser-syntax)
17 (require 'geiser-custom)
18 (require 'geiser-base)
20 (require 'eldoc)
23 ;;; Customization:
25 (defgroup geiser-autodoc nil
26 "Options for displaying autodoc strings in the echo area."
27 :group 'geiser)
29 (geiser-custom--defface autodoc-current-arg
30 'font-lock-variable-name-face
31 geiser-autodoc "highlighting current argument in autodoc messages")
33 (geiser-custom--defface autodoc-identifier
34 'font-lock-function-name-face
35 geiser-autodoc "highlighting procedure name in autodoc messages")
37 (geiser-custom--defcustom geiser-autodoc-delay 0.3
38 "Delay before autodoc messages are fetched and displayed, in seconds."
39 :type 'number
40 :group 'geiser-autodoc)
42 (geiser-custom--defcustom geiser-autodoc-display-module-p t
43 "Whether to display procedure module in autodoc strings."
44 :type 'boolean
45 :group 'geiser-autodoc)
47 (geiser-custom--defcustom geiser-autodoc-identifier-format "%s:%s"
48 "Format for displaying module and procedure or variable name, in that order,
49 when `geiser-autodoc-display-module-p' is on."
50 :type 'string
51 :group 'geiser-autodoc)
54 ;;; Procedure arguments:
56 (make-variable-buffer-local
57 (defvar geiser-autodoc--cached-signatures nil))
59 (defsubst geiser-autodoc--clean-cache ()
60 (setq geiser-autodoc--cached-signatures nil))
62 (defun geiser-autodoc--show-signatures (ret)
63 (let ((res (geiser-eval--retort-result ret))
64 (signs))
65 (when res
66 (dolist (item res)
67 (push (cons (format "%s" (car item)) (cdr item)) signs))
68 (let ((str (geiser-autodoc--autodoc (geiser-syntax--scan-sexps) signs)))
69 (when (not (string-equal str eldoc-last-message))
70 (eldoc-message str)))
71 (setq geiser-autodoc--cached-signatures signs))))
73 (defun geiser-autodoc--get-signatures (funs)
74 (when funs
75 (let ((m (format "'(%s)" (mapconcat 'identity funs " "))))
76 (geiser-eval--send `(:eval (:ge autodoc (:scm ,m)))
77 'geiser-autodoc--show-signatures)))
78 (and (or (assoc (car funs) geiser-autodoc--cached-signatures)
79 (assoc (cadr funs) geiser-autodoc--cached-signatures))
80 geiser-autodoc--cached-signatures))
82 (defun geiser-autodoc--sanitize-args (args)
83 (cond ((null args) nil)
84 ((listp args)
85 (cons (car args) (geiser-autodoc--sanitize-args (cdr args))))
86 (t '("..."))))
88 (defun geiser-autodoc--format-arg (a)
89 (cond ((and (listp a) (geiser-syntax--keywordp (car a)))
90 (if (and (cdr a) (listp (cdr a)))
91 (format "(#%s %s)" (car a) (geiser-syntax--display (cadr a)))
92 (format "(#%s)" (car a))))
93 (t (geiser-syntax--display a))))
95 (defun geiser-autodoc--insert-arg-group (args current &optional pos)
96 (when args (insert " "))
97 (dolist (a (geiser-autodoc--sanitize-args args))
98 (let ((p (point)))
99 (insert (geiser-autodoc--format-arg a))
100 (when (or (and (numberp pos)
101 (numberp current)
102 (setq current (1+ current))
103 (= (1+ pos) current))
104 (and (geiser-syntax--keywordp current)
105 (listp a)
106 (geiser-syntax--symbol-eq current (car a))))
107 (put-text-property p (point)
108 'face 'geiser-font-lock-autodoc-current-arg)
109 (setq pos nil current nil)))
110 (insert " "))
111 (when args (backward-char))
112 current)
114 (defun geiser-autodoc--insert-args (args pos prev)
115 (let ((cpos 1)
116 (reqs (cdr (assoc "required" args)))
117 (opts (mapcar (lambda (a)
118 (if (and (symbolp a)
119 (not (equal (symbol-name a) "...")))
120 (list a)
122 (cdr (assoc "optional" args))))
123 (keys (cdr (assoc "key" args))))
124 (setq cpos
125 (geiser-autodoc--insert-arg-group reqs
126 cpos
127 (and (not (zerop pos)) pos)))
128 (setq cpos (geiser-autodoc--insert-arg-group opts cpos pos))
129 (geiser-autodoc--insert-arg-group keys prev nil)))
131 (defsubst geiser-autodoc--id-name (proc module)
132 (let ((str (if module
133 (format geiser-autodoc-identifier-format module proc)
134 (format "%s" proc))))
135 (propertize str 'face 'geiser-font-lock-autodoc-identifier)))
137 (defun geiser-autodoc--str* (full-signature)
138 (let ((geiser-font-lock-autodoc-current-arg 'default))
139 (geiser-autodoc--str (list (car full-signature)) full-signature)))
141 (defsubst geiser-autodoc--value-str (proc module value)
142 (let ((name (geiser-autodoc--id-name proc module)))
143 (if value (format "%s => %s" name value) name)))
145 (defun geiser-autodoc--str (desc signature)
146 (let ((proc (car desc))
147 (args (cdr (assoc "args" signature)))
148 (module (cdr (assoc "module" signature))))
149 (if (not args)
150 (geiser-autodoc--value-str proc module (cdr (assoc "value" signature)))
151 (save-current-buffer
152 (set-buffer (geiser-syntax--font-lock-buffer))
153 (erase-buffer)
154 (insert (format "(%s" (geiser-autodoc--id-name proc module)))
155 (let ((pos (or (cadr desc) 0))
156 (prev (car (cddr desc))))
157 (dolist (a args)
158 (when (not (member a (cdr (member a args))))
159 (geiser-autodoc--insert-args a pos prev)
160 (insert " |"))))
161 (delete-char -2)
162 (insert ")")
163 (buffer-substring (point-min) (point))))))
165 (defun geiser-autodoc--autodoc (path &optional signs)
166 (let ((signs (or signs (geiser-autodoc--get-signatures (mapcar 'car path))))
167 (p (car path))
168 (s))
169 (while (and p (not s))
170 (unless (setq s (cdr (assoc (car p) signs)))
171 (setq p (car path))
172 (setq path (cdr path))))
173 (when s (geiser-autodoc--str p s))))
176 ;;; Autodoc functions:
178 (make-variable-buffer-local
179 (defvar geiser-autodoc--inhibit-function nil))
181 (defsubst geiser-autodoc--inhibit ()
182 (and geiser-autodoc--inhibit-function
183 (funcall geiser-autodoc--inhibit-function)))
185 (defsubst geiser-autodoc--inhibit-autodoc ()
186 (setq geiser-autodoc--inhibit-function (lambda () t)))
188 (defsubst geiser-autodoc--disinhibit-autodoc ()
189 (setq geiser-autodoc--inhibit-function nil))
191 (defsubst geiser-autodoc--autodoc-at-point ()
192 (geiser-autodoc--autodoc (geiser-syntax--scan-sexps)))
194 (defun geiser-autodoc--eldoc-function ()
195 (ignore-errors
196 (when (not (geiser-autodoc--inhibit))
197 (geiser-autodoc--autodoc-at-point))))
199 (defun geiser-autodoc-show ()
200 "Show the signature or value of the symbol at point in the echo area."
201 (interactive)
202 (message (geiser-autodoc--autodoc-at-point)))
205 ;;; Autodoc mode:
207 (make-variable-buffer-local
208 (defvar geiser-autodoc-mode-string " A"
209 "Modeline indicator for geiser-autodoc-mode"))
211 (define-minor-mode geiser-autodoc-mode
212 "Toggle Geiser's Autodoc mode.
213 With no argument, this command toggles the mode.
214 Non-null prefix argument turns on the mode.
215 Null prefix argument turns off the mode.
217 When Autodoc mode is enabled, a synopsis of the word at point is
218 displayed in the minibuffer."
219 :init-value nil
220 :lighter geiser-autodoc-mode-string
221 :group 'geiser-autodoc
223 (set (make-local-variable 'eldoc-documentation-function)
224 (when geiser-autodoc-mode 'geiser-autodoc--eldoc-function))
225 (set (make-local-variable 'eldoc-minor-mode-string) nil)
226 (set (make-local-variable 'eldoc-idle-delay) geiser-autodoc-delay)
227 (eldoc-mode (if geiser-autodoc-mode 1 -1))
228 (when (called-interactively-p nil)
229 (message "Geiser Autodoc %s"
230 (if geiser-autodoc-mode "enabled" "disabled"))))
232 (defadvice eldoc-display-message-no-interference-p
233 (after geiser-autodoc--message-ok-p)
234 (when geiser-autodoc-mode
235 (setq ad-return-value
236 (and ad-return-value
237 ;; Display arglist only when the minibuffer is
238 ;; inactive, e.g. not on `C-x C-f'. Lifted from slime.
239 (not (active-minibuffer-window)))))
240 ad-return-value)
244 (provide 'geiser-autodoc)