speedbar.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. ;;; ede/speedbar.el --- Speedbar viewing of EDE projects
  2. ;; Copyright (C) 1998-2001, 2003, 2005, 2007-2012
  3. ;; Free Software Foundation, Inc.
  4. ;; Author: Eric M. Ludlam <zappo@gnu.org>
  5. ;; Keywords: project, make, tags
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;
  19. ;; Display a project's hierarchy in speedbar.
  20. ;;
  21. ;;; Code:
  22. (eval-when-compile (require 'cl))
  23. (require 'speedbar)
  24. (require 'eieio-speedbar)
  25. (require 'ede)
  26. ;;; Speedbar support mode
  27. ;;
  28. (defvar ede-speedbar-key-map nil
  29. "A Generic object based speedbar display keymap.")
  30. (defun ede-speedbar-make-map ()
  31. "Make the generic object based speedbar keymap."
  32. (setq ede-speedbar-key-map (speedbar-make-specialized-keymap))
  33. ;; General viewing things
  34. (define-key ede-speedbar-key-map "\C-m" 'speedbar-edit-line)
  35. (define-key ede-speedbar-key-map "+" 'speedbar-expand-line)
  36. (define-key ede-speedbar-key-map "=" 'speedbar-expand-line)
  37. (define-key ede-speedbar-key-map "-" 'speedbar-contract-line)
  38. (define-key ede-speedbar-key-map " " 'speedbar-toggle-line-expansion)
  39. ;; Some object based things
  40. (define-key ede-speedbar-key-map "C" 'eieio-speedbar-customize-line)
  41. ;; Some project based things
  42. (define-key ede-speedbar-key-map "R" 'ede-speedbar-remove-file-from-target)
  43. (define-key ede-speedbar-key-map "b" 'ede-speedbar-compile-line)
  44. (define-key ede-speedbar-key-map "B" 'ede-speedbar-compile-project)
  45. (define-key ede-speedbar-key-map "D" 'ede-speedbar-make-distribution)
  46. (define-key ede-speedbar-key-map "E" 'ede-speedbar-edit-projectfile)
  47. )
  48. (defvar ede-speedbar-menu
  49. '([ "Compile" ede-speedbar-compile-line t]
  50. [ "Compile Project" ede-speedbar-compile-project
  51. (ede-project-child-p (speedbar-line-token)) ]
  52. "---"
  53. [ "Edit File/Tag" speedbar-edit-line
  54. (not (eieio-object-p (speedbar-line-token)))]
  55. [ "Expand" speedbar-expand-line
  56. (save-excursion (beginning-of-line)
  57. (looking-at "[0-9]+: *.\\+. "))]
  58. [ "Contract" speedbar-contract-line
  59. (save-excursion (beginning-of-line)
  60. (looking-at "[0-9]+: *.-. "))]
  61. "---"
  62. [ "Remove File from Target" ede-speedbar-remove-file-from-target
  63. (stringp (speedbar-line-token)) ]
  64. [ "Customize Project/Target" eieio-speedbar-customize-line
  65. (eieio-object-p (speedbar-line-token)) ]
  66. [ "Edit Project File" ede-speedbar-edit-projectfile t]
  67. [ "Make Distribution" ede-speedbar-make-distribution
  68. (ede-project-child-p (speedbar-line-token)) ]
  69. )
  70. "Menu part in easymenu format used in speedbar while browsing objects.")
  71. (eieio-speedbar-create 'ede-speedbar-make-map
  72. 'ede-speedbar-key-map
  73. 'ede-speedbar-menu
  74. "Project"
  75. 'ede-speedbar-toplevel-buttons)
  76. (defun ede-speedbar ()
  77. "EDE development environment project browser for speedbar."
  78. (interactive)
  79. (speedbar-frame-mode 1)
  80. (speedbar-change-initial-expansion-list "Project")
  81. (speedbar-get-focus)
  82. )
  83. (defun ede-speedbar-toplevel-buttons (dir)
  84. "Return a list of objects to display in speedbar.
  85. Argument DIR is the directory from which to derive the list of objects."
  86. ede-projects
  87. )
  88. ;;; Some special commands useful in EDE
  89. ;;
  90. (defun ede-speedbar-remove-file-from-target ()
  91. "Remove the file at point from its target."
  92. (interactive)
  93. (if (stringp (speedbar-line-token))
  94. (progn
  95. (speedbar-edit-line)
  96. (ede-remove-file))))
  97. (defun ede-speedbar-compile-line ()
  98. "Compile/Build the project or target on this line."
  99. (interactive)
  100. (let ((obj (eieio-speedbar-find-nearest-object)))
  101. (if (not (eieio-object-p obj))
  102. nil
  103. (cond ((obj-of-class-p obj ede-project)
  104. (project-compile-project obj))
  105. ((obj-of-class-p obj ede-target)
  106. (project-compile-target obj))
  107. (t (error "Error in speedbar structure"))))))
  108. (defun ede-speedbar-get-top-project-for-line ()
  109. "Return a project object for this line."
  110. (interactive)
  111. (let ((obj (eieio-speedbar-find-nearest-object)))
  112. (if (not (eieio-object-p obj))
  113. (error "Error in speedbar or ede structure")
  114. (if (obj-of-class-p obj ede-target)
  115. (setq obj (ede-target-parent obj)))
  116. (if (obj-of-class-p obj ede-project)
  117. obj
  118. (error "Error in speedbar or ede structure")))))
  119. (defun ede-speedbar-compile-project ()
  120. "Compile/Build the project which owns this line."
  121. (interactive)
  122. (project-compile-project (ede-speedbar-get-top-project-for-line)))
  123. (defun ede-speedbar-compile-file-project ()
  124. "Compile/Build the target which the current file belongs to."
  125. (interactive)
  126. (let* ((file (speedbar-line-file))
  127. (buf (find-file-noselect file))
  128. (bwin (get-buffer-window buf 0)))
  129. (if bwin
  130. (progn
  131. (select-window bwin)
  132. (raise-frame (window-frame bwin)))
  133. (dframe-select-attached-frame speedbar-frame)
  134. (set-buffer buf)
  135. (ede-compile-target))))
  136. (defun ede-speedbar-make-distribution ()
  137. "Edit the project file based on this line."
  138. (interactive)
  139. (project-make-dist (ede-speedbar-get-top-project-for-line)))
  140. (defun ede-speedbar-edit-projectfile ()
  141. "Edit the project file based on this line."
  142. (interactive)
  143. (project-edit-file-target (ede-speedbar-get-top-project-for-line)))
  144. ;;; Speedbar Project Methods
  145. ;;
  146. (defun ede-find-nearest-file-line ()
  147. "Go backwards until we find a file."
  148. (save-excursion
  149. (beginning-of-line)
  150. (looking-at "^\\([0-9]+\\):")
  151. (let ((depth (string-to-number (match-string 1))))
  152. (while (not (re-search-forward "[]] [^ ]" (point-at-eol) t))
  153. (re-search-backward (format "^%d:" (1- depth)))
  154. (setq depth (1- depth)))
  155. (speedbar-line-token))))
  156. (defmethod eieio-speedbar-derive-line-path ((obj ede-project) &optional depth)
  157. "Return the path to OBJ.
  158. Optional DEPTH is the depth we start at."
  159. (file-name-directory (oref obj file))
  160. )
  161. (defmethod eieio-speedbar-derive-line-path ((obj ede-target) &optional depth)
  162. "Return the path to OBJ.
  163. Optional DEPTH is the depth we start at."
  164. (let ((proj (ede-target-parent obj)))
  165. ;; Check the type of line we are currently on.
  166. ;; If we are on a child, we need a file name too.
  167. (save-excursion
  168. (let ((lt (speedbar-line-token)))
  169. (if (or (eieio-object-p lt) (stringp lt))
  170. (eieio-speedbar-derive-line-path proj)
  171. ;; a child element is a token. Do some work to get a filename too.
  172. (concat (eieio-speedbar-derive-line-path proj)
  173. (ede-find-nearest-file-line)))))))
  174. (defmethod eieio-speedbar-description ((obj ede-project))
  175. "Provide a speedbar description for OBJ."
  176. (ede-description obj))
  177. (defmethod eieio-speedbar-description ((obj ede-target))
  178. "Provide a speedbar description for OBJ."
  179. (ede-description obj))
  180. (defmethod eieio-speedbar-child-description ((obj ede-target))
  181. "Provide a speedbar description for a plain-child of OBJ.
  182. A plain child is a child element which is not an EIEIO object."
  183. (or (speedbar-item-info-file-helper)
  184. (speedbar-item-info-tag-helper)))
  185. (defmethod eieio-speedbar-object-buttonname ((object ede-project))
  186. "Return a string to use as a speedbar button for OBJECT."
  187. (if (ede-parent-project object)
  188. (ede-name object)
  189. (concat (ede-name object) " " (oref object version))))
  190. (defmethod eieio-speedbar-object-buttonname ((object ede-target))
  191. "Return a string to use as a speedbar button for OBJECT."
  192. (ede-name object))
  193. (defmethod eieio-speedbar-object-children ((this ede-project))
  194. "Return the list of speedbar display children for THIS."
  195. (condition-case nil
  196. (with-slots (subproj targets) this
  197. (append subproj targets))
  198. (error nil)))
  199. (defmethod eieio-speedbar-object-children ((this ede-target))
  200. "Return the list of speedbar display children for THIS."
  201. (oref this source))
  202. (defmethod eieio-speedbar-child-make-tag-lines ((this ede-target) depth)
  203. "Create a speedbar tag line for a child of THIS.
  204. It has depth DEPTH."
  205. (with-slots (source) this
  206. (mapcar (lambda (car)
  207. (speedbar-make-tag-line 'bracket ?+
  208. 'speedbar-tag-file
  209. car
  210. car
  211. 'ede-file-find
  212. car
  213. 'speedbar-file-face depth))
  214. source)))
  215. ;;; Generic file management for TARGETS
  216. ;;
  217. (defun ede-file-find (text token indent)
  218. "Find the file TEXT at path TOKEN.
  219. INDENT is the current indentation level."
  220. (speedbar-find-file-in-frame
  221. (expand-file-name token (speedbar-line-directory indent)))
  222. (speedbar-maybee-jump-to-attached-frame))
  223. (defun ede-create-tag-buttons (filename indent)
  224. "Create the tag buttons associated with FILENAME at INDENT."
  225. (let* ((lst (speedbar-fetch-dynamic-tags filename)))
  226. ;; if no list, then remove expando button
  227. (if (not lst)
  228. (speedbar-change-expand-button-char ??)
  229. (speedbar-with-writable
  230. ;; We must do 1- because indent was already incremented.
  231. (speedbar-insert-generic-list (1- indent)
  232. lst
  233. 'ede-tag-expand
  234. 'ede-tag-find)))))
  235. (defun ede-tag-expand (text token indent)
  236. "Expand a tag sublist. Imenu will return sub-lists of specialized tag types.
  237. Etags does not support this feature. TEXT will be the button
  238. string. TOKEN will be the list, and INDENT is the current indentation
  239. level."
  240. (cond ((string-match "+" text) ;we have to expand this file
  241. (speedbar-change-expand-button-char ?-)
  242. (speedbar-with-writable
  243. (save-excursion
  244. (end-of-line) (forward-char 1)
  245. (speedbar-insert-generic-list indent token
  246. 'ede-tag-expand
  247. 'ede-tag-find))))
  248. ((string-match "-" text) ;we have to contract this node
  249. (speedbar-change-expand-button-char ?+)
  250. (speedbar-delete-subblock indent))
  251. (t (error "Ooops... not sure what to do")))
  252. (speedbar-center-buffer-smartly))
  253. (defun ede-tag-find (text token indent)
  254. "For the tag TEXT in a file TOKEN, goto that position.
  255. INDENT is the current indentation level."
  256. (let ((file (ede-find-nearest-file-line)))
  257. (speedbar-find-file-in-frame file)
  258. (save-excursion (speedbar-stealthy-updates))
  259. ;; Reset the timer with a new timeout when clicking a file
  260. ;; in case the user was navigating directories, we can cancel
  261. ;; that other timer.
  262. ; (speedbar-set-timer speedbar-update-speed)
  263. (goto-char token)
  264. (run-hooks 'speedbar-visiting-tag-hook)
  265. ;;(recenter)
  266. (speedbar-maybee-jump-to-attached-frame)
  267. ))
  268. ;;; EDE and the speedbar FILE display
  269. ;;
  270. ;; This will add a couple keybindings and menu items into the
  271. ;; FILE display for speedbar.
  272. (defvar ede-speedbar-file-menu-additions
  273. '("----"
  274. ["Create EDE Target" ede-new-target (ede-current-project) ]
  275. ["Add to project" ede-speedbar-file-add-to-project (ede-current-project) ]
  276. ["Compile project" ede-speedbar-compile-project (ede-current-project) ]
  277. ["Compile file target" ede-speedbar-compile-file-target (ede-current-project) ]
  278. ["Make distribution" ede-make-dist (ede-current-project) ]
  279. )
  280. "Set of menu items to splice into the speedbar menu.")
  281. (defvar ede-speedbar-file-keymap
  282. (let ((km (make-sparse-keymap)))
  283. (define-key km "a" 'ede-speedbar-file-add-to-project)
  284. (define-key km "t" 'ede-new-target)
  285. (define-key km "s" 'ede-speedbar)
  286. (define-key km "C" 'ede-speedbar-compile-project)
  287. (define-key km "c" 'ede-speedbar-compile-file-target)
  288. (define-key km "d" 'ede-make-dist)
  289. km)
  290. "Keymap spliced into the speedbar keymap.")
  291. ;;;###autoload
  292. (defun ede-speedbar-file-setup ()
  293. "Setup some keybindings in the Speedbar File display."
  294. (setq speedbar-easymenu-definition-special
  295. (append speedbar-easymenu-definition-special
  296. ede-speedbar-file-menu-additions
  297. ))
  298. (define-key speedbar-file-key-map "." ede-speedbar-file-keymap)
  299. ;; Finally, if the FILES mode is loaded, force a refresh
  300. ;; of the menus and such.
  301. (when (and (string= speedbar-initial-expansion-list-name "files")
  302. (buffer-live-p speedbar-buffer)
  303. )
  304. (speedbar-change-initial-expansion-list "files")))
  305. (provide 'ede/speedbar)
  306. ;; Local variables:
  307. ;; generated-autoload-file: "loaddefs.el"
  308. ;; generated-autoload-load-name: "ede/speedbar"
  309. ;; End:
  310. ;;; ede/speedbar.el ends here