Commit | Line | Data |
---|---|---|
55b522b2 | 1 | ;;; semantic/texi.el --- Semantic details for Texinfo files |
9573e58b | 2 | |
ab422c4d | 3 | ;; Copyright (C) 2001-2005, 2007-2013 Free Software Foundation, Inc. |
9573e58b CY |
4 | |
5 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
6 | ||
7 | ;; This file is part of GNU Emacs. | |
8 | ||
9 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
10 | ;; it under the terms of the GNU General Public License as published by | |
11 | ;; the Free Software Foundation, either version 3 of the License, or | |
12 | ;; (at your option) any later version. | |
13 | ||
14 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | ;; GNU General Public License for more details. | |
18 | ||
19 | ;; You should have received a copy of the GNU General Public License | |
20 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | ;;; Commentary: | |
23 | ;; | |
24 | ;; Parse Texinfo buffers using regular expressions. The core parser | |
25 | ;; engine is the function `semantic-texi-parse-headings'. The | |
26 | ;; parser plug-in is the function `semantic-texi-parse-region' that | |
27 | ;; overrides `semantic-parse-region'. | |
28 | ||
3f2a848d | 29 | (require 'semantic/db-find) |
9573e58b | 30 | (require 'semantic/format) |
3f2a848d | 31 | (require 'semantic/ctxt) |
9573e58b CY |
32 | (require 'texinfo) |
33 | ||
a4556861 | 34 | (defvar ede-minor-mode) |
55b522b2 | 35 | (declare-function lookup-words "ispell") |
a4556861 | 36 | (declare-function ede-current-project "ede") |
55b522b2 | 37 | |
9573e58b CY |
38 | (defvar semantic-texi-super-regex |
39 | "^@\\(top\\|chapter\\|\\(sub\\)*section\\|unnumbered\\(\\(sub\\)*sec\\)?\\|\ | |
40 | \\(chap\\|\\(sub\\)+\\|major\\)?heading\\|appendix\\(\\(sub\\)*sec\\)?\\|\ | |
41 | centerchap\\|def\\(var\\|un\\|fn\\|opt\\)x?\\)" | |
42 | "Regular expression used to find special sections in a Texinfo file.") | |
43 | ||
44 | (defvar semantic-texi-name-field-list | |
45 | '( ("defvar" . 1) | |
46 | ("defvarx" . 1) | |
47 | ("defun" . 1) | |
48 | ("defunx" . 1) | |
49 | ("defopt" . 1) | |
50 | ("deffn" . 2) | |
51 | ("deffnx" . 2) | |
52 | ) | |
53 | "List of definition commands, and the field position. | |
54 | The field position is the field number (based at 1) where the | |
55 | name of this section is.") | |
56 | ||
57 | ;;; Code: | |
58 | (defun semantic-texi-parse-region (&rest ignore) | |
59 | "Parse the current texinfo buffer for semantic tags. | |
60 | IGNORE any arguments, always parse the whole buffer. | |
61 | Each tag returned is of the form: | |
62 | (\"NAME\" section (:members CHILDREN)) | |
63 | or | |
64 | (\"NAME\" def) | |
65 | ||
66 | It is an override of 'parse-region and must be installed by the | |
67 | function `semantic-install-function-overrides'." | |
68 | (mapcar 'semantic-texi-expand-tag | |
69 | (semantic-texi-parse-headings))) | |
70 | ||
71 | (defun semantic-texi-parse-changes () | |
72 | "Parse changes in the current texinfo buffer." | |
73 | ;; NOTE: For now, just schedule a full reparse. | |
74 | ;; To be implemented later. | |
75 | (semantic-parse-tree-set-needs-rebuild)) | |
76 | ||
77 | (defun semantic-texi-expand-tag (tag) | |
78 | "Expand the texinfo tag TAG." | |
79 | (let ((chil (semantic-tag-components tag))) | |
80 | (if chil | |
81 | (semantic-tag-put-attribute | |
82 | tag :members (mapcar 'semantic-texi-expand-tag chil))) | |
83 | (car (semantic--tag-expand tag)))) | |
84 | ||
85 | (defun semantic-texi-parse-headings () | |
86 | "Parse the current texinfo buffer for all semantic tags now." | |
87 | (let ((pass1 nil)) | |
88 | ;; First search and snarf. | |
89 | (save-excursion | |
90 | (goto-char (point-min)) | |
91 | (let ((semantic--progress-reporter | |
92 | (make-progress-reporter | |
93 | (format "Parsing %s..." | |
94 | (file-name-nondirectory buffer-file-name)) | |
95 | (point-min) (point-max)))) | |
96 | (while (re-search-forward semantic-texi-super-regex nil t) | |
97 | (setq pass1 (cons (match-beginning 0) pass1)) | |
98 | (progress-reporter-update semantic--progress-reporter (point))) | |
99 | (progress-reporter-done semantic--progress-reporter))) | |
100 | (setq pass1 (nreverse pass1)) | |
101 | ;; Now, make some tags while creating a set of children. | |
102 | (car (semantic-texi-recursive-combobulate-list pass1 0)) | |
103 | )) | |
104 | ||
105 | (defsubst semantic-texi-new-section-tag (name members start end) | |
106 | "Create a semantic tag of class section. | |
107 | NAME is the name of this section. | |
108 | MEMBERS is a list of semantic tags representing the elements that make | |
109 | up this section. | |
110 | START and END define the location of data described by the tag." | |
111 | (append (semantic-tag name 'section :members members) | |
112 | (list start end))) | |
113 | ||
114 | (defsubst semantic-texi-new-def-tag (name start end) | |
115 | "Create a semantic tag of class def. | |
116 | NAME is the name of this definition. | |
117 | START and END define the location of data described by the tag." | |
118 | (append (semantic-tag name 'def) | |
119 | (list start end))) | |
120 | ||
121 | (defun semantic-texi-set-endpoint (metataglist pnt) | |
122 | "Set the end point of the first section tag in METATAGLIST to PNT. | |
123 | METATAGLIST is a list of tags in the intermediate tag format used by the | |
124 | texinfo parser. PNT is the new point to set." | |
125 | (let ((metatag nil)) | |
126 | (while (and metataglist | |
127 | (not (eq (semantic-tag-class (car metataglist)) 'section))) | |
128 | (setq metataglist (cdr metataglist))) | |
129 | (setq metatag (car metataglist)) | |
130 | (when metatag | |
131 | (setcar (nthcdr (1- (length metatag)) metatag) pnt) | |
132 | metatag))) | |
133 | ||
134 | (defun semantic-texi-recursive-combobulate-list (sectionlist level) | |
135 | "Rearrange SECTIONLIST to be a hierarchical tag list starting at LEVEL. | |
136 | Return the rearranged new list, with all remaining tags from | |
137 | SECTIONLIST starting at ELT 2. Sections not are not dealt with as soon as a | |
138 | tag with greater section value than LEVEL is found." | |
139 | (let ((newl nil) | |
140 | (oldl sectionlist) | |
141 | tag | |
142 | ) | |
143 | (save-excursion | |
144 | (catch 'level-jump | |
145 | (while oldl | |
146 | (goto-char (car oldl)) | |
147 | (if (looking-at "@\\(\\w+\\)") | |
148 | (let* ((word (match-string 1)) | |
149 | (levelmatch (assoc word texinfo-section-list)) | |
150 | text begin tmp | |
151 | ) | |
152 | ;; Set begin to the right location | |
153 | (setq begin (point)) | |
154 | ;; Get out of here if there if we made it that far. | |
155 | (if (and levelmatch (<= (car (cdr levelmatch)) level)) | |
156 | (progn | |
157 | (when newl | |
158 | (semantic-texi-set-endpoint newl begin)) | |
159 | (throw 'level-jump t))) | |
160 | ;; Recombobulate | |
161 | (if levelmatch | |
162 | (let ((end (match-end 1))) | |
163 | ;; Levels sometimes have a @node just in front. | |
164 | ;; That node statement should be included in the space | |
165 | ;; for this entry. | |
166 | (save-excursion | |
167 | (skip-chars-backward "\n \t") | |
168 | (beginning-of-line) | |
169 | (when (looking-at "@node\\>") | |
170 | (setq begin (point)))) | |
171 | ;; When there is a match, the descriptive text | |
172 | ;; consists of the rest of the line. | |
173 | (goto-char end) | |
174 | (skip-chars-forward " \t") | |
175 | (setq text (buffer-substring-no-properties | |
176 | (point) | |
177 | (progn (end-of-line) (point)))) | |
178 | ;; Next, recurse into the body to find the end. | |
179 | (setq tmp (semantic-texi-recursive-combobulate-list | |
180 | (cdr oldl) (car (cdr levelmatch)))) | |
181 | ;; Build a tag | |
182 | (setq tag (semantic-texi-new-section-tag | |
183 | text (car tmp) begin (point))) | |
184 | ;; Before appending the newtag, update the previous tag | |
185 | ;; if it is a section tag. | |
186 | (when newl | |
187 | (semantic-texi-set-endpoint newl begin)) | |
188 | ;; Append new tag to our master list. | |
189 | (setq newl (cons tag newl)) | |
190 | ;; continue | |
191 | (setq oldl (cdr tmp)) | |
192 | ) | |
193 | ;; No match means we have a def*, so get the name from | |
194 | ;; it based on the type of thingy we found. | |
195 | (setq levelmatch (assoc word semantic-texi-name-field-list) | |
196 | tmp (or (cdr levelmatch) 1)) | |
197 | (forward-sexp tmp) | |
198 | (skip-chars-forward " \t") | |
199 | (setq text (buffer-substring-no-properties | |
200 | (point) | |
201 | (progn (forward-sexp 1) (point)))) | |
202 | ;; Seek the end of this definition | |
203 | (goto-char begin) | |
204 | (semantic-texi-forward-deffn) | |
205 | (setq tag (semantic-texi-new-def-tag text begin (point)) | |
206 | newl (cons tag newl)) | |
207 | ;; continue | |
208 | (setq oldl (cdr oldl))) | |
209 | ) | |
210 | (error "Problem finding section in semantic/texi parser")) | |
211 | ;; (setq oldl (cdr oldl)) | |
212 | ) | |
213 | ;; When oldl runs out, force a new endpoint as point-max | |
214 | (when (not oldl) | |
215 | (semantic-texi-set-endpoint newl (point-max))) | |
216 | )) | |
217 | (cons (nreverse newl) oldl))) | |
218 | ||
219 | (defun semantic-texi-forward-deffn () | |
220 | "Move forward over one deffn type definition. | |
221 | The cursor should be on the @ sign." | |
222 | (when (looking-at "@\\(\\w+\\)") | |
223 | (let* ((type (match-string 1)) | |
224 | (seek (concat "^@end\\s-+" (regexp-quote type)))) | |
225 | (re-search-forward seek nil t)))) | |
226 | ||
227 | (define-mode-local-override semantic-tag-components | |
228 | texinfo-mode (tag) | |
229 | "Return components belonging to TAG." | |
230 | (semantic-tag-get-attribute tag :members)) | |
231 | ||
232 | \f | |
233 | ;;; Overrides: Context Parsing | |
234 | ;; | |
235 | ;; How to treat texi as a language? | |
236 | ;; | |
237 | (defvar semantic-texi-environment-regexp | |
238 | (if (string-match texinfo-environment-regexp "@menu") | |
239 | ;; Make sure our Emacs has menus in it. | |
240 | texinfo-environment-regexp | |
241 | ;; If no menus, then merge in the menu concept. | |
242 | (when (string-match "cartouche" texinfo-environment-regexp) | |
243 | (concat (substring texinfo-environment-regexp | |
244 | 0 (match-beginning 0)) | |
245 | "menu\\|" | |
246 | (substring texinfo-environment-regexp | |
247 | (match-beginning 0))))) | |
9bf6c65c | 248 | "Regular expression for matching texinfo environments. |
9573e58b CY |
249 | uses `texinfo-environment-regexp', but makes sure that it |
250 | can handle the @menu environment.") | |
251 | ||
252 | (define-mode-local-override semantic-up-context texinfo-mode () | |
253 | "Handle texinfo constructs which do not use parenthetical nesting." | |
254 | (let ((done nil)) | |
255 | (save-excursion | |
256 | (let ((parenthetical (semantic-up-context-default)) | |
257 | ) | |
258 | (when (not parenthetical) | |
e1dbe924 | 259 | ;; We are in parentheses. Are they the types of parens |
9573e58b CY |
260 | ;; belonging to a texinfo construct? |
261 | (forward-word -1) | |
262 | (when (looking-at "@\\w+{") | |
263 | (setq done (point)))))) | |
264 | ;; If we are not in a parenthetical node, then find a block instead. | |
265 | ;; Use the texinfo support to find block start/end constructs. | |
266 | (save-excursion | |
267 | (while (and (not done) | |
268 | (re-search-backward semantic-texi-environment-regexp nil t)) | |
269 | ;; For any hit, if we find an @end foo, then jump to the | |
270 | ;; matching @foo. If it is not an end, then we win! | |
271 | (if (not (looking-at "@end\\s-+\\(\\w+\\)")) | |
272 | (setq done (point)) | |
273 | ;; Skip over this block | |
274 | (let ((env (match-string 1))) | |
275 | (re-search-backward (concat "@" env)))) | |
276 | )) | |
277 | ;; All over, post what we find. | |
278 | (if done | |
279 | ;; We found something, so use it. | |
280 | (progn (goto-char done) | |
281 | nil) | |
282 | t))) | |
283 | ||
284 | (define-mode-local-override semantic-beginning-of-context texinfo-mode (&optional point) | |
285 | "Move to the beginning of the context surrounding POINT." | |
286 | (if (semantic-up-context point) | |
287 | ;; If we can't go up, we can't do this either. | |
288 | t | |
289 | ;; We moved, so now we need to skip into whatever this thing is. | |
290 | (forward-word 1) ;; skip the command | |
291 | (if (looking-at "\\s-*{") | |
292 | ;; In a short command. Go in. | |
293 | (down-list 1) | |
294 | ;; An environment. Go to the next line. | |
295 | (end-of-line) | |
296 | (forward-char 1)) | |
297 | nil)) | |
298 | ||
299 | (define-mode-local-override semantic-ctxt-current-class-list | |
300 | texinfo-mode (&optional point) | |
301 | "Determine the class of tags that can be used at POINT. | |
302 | For texinfo, there two possibilities returned. | |
303 | 1) 'function - for a call to a texinfo function | |
304 | 2) 'word - indicates an english word. | |
305 | It would be nice to know function arguments too, but not today." | |
306 | (let ((sym (semantic-ctxt-current-symbol))) | |
307 | (if (and sym (= (aref (car sym) 0) ?@)) | |
308 | '(function) | |
309 | '(word)))) | |
310 | ||
311 | \f | |
312 | ;;; Overrides : Formatting | |
313 | ;; | |
314 | ;; Various override to better format texi tags. | |
315 | ;; | |
316 | ||
317 | (define-mode-local-override semantic-format-tag-abbreviate | |
318 | texinfo-mode (tag &optional parent color) | |
319 | "Texinfo tags abbreviation." | |
320 | (let ((class (semantic-tag-class tag)) | |
321 | (name (semantic-format-tag-name tag parent color)) | |
322 | ) | |
323 | (cond ((eq class 'function) | |
324 | (concat name "{ }")) | |
325 | (t (semantic-format-tag-abbreviate-default tag parent color))) | |
326 | )) | |
327 | ||
328 | (define-mode-local-override semantic-format-tag-prototype | |
329 | texinfo-mode (tag &optional parent color) | |
330 | "Texinfo tags abbreviation." | |
331 | (semantic-format-tag-abbreviate tag parent color)) | |
332 | ||
333 | \f | |
334 | ;;; Texi Unique Features | |
335 | ;; | |
336 | (defun semantic-tag-texi-section-text-bounds (tag) | |
337 | "Get the bounds to the text of TAG. | |
338 | The text bounds is the text belonging to this node excluding | |
339 | the text of any child nodes, but including any defuns." | |
340 | (let ((memb (semantic-tag-components tag))) | |
341 | ;; Members.. if one is a section, check it out. | |
342 | (while (and memb (not (semantic-tag-of-class-p (car memb) 'section))) | |
343 | (setq memb (cdr memb))) | |
344 | ;; No members? ... then a simple problem! | |
345 | (if (not memb) | |
346 | (semantic-tag-bounds tag) | |
347 | ;; Our end is their beginning... | |
348 | (list (semantic-tag-start tag) (semantic-tag-start (car memb)))))) | |
349 | ||
350 | (defun semantic-texi-current-environment (&optional point) | |
351 | "Return as a string the type of the current environment. | |
352 | Optional argument POINT is where to look for the environment." | |
353 | (save-excursion | |
354 | (when point (goto-char (point))) | |
355 | (while (and (or (not (looking-at semantic-texi-environment-regexp)) | |
356 | (looking-at "@end")) | |
357 | (not (semantic-up-context))) | |
358 | ) | |
359 | (when (looking-at semantic-texi-environment-regexp) | |
360 | (match-string 1)))) | |
361 | ||
362 | \f | |
363 | ;;; Analyzer | |
364 | ;; | |
365 | (eval-when-compile | |
366 | (require 'semantic/analyze)) | |
367 | ||
368 | (define-mode-local-override semantic-analyze-current-context | |
369 | texinfo-mode (point) | |
370 | "Analysis context makes no sense for texinfo. Return nil." | |
371 | (let* ((prefixandbounds (semantic-ctxt-current-symbol-and-bounds (point))) | |
372 | (prefix (car prefixandbounds)) | |
373 | (bounds (nth 2 prefixandbounds)) | |
374 | (prefixclass (semantic-ctxt-current-class-list)) | |
375 | ) | |
376 | (when prefix | |
55b522b2 | 377 | (require 'semantic/analyze) |
9573e58b CY |
378 | (semantic-analyze-context |
379 | "Context-for-texinfo" | |
380 | :buffer (current-buffer) | |
381 | :scope nil | |
382 | :bounds bounds | |
383 | :prefix prefix | |
384 | :prefixtypes nil | |
385 | :prefixclass prefixclass) | |
386 | ) | |
387 | )) | |
388 | ||
389 | (defvar semantic-texi-command-completion-list | |
390 | (append (mapcar (lambda (a) (car a)) texinfo-section-list) | |
391 | (condition-case nil | |
392 | texinfo-environments | |
393 | (error | |
394 | ;; XEmacs doesn't use the above. Split up its regexp | |
395 | (split-string texinfo-environment-regexp "\\\\|\\|\\^@\\\\(\\|\\\\)") | |
396 | )) | |
397 | ;; Is there a better list somewhere? Here are few | |
398 | ;; of the top of my head. | |
399 | "anchor" "asis" | |
400 | "bullet" | |
401 | "code" "copyright" | |
402 | "defun" "deffn" "defoption" "defvar" "dfn" | |
403 | "emph" "end" | |
404 | "ifinfo" "iftex" "inforef" "item" "itemx" | |
405 | "kdb" | |
406 | "node" | |
407 | "ref" | |
408 | "set" "setfilename" "settitle" | |
409 | "value" "var" | |
410 | "xref" | |
411 | ) | |
412 | "List of commands that we might bother completing.") | |
413 | ||
414 | (define-mode-local-override semantic-analyze-possible-completions | |
415 | texinfo-mode (context) | |
416 | "List smart completions at point. | |
417 | Since texinfo is not a programming language the default version is not | |
f6b1b0a8 | 418 | useful. Instead, look at the current symbol. If it is a command |
9573e58b CY |
419 | do primitive texinfo built ins. If not, use ispell to lookup words |
420 | that start with that symbol." | |
421 | (let ((prefix (car (oref context :prefix))) | |
422 | ) | |
423 | (cond ((member 'function (oref context :prefixclass)) | |
424 | ;; Do completion for texinfo commands | |
425 | (let* ((cmd (substring prefix 1)) | |
426 | (lst (all-completions | |
427 | cmd semantic-texi-command-completion-list))) | |
428 | (mapcar (lambda (f) (semantic-tag (concat "@" f) 'function)) | |
429 | lst)) | |
430 | ) | |
431 | ((member 'word (oref context :prefixclass)) | |
432 | ;; Do completion for words via ispell. | |
433 | (require 'ispell) | |
434 | (let ((word-list (lookup-words prefix))) | |
435 | (mapcar (lambda (f) (semantic-tag f 'word)) word-list)) | |
436 | ) | |
437 | (t nil)) | |
438 | )) | |
439 | ||
440 | \f | |
441 | ;;; Parser Setup | |
442 | ;; | |
07a79ce4 | 443 | ;; In semantic/imenu.el, not part of Emacs. |
f3628edd GM |
444 | (defvar semantic-imenu-expandable-tag-classes) |
445 | (defvar semantic-imenu-bucketize-file) | |
446 | (defvar semantic-imenu-bucketize-type-members) | |
447 | ||
62a81506 | 448 | ;;;###autoload |
9573e58b CY |
449 | (defun semantic-default-texi-setup () |
450 | "Set up a buffer for parsing of Texinfo files." | |
451 | ;; This will use our parser. | |
452 | (semantic-install-function-overrides | |
453 | '((parse-region . semantic-texi-parse-region) | |
454 | (parse-changes . semantic-texi-parse-changes))) | |
455 | (setq semantic-parser-name "TEXI" | |
456 | ;; Setup a dummy parser table to enable parsing! | |
457 | semantic--parse-table t | |
458 | imenu-create-index-function 'semantic-create-imenu-index | |
459 | semantic-command-separation-character "@" | |
460 | semantic-type-relation-separator-character '(":") | |
461 | semantic-symbol->name-assoc-list '((section . "Section") | |
462 | (def . "Definition") | |
463 | ) | |
464 | semantic-imenu-expandable-tag-classes '(section) | |
465 | semantic-imenu-bucketize-file nil | |
466 | semantic-imenu-bucketize-type-members nil | |
467 | senator-step-at-start-end-tag-classes '(section) | |
468 | semantic-stickyfunc-sticky-classes '(section) | |
469 | ) | |
996bc9bf | 470 | ;; (local-set-key [(f9)] 'semantic-texi-update-doc-from-texi) |
9573e58b CY |
471 | ) |
472 | ||
473 | (add-hook 'texinfo-mode-hook 'semantic-default-texi-setup) | |
474 | ||
475 | \f | |
476 | ;;; Special features of Texinfo tag streams | |
477 | ;; | |
478 | ;; This section provides specialized access into texinfo files. | |
479 | ;; Because texinfo files often directly refer to functions and programs | |
480 | ;; it is useful to access the texinfo file from the C code for document | |
53964682 | 481 | ;; maintenance. |
9573e58b CY |
482 | (defun semantic-texi-associated-files (&optional buffer) |
483 | "Find texinfo files associated with BUFFER." | |
484 | (save-excursion | |
485 | (if buffer (set-buffer buffer)) | |
486 | (cond ((and (fboundp 'ede-documentation-files) | |
487 | ede-minor-mode (ede-current-project)) | |
488 | ;; When EDE is active, ask it. | |
489 | (ede-documentation-files) | |
490 | ) | |
55b522b2 | 491 | ((and (featurep 'semantic/db) (semanticdb-minor-mode-p)) |
9573e58b CY |
492 | ;; See what texinfo files we have loaded in the database |
493 | (let ((tabs (semanticdb-get-database-tables | |
494 | semanticdb-current-database)) | |
495 | (r nil)) | |
496 | (while tabs | |
497 | (if (eq (oref (car tabs) major-mode) 'texinfo-mode) | |
498 | (setq r (cons (oref (car tabs) file) r))) | |
499 | (setq tabs (cdr tabs))) | |
500 | r)) | |
501 | (t | |
502 | (directory-files default-directory nil "\\.texi$")) | |
503 | ))) | |
504 | ||
505 | ;; Turns out this might not be useful. | |
506 | ;; Delete later if that is true. | |
507 | (defun semantic-texi-find-documentation (name &optional type) | |
508 | "Find the function or variable NAME of TYPE in the texinfo source. | |
509 | NAME is a string representing some functional symbol. | |
510 | TYPE is a string, such as \"variable\" or \"Command\" used to find | |
511 | the correct definition in case NAME qualifies as several things. | |
512 | When this function exists, POINT is at the definition. | |
513 | If the doc was not found, an error is thrown. | |
514 | Note: TYPE not yet implemented." | |
515 | (let ((f (semantic-texi-associated-files)) | |
516 | stream match) | |
517 | (while (and f (not match)) | |
518 | (unless stream | |
519 | (with-current-buffer (find-file-noselect (car f)) | |
520 | (setq stream (semantic-fetch-tags)))) | |
521 | (setq match (semantic-find-first-tag-by-name name stream)) | |
522 | (when match | |
523 | (set-buffer (semantic-tag-buffer match)) | |
524 | (goto-char (semantic-tag-start match))) | |
525 | (setq f (cdr f))))) | |
526 | ||
996bc9bf CY |
527 | ;; (defun semantic-texi-update-doc-from-texi (&optional tag) |
528 | ;; "Update the documentation in the texinfo deffn class tag TAG. | |
529 | ;; The current buffer must be a texinfo file containing TAG. | |
530 | ;; If TAG is nil, determine a tag based on the current position." | |
531 | ;; (interactive) | |
532 | ;; (unless (or (featurep 'semantic/db) | |
533 | ;; (require 'semantic/db-mode) | |
534 | ;; (semanticdb-minor-mode-p)) | |
535 | ;; (error "Texinfo updating only works when `semanticdb' is being used")) | |
536 | ;; (semantic-fetch-tags) | |
537 | ;; (unless tag | |
538 | ;; (beginning-of-line) | |
539 | ;; (setq tag (semantic-current-tag))) | |
540 | ;; (unless (semantic-tag-of-class-p tag 'def) | |
541 | ;; (error "Only deffns (or defun or defvar) can be updated")) | |
542 | ;; (let* ((name (semantic-tag-name tag)) | |
543 | ;; (tags (semanticdb-strip-find-results | |
544 | ;; (semanticdb-with-match-any-mode | |
545 | ;; (semanticdb-brute-deep-find-tags-by-name name)) | |
546 | ;; 'name)) | |
547 | ;; (docstring nil) | |
548 | ;; (docstringproto nil) | |
549 | ;; (docstringvar nil) | |
550 | ;; (doctag nil) | |
551 | ;; (doctagproto nil) | |
552 | ;; (doctagvar nil) | |
553 | ;; ) | |
554 | ;; (save-excursion | |
555 | ;; (while (and tags (not docstring)) | |
556 | ;; (let ((sourcetag (car tags))) | |
557 | ;; ;; There could be more than one! Come up with a better | |
558 | ;; ;; solution someday. | |
559 | ;; (when (semantic-tag-buffer sourcetag) | |
560 | ;; (set-buffer (semantic-tag-buffer sourcetag)) | |
561 | ;; (unless (eq major-mode 'texinfo-mode) | |
562 | ;; (cond ((semantic-tag-get-attribute sourcetag :prototype-flag) | |
563 | ;; ;; If we found a match with doc that is a prototype, then store | |
564 | ;; ;; that, but don't exit till we find the real deal. | |
565 | ;; (setq docstringproto (semantic-documentation-for-tag sourcetag) | |
566 | ;; doctagproto sourcetag)) | |
567 | ;; ((eq (semantic-tag-class sourcetag) 'variable) | |
568 | ;; (setq docstringvar (semantic-documentation-for-tag sourcetag) | |
569 | ;; doctagvar sourcetag)) | |
570 | ;; ((semantic-tag-get-attribute sourcetag :override-function-flag) | |
571 | ;; nil) | |
572 | ;; (t | |
573 | ;; (setq docstring (semantic-documentation-for-tag sourcetag)))) | |
574 | ;; (setq doctag (if docstring sourcetag nil)))) | |
575 | ;; (setq tags (cdr tags))))) | |
576 | ;; ;; If we found a prototype of the function that has some doc, but not the | |
c7015153 | 577 | ;; ;; actual function, let's make due with that. |
996bc9bf CY |
578 | ;; (if (not docstring) |
579 | ;; (cond ((stringp docstringvar) | |
580 | ;; (setq docstring docstringvar | |
581 | ;; doctag doctagvar)) | |
582 | ;; ((stringp docstringproto) | |
583 | ;; (setq docstring docstringproto | |
584 | ;; doctag doctagproto)))) | |
585 | ;; ;; Test for doc string | |
586 | ;; (unless docstring | |
587 | ;; (error "Could not find documentation for %s" (semantic-tag-name tag))) | |
dd9af436 CY |
588 | ;; |
589 | ;; (require 'srecode) | |
07a79ce4 | 590 | ;; (require 'srecode/texi) |
dd9af436 | 591 | ;; |
996bc9bf CY |
592 | ;; ;; If we have a string, do the replacement. |
593 | ;; (delete-region (semantic-tag-start tag) | |
594 | ;; (semantic-tag-end tag)) | |
4c36be58 | 595 | ;; ;; Use useful functions from the document library. |
dd9af436 CY |
596 | ;; (srecode-texi-insert-tag-as-doc doctag) |
597 | ;; ;(semantic-insert-foreign-tag doctag) | |
996bc9bf CY |
598 | ;; )) |
599 | ||
600 | ;; (defun semantic-texi-update-doc-from-source (&optional tag) | |
601 | ;; "Update the documentation for the source TAG. | |
602 | ;; The current buffer must be a non-texinfo source file containing TAG. | |
603 | ;; If TAG is nil, determine the tag based on the current position. | |
604 | ;; The current buffer must include TAG." | |
605 | ;; (interactive) | |
606 | ;; (when (eq major-mode 'texinfo-mode) | |
607 | ;; (error "Not a source file")) | |
608 | ;; (semantic-fetch-tags) | |
609 | ;; (unless tag | |
610 | ;; (setq tag (semantic-current-tag))) | |
611 | ;; (unless (semantic-documentation-for-tag tag) | |
612 | ;; (error "Cannot find interesting documentation to use for %s" | |
613 | ;; (semantic-tag-name tag))) | |
614 | ;; (let* ((name (semantic-tag-name tag)) | |
615 | ;; (texi (semantic-texi-associated-files)) | |
616 | ;; (doctag nil) | |
617 | ;; (docbuff nil)) | |
618 | ;; (while (and texi (not doctag)) | |
619 | ;; (set-buffer (find-file-noselect (car texi))) | |
620 | ;; (setq doctag (car (semantic-deep-find-tags-by-name | |
621 | ;; name (semantic-fetch-tags))) | |
622 | ;; docbuff (if doctag (current-buffer) nil)) | |
623 | ;; (setq texi (cdr texi))) | |
624 | ;; (unless doctag | |
625 | ;; (error "Tag %s is not yet documented. Use the `document' command" | |
626 | ;; name)) | |
627 | ;; ;; Ok, we should have everything we need. Do the deed. | |
628 | ;; (if (get-buffer-window docbuff) | |
629 | ;; (set-buffer docbuff) | |
630 | ;; (switch-to-buffer docbuff)) | |
631 | ;; (goto-char (semantic-tag-start doctag)) | |
632 | ;; (delete-region (semantic-tag-start doctag) | |
633 | ;; (semantic-tag-end doctag)) | |
634 | ;; ;; Use useful functions from the document library. | |
635 | ;; (require 'document) | |
636 | ;; (document-insert-texinfo tag (semantic-tag-buffer tag)) | |
637 | ;; )) | |
638 | ||
639 | ;; (defun semantic-texi-update-doc (&optional tag) | |
640 | ;; "Update the documentation for TAG. | |
641 | ;; If the current buffer is a texinfo file, then find the source doc, and | |
642 | ;; update it. If the current buffer is a source file, then get the | |
643 | ;; documentation for this item, find the existing doc in the associated | |
644 | ;; manual, and update that." | |
645 | ;; (interactive) | |
646 | ;; (cond ;;((eq major-mode 'texinfo-mode) | |
647 | ;; ;; (semantic-texi-update-doc-from-texi tag)) | |
648 | ;; (t | |
649 | ;; (semantic-texi-update-doc-from-source tag)))) | |
9573e58b CY |
650 | |
651 | (defun semantic-texi-goto-source (&optional tag) | |
652 | "Jump to the source for the definition in the texinfo file TAG. | |
653 | If TAG is nil, it is derived from the deffn under POINT." | |
654 | (interactive) | |
55b522b2 | 655 | (unless (or (featurep 'semantic/db) (semanticdb-minor-mode-p)) |
9573e58b CY |
656 | (error "Texinfo updating only works when `semanticdb' is being used")) |
657 | (semantic-fetch-tags) | |
658 | (unless tag | |
659 | (beginning-of-line) | |
660 | (setq tag (semantic-current-tag))) | |
661 | (unless (semantic-tag-of-class-p tag 'def) | |
662 | (error "Only deffns (or defun or defvar) can be updated")) | |
663 | (let* ((name (semantic-tag-name tag)) | |
664 | (tags (semanticdb-fast-strip-find-results | |
665 | (semanticdb-with-match-any-mode | |
666 | (semanticdb-brute-deep-find-tags-by-name name nil 'name)) | |
667 | )) | |
668 | ||
669 | (done nil) | |
670 | ) | |
671 | (save-excursion | |
672 | (while (and tags (not done)) | |
673 | (set-buffer (semantic-tag-buffer (car tags))) | |
674 | (unless (eq major-mode 'texinfo-mode) | |
675 | (switch-to-buffer (semantic-tag-buffer (car tags))) | |
676 | (goto-char (semantic-tag-start (car tags))) | |
677 | (setq done t)) | |
678 | (setq tags (cdr tags))) | |
679 | (if (not done) | |
680 | (error "Could not find tag for %s" (semantic-tag-name tag))) | |
681 | ))) | |
682 | ||
683 | (provide 'semantic/texi) | |
684 | ||
62a81506 CY |
685 | ;; Local variables: |
686 | ;; generated-autoload-file: "loaddefs.el" | |
687 | ;; generated-autoload-load-name: "semantic/texi" | |
688 | ;; End: | |
689 | ||
55b522b2 | 690 | ;;; semantic/texi.el ends here |