123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- (require 'semantic)
- (require 'semantic/format)
- (require 'texinfo)
- (eval-when-compile
- (require 'semantic/db)
- (require 'semantic/db-find)
- (require 'semantic/ctxt)
- (require 'semantic/find)
- (require 'semantic/doc))
- (defvar ede-minor-mode)
- (declare-function lookup-words "ispell")
- (declare-function ede-current-project "ede")
- (defvar semantic-texi-super-regex
- "^@\\(top\\|chapter\\|\\(sub\\)*section\\|unnumbered\\(\\(sub\\)*sec\\)?\\|\
- \\(chap\\|\\(sub\\)+\\|major\\)?heading\\|appendix\\(\\(sub\\)*sec\\)?\\|\
- centerchap\\|def\\(var\\|un\\|fn\\|opt\\)x?\\)"
- "Regular expression used to find special sections in a Texinfo file.")
- (defvar semantic-texi-name-field-list
- '( ("defvar" . 1)
- ("defvarx" . 1)
- ("defun" . 1)
- ("defunx" . 1)
- ("defopt" . 1)
- ("deffn" . 2)
- ("deffnx" . 2)
- )
- "List of definition commands, and the field position.
- The field position is the field number (based at 1) where the
- name of this section is.")
- (defun semantic-texi-parse-region (&rest ignore)
- "Parse the current texinfo buffer for semantic tags.
- IGNORE any arguments, always parse the whole buffer.
- Each tag returned is of the form:
- (\"NAME\" section (:members CHILDREN))
- or
- (\"NAME\" def)
- It is an override of 'parse-region and must be installed by the
- function `semantic-install-function-overrides'."
- (mapcar 'semantic-texi-expand-tag
- (semantic-texi-parse-headings)))
- (defun semantic-texi-parse-changes ()
- "Parse changes in the current texinfo buffer."
-
-
- (semantic-parse-tree-set-needs-rebuild))
- (defun semantic-texi-expand-tag (tag)
- "Expand the texinfo tag TAG."
- (let ((chil (semantic-tag-components tag)))
- (if chil
- (semantic-tag-put-attribute
- tag :members (mapcar 'semantic-texi-expand-tag chil)))
- (car (semantic--tag-expand tag))))
- (defun semantic-texi-parse-headings ()
- "Parse the current texinfo buffer for all semantic tags now."
- (let ((pass1 nil))
-
- (save-excursion
- (goto-char (point-min))
- (let ((semantic--progress-reporter
- (make-progress-reporter
- (format "Parsing %s..."
- (file-name-nondirectory buffer-file-name))
- (point-min) (point-max))))
- (while (re-search-forward semantic-texi-super-regex nil t)
- (setq pass1 (cons (match-beginning 0) pass1))
- (progress-reporter-update semantic--progress-reporter (point)))
- (progress-reporter-done semantic--progress-reporter)))
- (setq pass1 (nreverse pass1))
-
- (car (semantic-texi-recursive-combobulate-list pass1 0))
- ))
- (defsubst semantic-texi-new-section-tag (name members start end)
- "Create a semantic tag of class section.
- NAME is the name of this section.
- MEMBERS is a list of semantic tags representing the elements that make
- up this section.
- START and END define the location of data described by the tag."
- (append (semantic-tag name 'section :members members)
- (list start end)))
- (defsubst semantic-texi-new-def-tag (name start end)
- "Create a semantic tag of class def.
- NAME is the name of this definition.
- START and END define the location of data described by the tag."
- (append (semantic-tag name 'def)
- (list start end)))
- (defun semantic-texi-set-endpoint (metataglist pnt)
- "Set the end point of the first section tag in METATAGLIST to PNT.
- METATAGLIST is a list of tags in the intermediate tag format used by the
- texinfo parser. PNT is the new point to set."
- (let ((metatag nil))
- (while (and metataglist
- (not (eq (semantic-tag-class (car metataglist)) 'section)))
- (setq metataglist (cdr metataglist)))
- (setq metatag (car metataglist))
- (when metatag
- (setcar (nthcdr (1- (length metatag)) metatag) pnt)
- metatag)))
- (defun semantic-texi-recursive-combobulate-list (sectionlist level)
- "Rearrange SECTIONLIST to be a hierarchical tag list starting at LEVEL.
- Return the rearranged new list, with all remaining tags from
- SECTIONLIST starting at ELT 2. Sections not are not dealt with as soon as a
- tag with greater section value than LEVEL is found."
- (let ((newl nil)
- (oldl sectionlist)
- tag
- )
- (save-excursion
- (catch 'level-jump
- (while oldl
- (goto-char (car oldl))
- (if (looking-at "@\\(\\w+\\)")
- (let* ((word (match-string 1))
- (levelmatch (assoc word texinfo-section-list))
- text begin tmp
- )
-
- (setq begin (point))
-
- (if (and levelmatch (<= (car (cdr levelmatch)) level))
- (progn
- (when newl
- (semantic-texi-set-endpoint newl begin))
- (throw 'level-jump t)))
-
- (if levelmatch
- (let ((end (match-end 1)))
-
-
-
- (save-excursion
- (skip-chars-backward "\n \t")
- (beginning-of-line)
- (when (looking-at "@node\\>")
- (setq begin (point))))
-
-
- (goto-char end)
- (skip-chars-forward " \t")
- (setq text (buffer-substring-no-properties
- (point)
- (progn (end-of-line) (point))))
-
- (setq tmp (semantic-texi-recursive-combobulate-list
- (cdr oldl) (car (cdr levelmatch))))
-
- (setq tag (semantic-texi-new-section-tag
- text (car tmp) begin (point)))
-
-
- (when newl
- (semantic-texi-set-endpoint newl begin))
-
- (setq newl (cons tag newl))
-
- (setq oldl (cdr tmp))
- )
-
-
- (setq levelmatch (assoc word semantic-texi-name-field-list)
- tmp (or (cdr levelmatch) 1))
- (forward-sexp tmp)
- (skip-chars-forward " \t")
- (setq text (buffer-substring-no-properties
- (point)
- (progn (forward-sexp 1) (point))))
-
- (goto-char begin)
- (semantic-texi-forward-deffn)
- (setq tag (semantic-texi-new-def-tag text begin (point))
- newl (cons tag newl))
-
- (setq oldl (cdr oldl)))
- )
- (error "Problem finding section in semantic/texi parser"))
-
- )
-
- (when (not oldl)
- (semantic-texi-set-endpoint newl (point-max)))
- ))
- (cons (nreverse newl) oldl)))
- (defun semantic-texi-forward-deffn ()
- "Move forward over one deffn type definition.
- The cursor should be on the @ sign."
- (when (looking-at "@\\(\\w+\\)")
- (let* ((type (match-string 1))
- (seek (concat "^@end\\s-+" (regexp-quote type))))
- (re-search-forward seek nil t))))
- (define-mode-local-override semantic-tag-components
- texinfo-mode (tag)
- "Return components belonging to TAG."
- (semantic-tag-get-attribute tag :members))
- (defvar semantic-texi-environment-regexp
- (if (string-match texinfo-environment-regexp "@menu")
-
- texinfo-environment-regexp
-
- (when (string-match "cartouche" texinfo-environment-regexp)
- (concat (substring texinfo-environment-regexp
- 0 (match-beginning 0))
- "menu\\|"
- (substring texinfo-environment-regexp
- (match-beginning 0)))))
- "Regular expression for matching texinfo environments.
- uses `texinfo-environment-regexp', but makes sure that it
- can handle the @menu environment.")
- (define-mode-local-override semantic-up-context texinfo-mode ()
- "Handle texinfo constructs which do not use parenthetical nesting."
- (let ((done nil))
- (save-excursion
- (let ((parenthetical (semantic-up-context-default))
- )
- (when (not parenthetical)
-
-
- (forward-word -1)
- (when (looking-at "@\\w+{")
- (setq done (point))))))
-
-
- (save-excursion
- (while (and (not done)
- (re-search-backward semantic-texi-environment-regexp nil t))
-
-
- (if (not (looking-at "@end\\s-+\\(\\w+\\)"))
- (setq done (point))
-
- (let ((env (match-string 1)))
- (re-search-backward (concat "@" env))))
- ))
-
- (if done
-
- (progn (goto-char done)
- nil)
- t)))
- (define-mode-local-override semantic-beginning-of-context texinfo-mode (&optional point)
- "Move to the beginning of the context surrounding POINT."
- (if (semantic-up-context point)
-
- t
-
- (forward-word 1)
- (if (looking-at "\\s-*{")
-
- (down-list 1)
-
- (end-of-line)
- (forward-char 1))
- nil))
- (define-mode-local-override semantic-ctxt-current-class-list
- texinfo-mode (&optional point)
- "Determine the class of tags that can be used at POINT.
- For texinfo, there two possibilities returned.
- 1) 'function - for a call to a texinfo function
- 2) 'word - indicates an english word.
- It would be nice to know function arguments too, but not today."
- (let ((sym (semantic-ctxt-current-symbol)))
- (if (and sym (= (aref (car sym) 0) ?@))
- '(function)
- '(word))))
- (define-mode-local-override semantic-format-tag-abbreviate
- texinfo-mode (tag &optional parent color)
- "Texinfo tags abbreviation."
- (let ((class (semantic-tag-class tag))
- (name (semantic-format-tag-name tag parent color))
- )
- (cond ((eq class 'function)
- (concat name "{ }"))
- (t (semantic-format-tag-abbreviate-default tag parent color)))
- ))
- (define-mode-local-override semantic-format-tag-prototype
- texinfo-mode (tag &optional parent color)
- "Texinfo tags abbreviation."
- (semantic-format-tag-abbreviate tag parent color))
- (defun semantic-tag-texi-section-text-bounds (tag)
- "Get the bounds to the text of TAG.
- The text bounds is the text belonging to this node excluding
- the text of any child nodes, but including any defuns."
- (let ((memb (semantic-tag-components tag)))
-
- (while (and memb (not (semantic-tag-of-class-p (car memb) 'section)))
- (setq memb (cdr memb)))
-
- (if (not memb)
- (semantic-tag-bounds tag)
-
- (list (semantic-tag-start tag) (semantic-tag-start (car memb))))))
- (defun semantic-texi-current-environment (&optional point)
- "Return as a string the type of the current environment.
- Optional argument POINT is where to look for the environment."
- (save-excursion
- (when point (goto-char (point)))
- (while (and (or (not (looking-at semantic-texi-environment-regexp))
- (looking-at "@end"))
- (not (semantic-up-context)))
- )
- (when (looking-at semantic-texi-environment-regexp)
- (match-string 1))))
- (eval-when-compile
- (require 'semantic/analyze))
- (define-mode-local-override semantic-analyze-current-context
- texinfo-mode (point)
- "Analysis context makes no sense for texinfo. Return nil."
- (let* ((prefixandbounds (semantic-ctxt-current-symbol-and-bounds (point)))
- (prefix (car prefixandbounds))
- (bounds (nth 2 prefixandbounds))
- (prefixclass (semantic-ctxt-current-class-list))
- )
- (when prefix
- (require 'semantic/analyze)
- (semantic-analyze-context
- "Context-for-texinfo"
- :buffer (current-buffer)
- :scope nil
- :bounds bounds
- :prefix prefix
- :prefixtypes nil
- :prefixclass prefixclass)
- )
- ))
- (defvar semantic-texi-command-completion-list
- (append (mapcar (lambda (a) (car a)) texinfo-section-list)
- (condition-case nil
- texinfo-environments
- (error
-
- (split-string texinfo-environment-regexp "\\\\|\\|\\^@\\\\(\\|\\\\)")
- ))
-
-
- "anchor" "asis"
- "bullet"
- "code" "copyright"
- "defun" "deffn" "defoption" "defvar" "dfn"
- "emph" "end"
- "ifinfo" "iftex" "inforef" "item" "itemx"
- "kdb"
- "node"
- "ref"
- "set" "setfilename" "settitle"
- "value" "var"
- "xref"
- )
- "List of commands that we might bother completing.")
- (define-mode-local-override semantic-analyze-possible-completions
- texinfo-mode (context)
- "List smart completions at point.
- Since texinfo is not a programming language the default version is not
- useful. Instead, look at the current symbol. If it is a command
- do primitive texinfo built ins. If not, use ispell to lookup words
- that start with that symbol."
- (let ((prefix (car (oref context :prefix)))
- )
- (cond ((member 'function (oref context :prefixclass))
-
- (let* ((cmd (substring prefix 1))
- (lst (all-completions
- cmd semantic-texi-command-completion-list)))
- (mapcar (lambda (f) (semantic-tag (concat "@" f) 'function))
- lst))
- )
- ((member 'word (oref context :prefixclass))
-
- (require 'ispell)
- (let ((word-list (lookup-words prefix)))
- (mapcar (lambda (f) (semantic-tag f 'word)) word-list))
- )
- (t nil))
- ))
- (defvar semantic-imenu-expandable-tag-classes)
- (defvar semantic-imenu-bucketize-file)
- (defvar semantic-imenu-bucketize-type-members)
- (defun semantic-default-texi-setup ()
- "Set up a buffer for parsing of Texinfo files."
-
- (semantic-install-function-overrides
- '((parse-region . semantic-texi-parse-region)
- (parse-changes . semantic-texi-parse-changes)))
- (setq semantic-parser-name "TEXI"
-
- semantic--parse-table t
- imenu-create-index-function 'semantic-create-imenu-index
- semantic-command-separation-character "@"
- semantic-type-relation-separator-character '(":")
- semantic-symbol->name-assoc-list '((section . "Section")
- (def . "Definition")
- )
- semantic-imenu-expandable-tag-classes '(section)
- semantic-imenu-bucketize-file nil
- semantic-imenu-bucketize-type-members nil
- senator-step-at-start-end-tag-classes '(section)
- semantic-stickyfunc-sticky-classes '(section)
- )
-
- )
- (add-hook 'texinfo-mode-hook 'semantic-default-texi-setup)
- (defun semantic-texi-associated-files (&optional buffer)
- "Find texinfo files associated with BUFFER."
- (save-excursion
- (if buffer (set-buffer buffer))
- (cond ((and (fboundp 'ede-documentation-files)
- ede-minor-mode (ede-current-project))
-
- (ede-documentation-files)
- )
- ((and (featurep 'semantic/db) (semanticdb-minor-mode-p))
-
- (let ((tabs (semanticdb-get-database-tables
- semanticdb-current-database))
- (r nil))
- (while tabs
- (if (eq (oref (car tabs) major-mode) 'texinfo-mode)
- (setq r (cons (oref (car tabs) file) r)))
- (setq tabs (cdr tabs)))
- r))
- (t
- (directory-files default-directory nil "\\.texi$"))
- )))
- (defun semantic-texi-find-documentation (name &optional type)
- "Find the function or variable NAME of TYPE in the texinfo source.
- NAME is a string representing some functional symbol.
- TYPE is a string, such as \"variable\" or \"Command\" used to find
- the correct definition in case NAME qualifies as several things.
- When this function exists, POINT is at the definition.
- If the doc was not found, an error is thrown.
- Note: TYPE not yet implemented."
- (let ((f (semantic-texi-associated-files))
- stream match)
- (while (and f (not match))
- (unless stream
- (with-current-buffer (find-file-noselect (car f))
- (setq stream (semantic-fetch-tags))))
- (setq match (semantic-find-first-tag-by-name name stream))
- (when match
- (set-buffer (semantic-tag-buffer match))
- (goto-char (semantic-tag-start match)))
- (setq f (cdr f)))))
- (defun semantic-texi-goto-source (&optional tag)
- "Jump to the source for the definition in the texinfo file TAG.
- If TAG is nil, it is derived from the deffn under POINT."
- (interactive)
- (unless (or (featurep 'semantic/db) (semanticdb-minor-mode-p))
- (error "Texinfo updating only works when `semanticdb' is being used"))
- (semantic-fetch-tags)
- (unless tag
- (beginning-of-line)
- (setq tag (semantic-current-tag)))
- (unless (semantic-tag-of-class-p tag 'def)
- (error "Only deffns (or defun or defvar) can be updated"))
- (let* ((name (semantic-tag-name tag))
- (tags (semanticdb-fast-strip-find-results
- (semanticdb-with-match-any-mode
- (semanticdb-brute-deep-find-tags-by-name name nil 'name))
- ))
- (done nil)
- )
- (save-excursion
- (while (and tags (not done))
- (set-buffer (semantic-tag-buffer (car tags)))
- (unless (eq major-mode 'texinfo-mode)
- (switch-to-buffer (semantic-tag-buffer (car tags)))
- (goto-char (semantic-tag-start (car tags)))
- (setq done t))
- (setq tags (cdr tags)))
- (if (not done)
- (error "Could not find tag for %s" (semantic-tag-name tag)))
- )))
- (provide 'semantic/texi)
|