Commit | Line | Data |
---|---|---|
9e031c31 | 1 | ;;; semantic/ia.el --- Interactive Analysis functions |
f273dfc6 | 2 | |
73b0cd50 | 3 | ;;; Copyright (C) 2000-2011 Free Software Foundation, Inc. |
f273dfc6 CY |
4 | |
5 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
6 | ;; Keywords: syntax | |
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 | ;; Interactive access to `semantic-analyze'. | |
26 | ;; | |
27 | ;; These routines are fairly simple, and show how to use the Semantic | |
28 | ;; analyzer to provide things such as completion lists, summaries, | |
29 | ;; locations, or documentation. | |
30 | ;; | |
31 | ||
32 | ;;; TODO | |
33 | ;; | |
34 | ;; fast-jump. For a virtual method, offer some of the possible | |
35 | ;; implementations in various sub-classes. | |
36 | ||
f273dfc6 | 37 | (require 'semantic/analyze) |
996bc9bf | 38 | (require 'semantic/format) |
f273dfc6 CY |
39 | (require 'pulse) |
40 | (eval-when-compile | |
41 | (require 'semantic/analyze) | |
dd9af436 CY |
42 | (require 'semantic/analyze/refs) |
43 | (require 'semantic/find)) | |
f273dfc6 | 44 | |
3d9d8486 CY |
45 | (declare-function imenu--mouse-menu "imenu") |
46 | ||
f273dfc6 CY |
47 | ;;; Code: |
48 | ||
49 | ;;; COMPLETION | |
50 | ;; | |
51 | ;; This set of routines provides some simplisting completion | |
52 | ;; functions. | |
53 | ||
54 | (defcustom semantic-ia-completion-format-tag-function | |
e96ec425 CY |
55 | 'semantic-format-tag-prototype |
56 | "Function used to convert a tag to a string during completion." | |
f273dfc6 CY |
57 | :group 'semantic |
58 | :type semantic-format-tag-custom-list) | |
59 | ||
3d9d8486 CY |
60 | ;;; COMPLETION HELPER |
61 | ;; | |
62 | ;; This overload function handles inserting a tag | |
63 | ;; into a buffer for these local completion routines. | |
64 | ;; | |
65 | ;; By creating the functions as overloadable, it can be | |
66 | ;; customized. For example, the default will put a paren "(" | |
67 | ;; character after function names. For Lisp, it might check | |
68 | ;; to put a "(" in front of a function name. | |
69 | ||
70 | (define-overloadable-function semantic-ia-insert-tag (tag) | |
71 | "Insert TAG into the current buffer based on completion.") | |
72 | ||
73 | (defun semantic-ia-insert-tag-default (tag) | |
74 | "Insert TAG into the current buffer based on completion." | |
75 | (insert (semantic-tag-name tag)) | |
76 | (let ((tt (semantic-tag-class tag))) | |
77 | (cond ((eq tt 'function) | |
78 | (insert "(")) | |
79 | (t nil)))) | |
80 | ||
dd9af436 CY |
81 | (defalias 'semantic-ia-get-completions 'semantic-ia-get-completions-deprecated |
82 | "`Semantic-ia-get-completions' is obsolete. | |
83 | Use `semantic-analyze-possible-completions' instead.") | |
84 | ||
85 | (defun semantic-ia-get-completions-deprecated (context point) | |
86 | "A function to help transition away from `semantic-ia-get-completions'. | |
87 | Return completions based on CONTEXT at POINT. | |
88 | You should not use this, nor the aliased version. | |
89 | Use `semantic-analyze-possible-completions' instead." | |
90 | (semantic-analyze-possible-completions context)) | |
f273dfc6 | 91 | |
9e031c31 | 92 | ;;;###autoload |
9a594ee6 CY |
93 | (defun semantic-ia-complete-symbol (&optional pos) |
94 | "Complete the current symbol at POS. | |
95 | If POS is nil, default to point. | |
f273dfc6 CY |
96 | Completion options are calculated with `semantic-analyze-possible-completions'." |
97 | (interactive "d") | |
dd9af436 CY |
98 | (when (semantic-active-p) |
99 | (or pos (setq pos (point))) | |
100 | ;; Calculating completions is a two step process. | |
101 | ;; | |
102 | ;; The first analyzer the current context, which finds tags for | |
103 | ;; all the stuff that may be references by the code around POS. | |
104 | ;; | |
105 | ;; The second step derives completions from that context. | |
106 | (let* ((a (semantic-analyze-current-context pos)) | |
107 | (syms (semantic-analyze-possible-completions a)) | |
108 | (pre (car (reverse (oref a prefix))))) | |
109 | ;; If PRE was actually an already completed symbol, it doesn't | |
110 | ;; come in as a string, but as a tag instead. | |
111 | (if (semantic-tag-p pre) | |
112 | ;; We will try completions on it anyway. | |
113 | (setq pre (semantic-tag-name pre))) | |
114 | ;; Complete this symbol. | |
115 | (if (null syms) | |
f273dfc6 CY |
116 | (if (semantic-analyze-context-p a) |
117 | ;; This is a clever hack. If we were unable to find any | |
c7015153 | 118 | ;; smart completions, let's divert to how senator derives |
f273dfc6 CY |
119 | ;; completions. |
120 | ;; | |
dd9af436 | 121 | ;; This is a way of making this fcn more useful since |
c5e87d10 | 122 | ;; the smart completion engine sometimes fails. |
dd9af436 CY |
123 | (semantic-complete-symbol)) |
124 | ;; Use try completion to seek a common substring. | |
125 | (let ((tc (try-completion (or pre "") syms))) | |
126 | (if (and (stringp tc) (not (string= tc (or pre "")))) | |
127 | (let ((tok (semantic-find-first-tag-by-name | |
128 | tc syms))) | |
129 | ;; Delete what came before... | |
130 | (when (and (car (oref a bounds)) (cdr (oref a bounds))) | |
131 | (delete-region (car (oref a bounds)) | |
132 | (cdr (oref a bounds))) | |
133 | (goto-char (car (oref a bounds)))) | |
134 | ;; We have some new text. Stick it in. | |
135 | (if tok | |
136 | (semantic-ia-insert-tag tok) | |
137 | (insert tc))) | |
138 | ;; We don't have new text. Show all completions. | |
139 | (when (cdr (oref a bounds)) | |
140 | (goto-char (cdr (oref a bounds)))) | |
141 | (with-output-to-temp-buffer "*Completions*" | |
142 | (display-completion-list | |
143 | (mapcar semantic-ia-completion-format-tag-function syms))))))))) | |
f273dfc6 CY |
144 | |
145 | (defcustom semantic-ia-completion-menu-format-tag-function | |
146 | 'semantic-uml-concise-prototype-nonterminal | |
147 | "*Function used to convert a tag to a string during completion." | |
148 | :group 'semantic | |
149 | :type semantic-format-tag-custom-list) | |
150 | ||
f273dfc6 CY |
151 | ;;; Completions Tip |
152 | ;; | |
153 | ;; This functions shows how to get the list of completions, | |
154 | ;; to place in a tooltip. It doesn't actually do any completion. | |
155 | ||
9e031c31 | 156 | ;;;###autoload |
f273dfc6 CY |
157 | (defun semantic-ia-complete-tip (point) |
158 | "Pop up a tooltip for completion at POINT." | |
159 | (interactive "d") | |
160 | (let* ((a (semantic-analyze-current-context point)) | |
dd9af436 | 161 | (syms (semantic-analyze-possible-completions a)) |
f273dfc6 CY |
162 | (x (mod (- (current-column) (window-hscroll)) |
163 | (window-width))) | |
164 | (y (save-excursion | |
165 | (save-restriction | |
166 | (widen) | |
167 | (narrow-to-region (window-start) (point)) | |
168 | (goto-char (point-min)) | |
169 | (1+ (vertical-motion (buffer-size)))))) | |
170 | (str (mapconcat #'semantic-tag-name | |
171 | syms | |
172 | "\n")) | |
173 | ) | |
174 | (cond ((fboundp 'x-show-tip) | |
175 | (x-show-tip str | |
176 | (selected-frame) | |
177 | nil | |
178 | nil | |
179 | x y) | |
180 | ) | |
181 | (t (message str)) | |
182 | ))) | |
183 | ||
184 | ;;; Summary | |
185 | ;; | |
186 | ;; Like idle-summary-mode, this shows how to get something to | |
187 | ;; show a summary on. | |
188 | ||
9e031c31 | 189 | ;;;###autoload |
f273dfc6 CY |
190 | (defun semantic-ia-show-summary (point) |
191 | "Display a summary for the symbol under POINT." | |
192 | (interactive "P") | |
193 | (let* ((ctxt (semantic-analyze-current-context point)) | |
194 | (pf (when ctxt | |
195 | ;; The CTXT is an EIEIO object. The below | |
196 | ;; method will attempt to pick the most interesting | |
197 | ;; tag associated with the current context. | |
198 | (semantic-analyze-interesting-tag ctxt))) | |
199 | ) | |
dd9af436 CY |
200 | (if pf |
201 | (message "%s" (semantic-format-tag-summarize pf nil t)) | |
91af3942 | 202 | (message "No summary info available")))) |
dd9af436 CY |
203 | |
204 | ;;; Variants | |
205 | ;; | |
206 | ;; Show all variants for the symbol under point. | |
207 | ||
208 | ;;;###autoload | |
209 | (defun semantic-ia-show-variants (point) | |
210 | "Display a list of all variants for the symbol under POINT." | |
211 | (interactive "P") | |
212 | (let* ((ctxt (semantic-analyze-current-context point)) | |
213 | (comp nil)) | |
214 | ||
215 | ;; We really want to look at the function if we are on an | |
216 | ;; argument. Are there some additional rules we care about for | |
217 | ;; changing the CTXT we look at? | |
218 | (when (semantic-analyze-context-functionarg-p ctxt) | |
219 | (goto-char (cdr (oref ctxt bounds))) | |
220 | (setq ctxt (semantic-analyze-current-context (point)))) | |
221 | ||
222 | ;; Get the "completion list", but remove ALL filters to get the master list | |
223 | ;; of all the possible things. | |
224 | (setq comp (semantic-analyze-possible-completions ctxt 'no-unique 'no-tc)) | |
225 | ||
226 | ;; Special case for a single type. List the constructors? | |
227 | (when (and (= (length comp) 1) (semantic-tag-of-class-p (car comp) 'type)) | |
228 | (setq comp (semantic-find-tags-by-name (semantic-tag-name (car comp)) | |
229 | (semantic-tag-type-members (car comp))))) | |
230 | ||
231 | ;; Display the results. | |
232 | (cond ((= (length comp) 0) | |
233 | (message "No Variants found.")) | |
234 | ((= (length comp) 1) | |
235 | (message "%s" (semantic-format-tag-summarize (car comp) nil t))) | |
236 | (t | |
237 | (with-output-to-temp-buffer "*Symbol Variants*" | |
238 | (semantic-analyze-princ-sequence comp "" (current-buffer))) | |
239 | (shrink-window-if-larger-than-buffer | |
240 | (get-buffer-window "*Symbol Variants*"))) | |
241 | ))) | |
f273dfc6 CY |
242 | |
243 | ;;; FAST Jump | |
244 | ;; | |
245 | ;; Jump to a destination based on the local context. | |
246 | ;; | |
247 | ;; This shows how to use the analyzer context, and the | |
91af3942 | 248 | ;; analyzer references objects to choose a good destination. |
f273dfc6 CY |
249 | |
250 | (defun semantic-ia--fast-jump-helper (dest) | |
251 | "Jump to DEST, a Semantic tag. | |
252 | This helper manages the mark, buffer switching, and pulsing." | |
253 | ;; We have a tag, but in C++, we usually get a prototype instead | |
c7015153 JB |
254 | ;; because of header files. Let's try to find the actual |
255 | ;; implementation instead. | |
f273dfc6 CY |
256 | (when (semantic-tag-prototype-p dest) |
257 | (let* ((refs (semantic-analyze-tag-references dest)) | |
258 | (impl (semantic-analyze-refs-impl refs t)) | |
259 | ) | |
260 | (when impl (setq dest (car impl))))) | |
261 | ||
262 | ;; Make sure we have a place to go... | |
263 | (if (not (and (or (semantic-tag-with-position-p dest) | |
264 | (semantic-tag-get-attribute dest :line)) | |
265 | (semantic-tag-file-name dest))) | |
266 | (error "Tag %s has no buffer information" | |
267 | (semantic-format-tag-name dest))) | |
268 | ||
269 | ;; Once we have the tag, we can jump to it. Here | |
270 | ;; are the key bits to the jump: | |
271 | ||
272 | ;; 1) Push the mark, so you can pop global mark back, or | |
273 | ;; use semantic-mru-bookmark mode to do so. | |
274 | (push-mark) | |
275 | (when (fboundp 'push-tag-mark) | |
276 | (push-tag-mark)) | |
277 | ;; 2) Visits the tag. | |
278 | (semantic-go-to-tag dest) | |
279 | ;; 3) go-to-tag doesn't switch the buffer in the current window, | |
280 | ;; so it is like find-file-noselect. Bring it forward. | |
281 | (switch-to-buffer (current-buffer)) | |
282 | ;; 4) Fancy pulsing. | |
283 | (pulse-momentary-highlight-one-line (point)) | |
284 | ) | |
285 | ||
3d9d8486 CY |
286 | (declare-function semantic-decoration-include-visit "semantic/decorate/include") |
287 | ||
9e031c31 | 288 | ;;;###autoload |
f273dfc6 CY |
289 | (defun semantic-ia-fast-jump (point) |
290 | "Jump to the tag referred to by the code at POINT. | |
291 | Uses `semantic-analyze-current-context' output to identify an accurate | |
292 | origin of the code at point." | |
293 | (interactive "d") | |
294 | (let* ((ctxt (semantic-analyze-current-context point)) | |
295 | (pf (and ctxt (reverse (oref ctxt prefix)))) | |
296 | ;; In the analyzer context, the PREFIX is the list of items | |
297 | ;; that makes up the code context at point. Thus the c++ code | |
298 | ;; this.that().theothe | |
299 | ;; would make a list: | |
300 | ;; ( ("this" variable ..) ("that" function ...) "theothe") | |
301 | ;; Where the first two elements are the semantic tags of the prefix. | |
302 | ;; | |
303 | ;; PF is the reverse of this list. If the first item is a string, | |
304 | ;; then it is an incomplete symbol, thus we pick the second. | |
305 | ;; The second cannot be a string, as that would have been an error. | |
306 | (first (car pf)) | |
307 | (second (nth 1 pf)) | |
308 | ) | |
309 | (cond | |
310 | ((semantic-tag-p first) | |
311 | ;; We have a match. Just go there. | |
312 | (semantic-ia--fast-jump-helper first)) | |
313 | ||
314 | ((semantic-tag-p second) | |
315 | ;; Because FIRST failed, we should visit our second tag. | |
316 | ;; HOWEVER, the tag we actually want that was only an unfound | |
317 | ;; string may be related to some take in the datatype that belongs | |
318 | ;; to SECOND. Thus, instead of visiting second directly, we | |
319 | ;; can offer to find the type of SECOND, and go there. | |
320 | (let ((secondclass (car (reverse (oref ctxt prefixtypes))))) | |
321 | (cond | |
322 | ((and (semantic-tag-with-position-p secondclass) | |
323 | (y-or-n-p (format "Could not find `%s'. Jump to %s? " | |
324 | first (semantic-tag-name secondclass)))) | |
325 | (semantic-ia--fast-jump-helper secondclass) | |
326 | ) | |
327 | ;; If we missed out on the class of the second item, then | |
328 | ;; just visit SECOND. | |
329 | ((and (semantic-tag-p second) | |
330 | (y-or-n-p (format "Could not find `%s'. Jump to %s? " | |
331 | first (semantic-tag-name second)))) | |
332 | (semantic-ia--fast-jump-helper second) | |
333 | )))) | |
334 | ||
335 | ((semantic-tag-of-class-p (semantic-current-tag) 'include) | |
336 | ;; Just borrow this cool fcn. | |
3d9d8486 | 337 | (require 'semantic/decorate/include) |
f273dfc6 CY |
338 | (semantic-decoration-include-visit) |
339 | ) | |
340 | ||
341 | (t | |
342 | (error "Could not find suitable jump point for %s" | |
343 | first)) | |
344 | ))) | |
345 | ||
9e031c31 | 346 | ;;;###autoload |
f273dfc6 CY |
347 | (defun semantic-ia-fast-mouse-jump (evt) |
348 | "Jump to the tag referred to by the point clicked on. | |
349 | See `semantic-ia-fast-jump' for details on how it works. | |
350 | This command is meant to be bound to a mouse event." | |
351 | (interactive "e") | |
352 | (semantic-ia-fast-jump | |
353 | (save-excursion | |
354 | (posn-set-point (event-end evt)) | |
355 | (point)))) | |
356 | ||
357 | ;;; DOC/DESCRIBE | |
358 | ;; | |
359 | ;; These routines show how to get additional information about a tag | |
360 | ;; for purposes of describing or showing documentation about them. | |
9e031c31 | 361 | ;;;###autoload |
f273dfc6 CY |
362 | (defun semantic-ia-show-doc (point) |
363 | "Display the code-level documentation for the symbol at POINT." | |
364 | (interactive "d") | |
365 | (let* ((ctxt (semantic-analyze-current-context point)) | |
366 | (pf (reverse (oref ctxt prefix))) | |
367 | ) | |
368 | ;; If PF, the prefix is non-nil, then the last element is either | |
369 | ;; a string (incomplete type), or a semantic TAG. If it is a TAG | |
370 | ;; then we should be able to find DOC for it. | |
371 | (cond | |
372 | ((stringp (car pf)) | |
373 | (message "Incomplete symbol name.")) | |
374 | ((semantic-tag-p (car pf)) | |
375 | ;; The `semantic-documentation-for-tag' fcn is language | |
376 | ;; specific. If it doesn't return what you expect, you may | |
377 | ;; need to implement something for your language. | |
378 | ;; | |
379 | ;; The default tries to find a comment in front of the tag | |
380 | ;; and then strings off comment prefixes. | |
381 | (let ((doc (semantic-documentation-for-tag (car pf)))) | |
dd9af436 CY |
382 | (if (or (null doc) (string= doc "")) |
383 | (message "Doc unavailable for: %s" | |
384 | (semantic-format-tag-prototype (car pf))) | |
385 | (with-output-to-temp-buffer "*TAG DOCUMENTATION*" | |
386 | (princ "Tag: ") | |
387 | (princ (semantic-format-tag-prototype (car pf))) | |
388 | (princ "\n") | |
389 | (princ "\n") | |
390 | (princ "Snarfed Documentation: ") | |
391 | (princ "\n") | |
392 | (princ "\n") | |
393 | (if doc | |
394 | (princ doc) | |
395 | (princ " Documentation unavailable.")) | |
396 | )))) | |
f273dfc6 CY |
397 | (t |
398 | (message "Unknown tag."))) | |
399 | )) | |
400 | ||
9e031c31 | 401 | ;;;###autoload |
f273dfc6 CY |
402 | (defun semantic-ia-describe-class (typename) |
403 | "Display all known parts for the datatype TYPENAME. | |
404 | If the type in question is a class, all methods and other accessible | |
405 | parts of the parent classes are displayed." | |
406 | ;; @todo - use a fancy completing reader. | |
407 | (interactive "sType Name: ") | |
408 | ||
409 | ;; When looking for a tag of any name there are a couple ways to do | |
410 | ;; it. The simple `semanticdb-find-tag-by-...' are simple, and | |
411 | ;; you need to pass it the exact name you want. | |
412 | ;; | |
413 | ;; The analyzer function `semantic-analyze-tag-name' will take | |
414 | ;; more complex names, such as the cpp symbol foo::bar::baz, | |
415 | ;; and break it up, and dive through the namespaces. | |
416 | (let ((class (semantic-analyze-find-tag typename))) | |
417 | ||
418 | (when (not (semantic-tag-p class)) | |
419 | (error "Cannot find class %s" class)) | |
420 | (with-output-to-temp-buffer "*TAG DOCUMENTATION*" | |
421 | ;; There are many semantic-format-tag-* fcns. | |
422 | ;; The summarize routine is a fairly generic one. | |
423 | (princ (semantic-format-tag-summarize class)) | |
424 | (princ "\n") | |
425 | (princ " Type Members:\n") | |
426 | ;; The type tag contains all the parts of the type. | |
427 | ;; In complex languages with inheritance, not all the | |
428 | ;; parts are in the tag. This analyzer fcn will traverse | |
429 | ;; the inheritance tree, and find all the pieces that | |
430 | ;; are inherited. | |
431 | (let ((parts (semantic-analyze-scoped-type-parts class))) | |
432 | (while parts | |
433 | (princ " ") | |
434 | (princ (semantic-format-tag-summarize (car parts))) | |
435 | (princ "\n") | |
436 | (setq parts (cdr parts))) | |
437 | ) | |
438 | ))) | |
439 | ||
440 | (provide 'semantic/ia) | |
441 | ||
9e031c31 CY |
442 | ;; Local variables: |
443 | ;; generated-autoload-file: "loaddefs.el" | |
9e031c31 CY |
444 | ;; generated-autoload-load-name: "semantic/ia" |
445 | ;; End: | |
446 | ||
447 | ;;; semantic/ia.el ends here |