sb.el 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. ;;; semantic/sb.el --- Semantic tag display for speedbar
  2. ;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric M. Ludlam <zappo@gnu.org>
  4. ;; Keywords: syntax
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;
  18. ;; Convert a tag table into speedbar buttons.
  19. ;;; TODO:
  20. ;; Use semanticdb to find which semanticdb-table is being used for each
  21. ;; file/tag. Replace `semantic-sb-with-tag-buffer' to instead call
  22. ;; children with the new `with-mode-local' instead.
  23. (require 'semantic)
  24. (require 'semantic/format)
  25. (require 'semantic/sort)
  26. (require 'semantic/util)
  27. (require 'speedbar)
  28. (declare-function semanticdb-file-stream "semantic/db")
  29. (defcustom semantic-sb-autoexpand-length 1
  30. "*Length of a semantic bucket to autoexpand in place.
  31. This will replace the named bucket that would have usually occurred here."
  32. :group 'speedbar
  33. :type 'integer)
  34. (defcustom semantic-sb-button-format-tag-function 'semantic-format-tag-abbreviate
  35. "*Function called to create the text for a but from a token."
  36. :group 'speedbar
  37. :type semantic-format-tag-custom-list)
  38. (defcustom semantic-sb-info-format-tag-function 'semantic-format-tag-summarize
  39. "*Function called to create the text for info display from a token."
  40. :group 'speedbar
  41. :type semantic-format-tag-custom-list)
  42. ;;; Code:
  43. ;;
  44. ;;; Buffer setting for correct mode manipulation.
  45. (defun semantic-sb-tag-set-buffer (tag)
  46. "Set the current buffer to something associated with TAG.
  47. use the `speedbar-line-file' to get this info if needed."
  48. (if (semantic-tag-buffer tag)
  49. (set-buffer (semantic-tag-buffer tag))
  50. (let ((f (speedbar-line-file)))
  51. (set-buffer (find-file-noselect f)))))
  52. (defmacro semantic-sb-with-tag-buffer (tag &rest forms)
  53. "Set the current buffer to the origin of TAG and execute FORMS.
  54. Restore the old current buffer when completed."
  55. `(save-excursion
  56. (semantic-sb-tag-set-buffer ,tag)
  57. ,@forms))
  58. (put 'semantic-sb-with-tag-buffer 'lisp-indent-function 1)
  59. ;;; Button Generation
  60. ;;
  61. ;; Here are some button groups:
  62. ;;
  63. ;; +> Function ()
  64. ;; @ return_type
  65. ;; +( arg1
  66. ;; +| arg2
  67. ;; +) arg3
  68. ;;
  69. ;; +> Variable[1] =
  70. ;; @ type
  71. ;; = default value
  72. ;;
  73. ;; +> keyword Type
  74. ;; +> type part
  75. ;;
  76. ;; +> -> click to see additional information
  77. (define-overloadable-function semantic-sb-tag-children-to-expand (tag)
  78. "For TAG, return a list of children that TAG expands to.
  79. If this returns a value, then a +> icon is created.
  80. If it returns nil, then a => icon is created.")
  81. (defun semantic-sb-tag-children-to-expand-default (tag)
  82. "For TAG, the children for type, variable, and function classes."
  83. (semantic-sb-with-tag-buffer tag
  84. (semantic-tag-components tag)))
  85. (defun semantic-sb-one-button (tag depth &optional prefix)
  86. "Insert TAG as a speedbar button at DEPTH.
  87. Optional PREFIX is used to specify special marker characters."
  88. (let* ((class (semantic-tag-class tag))
  89. (edata (semantic-sb-tag-children-to-expand tag))
  90. (type (semantic-tag-type tag))
  91. (abbrev (semantic-sb-with-tag-buffer tag
  92. (funcall semantic-sb-button-format-tag-function tag)))
  93. (start (point))
  94. (end (progn
  95. (insert (int-to-string depth) ":")
  96. (point))))
  97. (insert-char ? (1- depth) nil)
  98. (put-text-property end (point) 'invisible nil)
  99. ;; take care of edata = (nil) -- a yucky but hard to clean case
  100. (if (and edata (listp edata) (and (<= (length edata) 1) (not (car edata))))
  101. (setq edata nil))
  102. (if (and (not edata)
  103. (member class '(variable function))
  104. type)
  105. (setq edata t))
  106. ;; types are a bit unique. Variable types can have special meaning.
  107. (if edata
  108. (speedbar-insert-button (if prefix (concat " +" prefix) " +>")
  109. 'speedbar-button-face
  110. 'speedbar-highlight-face
  111. 'semantic-sb-show-extra
  112. tag t)
  113. (speedbar-insert-button (if prefix (concat " " prefix) " =>")
  114. nil nil nil nil t))
  115. (speedbar-insert-button abbrev
  116. 'speedbar-tag-face
  117. 'speedbar-highlight-face
  118. 'semantic-sb-token-jump
  119. tag t)
  120. ;; This is very bizarre. When this was just after the insertion
  121. ;; of the depth: text, the : would get erased, but only for the
  122. ;; auto-expanded short- buckets. Move back for a later version
  123. ;; version of Emacs 21 CVS
  124. (put-text-property start end 'invisible t)
  125. ))
  126. (defun semantic-sb-speedbar-data-line (depth button text &optional
  127. text-fun text-data)
  128. "Insert a semantic token data element.
  129. DEPTH is the current depth. BUTTON is the text for the button.
  130. TEXT is the actual info with TEXT-FUN to occur when it happens.
  131. Argument TEXT-DATA is the token data to pass to TEXT-FUN."
  132. (let ((start (point))
  133. (end (progn
  134. (insert (int-to-string depth) ":")
  135. (point))))
  136. (put-text-property start end 'invisible t)
  137. (insert-char ? depth nil)
  138. (put-text-property end (point) 'invisible nil)
  139. (speedbar-insert-button button nil nil nil nil t)
  140. (speedbar-insert-button text
  141. 'speedbar-tag-face
  142. (if text-fun 'speedbar-highlight-face)
  143. text-fun text-data t)
  144. ))
  145. (defun semantic-sb-maybe-token-to-button (obj indent &optional
  146. prefix modifiers)
  147. "Convert OBJ, which was returned from the semantic parser, into a button.
  148. This OBJ might be a plain string (simple type or untyped variable)
  149. or a complete tag.
  150. Argument INDENT is the indentation used when making the button.
  151. Optional PREFIX is the character to use when marking the line.
  152. Optional MODIFIERS is additional text needed for variables."
  153. (let ((myprefix (or prefix ">")))
  154. (if (stringp obj)
  155. (semantic-sb-speedbar-data-line indent myprefix obj)
  156. (if (listp obj)
  157. (progn
  158. (if (and (stringp (car obj))
  159. (= (length obj) 1))
  160. (semantic-sb-speedbar-data-line indent myprefix
  161. (concat
  162. (car obj)
  163. (or modifiers "")))
  164. (semantic-sb-one-button obj indent prefix)))))))
  165. (defun semantic-sb-insert-details (tag indent)
  166. "Insert details about TAG at level INDENT."
  167. (let ((tt (semantic-tag-class tag))
  168. (type (semantic-tag-type tag)))
  169. (cond ((eq tt 'type)
  170. (let ((parts (semantic-tag-type-members tag))
  171. (newparts nil))
  172. ;; Lets expect PARTS to be a list of either strings,
  173. ;; or variable tokens.
  174. (when (semantic-tag-p (car parts))
  175. ;; Bucketize into groups
  176. (semantic-sb-with-tag-buffer (car parts)
  177. (setq newparts (semantic-bucketize parts)))
  178. (when (> (length newparts) semantic-sb-autoexpand-length)
  179. ;; More than one bucket, insert inline
  180. (semantic-sb-insert-tag-table (1- indent) newparts)
  181. (setq parts nil))
  182. ;; Dump the strings in.
  183. (while parts
  184. (semantic-sb-maybe-token-to-button (car parts) indent)
  185. (setq parts (cdr parts))))))
  186. ((eq tt 'variable)
  187. (if type
  188. (semantic-sb-maybe-token-to-button type indent "@"))
  189. (let ((default (semantic-tag-variable-default tag)))
  190. (if default
  191. (semantic-sb-maybe-token-to-button default indent "=")))
  192. )
  193. ((eq tt 'function)
  194. (if type
  195. (semantic-sb-speedbar-data-line
  196. indent "@"
  197. (if (stringp type) type
  198. (semantic-tag-name type))))
  199. ;; Arguments to the function
  200. (let ((args (semantic-tag-function-arguments tag)))
  201. (if (and args (car args))
  202. (progn
  203. (semantic-sb-maybe-token-to-button (car args) indent "(")
  204. (setq args (cdr args))
  205. (while (> (length args) 1)
  206. (semantic-sb-maybe-token-to-button (car args)
  207. indent
  208. "|")
  209. (setq args (cdr args)))
  210. (if args
  211. (semantic-sb-maybe-token-to-button
  212. (car args) indent ")"))
  213. ))))
  214. (t
  215. (let ((components
  216. (save-excursion
  217. (when (and (semantic-tag-overlay tag)
  218. (semantic-tag-buffer tag))
  219. (set-buffer (semantic-tag-buffer tag)))
  220. (semantic-sb-tag-children-to-expand tag))))
  221. ;; Well, it wasn't one of the many things we expect.
  222. ;; Lets just insert them in with no decoration.
  223. (while components
  224. (semantic-sb-one-button (car components) indent)
  225. (setq components (cdr components)))
  226. ))
  227. )
  228. ))
  229. (defun semantic-sb-detail-parent ()
  230. "Return the first parent token of the current line that includes a location."
  231. (save-excursion
  232. (beginning-of-line)
  233. (let ((dep (if (looking-at "[0-9]+:")
  234. (1- (string-to-number (match-string 0)))
  235. 0)))
  236. (re-search-backward (concat "^"
  237. (int-to-string dep)
  238. ":")
  239. nil t))
  240. (beginning-of-line)
  241. (if (looking-at "[0-9]+: +[-+][>()@|] \\([^\n]+\\)$")
  242. (let ((prop nil))
  243. (goto-char (match-beginning 1))
  244. (setq prop (get-text-property (point) 'speedbar-token))
  245. (if (semantic-tag-with-position-p prop)
  246. prop
  247. (semantic-sb-detail-parent)))
  248. nil)))
  249. (defun semantic-sb-show-extra (text token indent)
  250. "Display additional information about the token as an expansion.
  251. TEXT TOKEN and INDENT are the details."
  252. (cond ((string-match "+" text) ;we have to expand this file
  253. (speedbar-change-expand-button-char ?-)
  254. (speedbar-with-writable
  255. (save-excursion
  256. (end-of-line) (forward-char 1)
  257. (save-restriction
  258. (narrow-to-region (point) (point))
  259. ;; Add in stuff specific to this type of token.
  260. (semantic-sb-insert-details token (1+ indent))))))
  261. ((string-match "-" text) ;we have to contract this node
  262. (speedbar-change-expand-button-char ?+)
  263. (speedbar-delete-subblock indent))
  264. (t (error "Ooops... not sure what to do")))
  265. (speedbar-center-buffer-smartly))
  266. (defun semantic-sb-token-jump (text token indent)
  267. "Jump to the location specified in token.
  268. TEXT TOKEN and INDENT are the details."
  269. (let ((file
  270. (or
  271. (cond ((fboundp 'speedbar-line-path)
  272. (speedbar-line-directory indent))
  273. ((fboundp 'speedbar-line-directory)
  274. (speedbar-line-directory indent)))
  275. ;; If speedbar cannot figure this out, extract the filename from
  276. ;; the token. True for Analysis mode.
  277. (semantic-tag-file-name token)))
  278. (parent (semantic-sb-detail-parent)))
  279. (let ((f (selected-frame)))
  280. (dframe-select-attached-frame speedbar-frame)
  281. (run-hooks 'speedbar-before-visiting-tag-hook)
  282. (select-frame f))
  283. ;; Sometimes FILE may be nil here. If you are debugging a problem
  284. ;; when this happens, go back and figure out why FILE is nil and try
  285. ;; and fix the source.
  286. (speedbar-find-file-in-frame file)
  287. (save-excursion (speedbar-stealthy-updates))
  288. (semantic-go-to-tag token parent)
  289. (switch-to-buffer (current-buffer))
  290. ;; Reset the timer with a new timeout when clicking a file
  291. ;; in case the user was navigating directories, we can cancel
  292. ;; that other timer.
  293. ;; (speedbar-set-timer dframe-update-speed)
  294. ;;(recenter)
  295. (speedbar-maybee-jump-to-attached-frame)
  296. (run-hooks 'speedbar-visiting-tag-hook)))
  297. (defun semantic-sb-expand-group (text token indent)
  298. "Expand a group which has semantic tokens.
  299. TEXT TOKEN and INDENT are the details."
  300. (cond ((string-match "+" text) ;we have to expand this file
  301. (speedbar-change-expand-button-char ?-)
  302. (speedbar-with-writable
  303. (save-excursion
  304. (end-of-line) (forward-char 1)
  305. (save-restriction
  306. (narrow-to-region (point-min) (point))
  307. (semantic-sb-buttons-plain (1+ indent) token)))))
  308. ((string-match "-" text) ;we have to contract this node
  309. (speedbar-change-expand-button-char ?+)
  310. (speedbar-delete-subblock indent))
  311. (t (error "Ooops... not sure what to do")))
  312. (speedbar-center-buffer-smartly))
  313. (defun semantic-sb-buttons-plain (level tokens)
  314. "Create buttons at LEVEL using TOKENS."
  315. (let ((sordid (speedbar-create-tag-hierarchy tokens)))
  316. (while sordid
  317. (cond ((null (car-safe sordid)) nil)
  318. ((consp (car-safe (cdr-safe (car-safe sordid))))
  319. ;; A group!
  320. (speedbar-make-tag-line 'curly ?+ 'semantic-sb-expand-group
  321. (cdr (car sordid))
  322. (car (car sordid))
  323. nil nil 'speedbar-tag-face
  324. level))
  325. (t ;; Assume that this is a token.
  326. (semantic-sb-one-button (car sordid) level)))
  327. (setq sordid (cdr sordid)))))
  328. (defun semantic-sb-insert-tag-table (level table)
  329. "At LEVEL, insert the tag table TABLE.
  330. Use arcane knowledge about the semantic tokens in the tagged elements
  331. to create much wiser decisions about how to sort and group these items."
  332. (semantic-sb-buttons level table))
  333. (defun semantic-sb-buttons (level lst)
  334. "Create buttons at LEVEL using LST sorting into type buckets."
  335. (save-restriction
  336. (narrow-to-region (point-min) (point))
  337. (let (tmp)
  338. (while lst
  339. (setq tmp (car lst))
  340. (if (cdr tmp)
  341. (if (<= (length (cdr tmp)) semantic-sb-autoexpand-length)
  342. (semantic-sb-buttons-plain (1+ level) (cdr tmp))
  343. (speedbar-make-tag-line 'curly ?+ 'semantic-sb-expand-group
  344. (cdr tmp)
  345. (car (car lst))
  346. nil nil 'speedbar-tag-face
  347. (1+ level))))
  348. (setq lst (cdr lst))))))
  349. (defun semantic-sb-fetch-tag-table (file)
  350. "Load FILE into a buffer, and generate tags using the Semantic parser.
  351. Returns the tag list, or t for an error."
  352. (let ((out nil))
  353. (if (and (featurep 'semantic/db)
  354. (semanticdb-minor-mode-p)
  355. (not speedbar-power-click)
  356. ;; If the database is loaded and running, try to get
  357. ;; tokens from it.
  358. (setq out (semanticdb-file-stream file)))
  359. ;; Successful DB query.
  360. nil
  361. ;; No database, do it the old way.
  362. (with-current-buffer (find-file-noselect file)
  363. (if (or (not (featurep 'semantic))
  364. (not semantic--parse-table))
  365. (setq out t)
  366. (if speedbar-power-click (semantic-clear-toplevel-cache))
  367. (setq out (semantic-fetch-tags)))))
  368. (if (listp out)
  369. (condition-case nil
  370. (progn
  371. ;; This brings externally defined methods into
  372. ;; their classes, and creates meta classes for
  373. ;; orphans.
  374. (setq out (semantic-adopt-external-members out))
  375. ;; Dump all the tokens into buckets.
  376. (semantic-sb-with-tag-buffer (car out)
  377. (semantic-bucketize out)))
  378. (error t))
  379. t)))
  380. ;; Link ourselves into the tagging process.
  381. (add-to-list 'speedbar-dynamic-tags-function-list
  382. '(semantic-sb-fetch-tag-table . semantic-sb-insert-tag-table))
  383. (provide 'semantic/sb)
  384. ;;; semantic/sb.el ends here