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