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