mode.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. ;;; srecode/mode.el --- Minor mode for managing and using SRecode templates
  2. ;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric M. Ludlam <eric@siege-engine.com>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;; Minor mode for working with SRecode template files.
  18. ;;
  19. ;; Depends on Semantic for minor-mode convenience functions.
  20. (require 'mode-local)
  21. (require 'srecode)
  22. (require 'srecode/insert)
  23. (require 'srecode/find)
  24. (require 'srecode/map)
  25. (require 'semantic/decorate)
  26. (require 'semantic/wisent)
  27. (eval-when-compile (require 'semantic/find))
  28. ;;; Code:
  29. (defcustom srecode-minor-mode-hook nil
  30. "Hook run at the end of the function `srecode-minor-mode'."
  31. :group 'srecode
  32. :type 'hook)
  33. ;; We don't want to waste space. There is a menu after all.
  34. ;;(add-to-list 'minor-mode-alist '(srecode-minor-mode ""))
  35. (defvar srecode-prefix-key [(control ?c) ?/]
  36. "The common prefix key in srecode minor mode.")
  37. (defvar srecode-prefix-map
  38. (let ((km (make-sparse-keymap)))
  39. ;; Basic template codes
  40. (define-key km "/" 'srecode-insert)
  41. (define-key km [insert] 'srecode-insert)
  42. (define-key km "." 'srecode-insert-again)
  43. (define-key km "E" 'srecode-edit)
  44. ;; Template indirect binding
  45. (let ((k ?a))
  46. (while (<= k ?z)
  47. (define-key km (format "%c" k) 'srecode-bind-insert)
  48. (setq k (1+ k))))
  49. km)
  50. "Keymap used behind the srecode prefix key in srecode minor mode.")
  51. (defvar srecode-menu-bar
  52. (list
  53. "SRecoder"
  54. (semantic-menu-item
  55. ["Insert Template"
  56. srecode-insert
  57. :active t
  58. :help "Insert a template by name."
  59. ])
  60. (semantic-menu-item
  61. ["Insert Template Again"
  62. srecode-insert-again
  63. :active t
  64. :help "Run the same template as last time again."
  65. ])
  66. (semantic-menu-item
  67. ["Edit Template"
  68. srecode-edit
  69. :active t
  70. :help "Edit a template for this language by name."
  71. ])
  72. "---"
  73. '( "Insert ..." :filter srecode-minor-mode-templates-menu )
  74. `( "Generate ..." :filter srecode-minor-mode-generate-menu )
  75. "---"
  76. (semantic-menu-item
  77. ["Customize..."
  78. (customize-group "srecode")
  79. :active t
  80. :help "Customize SRecode options"
  81. ])
  82. (list
  83. "Debugging Tools..."
  84. (semantic-menu-item
  85. ["Dump Template MAP"
  86. srecode-get-maps
  87. :active t
  88. :help "Calculate (if needed) and display the current template file map."
  89. ])
  90. (semantic-menu-item
  91. ["Dump Tables"
  92. srecode-dump-templates
  93. :active t
  94. :help "Dump the current template table."
  95. ])
  96. (semantic-menu-item
  97. ["Dump Dictionary"
  98. srecode-dictionary-dump
  99. :active t
  100. :help "Calculate and dump a dictionary for point."
  101. ])
  102. (semantic-menu-item
  103. ["Show Macro Help"
  104. srecode-macro-help
  105. :active t
  106. :help "Display the different types of macros available."
  107. ])
  108. )
  109. )
  110. "Menu for srecode minor mode.")
  111. (defvar srecode-minor-menu nil
  112. "Menu keymap build from `srecode-menu-bar'.")
  113. (defcustom srecode-takeover-INS-key nil
  114. "Use the insert key for inserting templates."
  115. :group 'srecode
  116. :type 'boolean)
  117. (defvar srecode-mode-map
  118. (let ((km (make-sparse-keymap)))
  119. (define-key km srecode-prefix-key srecode-prefix-map)
  120. (easy-menu-define srecode-minor-menu km "Srecode Minor Mode Menu"
  121. srecode-menu-bar)
  122. (when srecode-takeover-INS-key
  123. (define-key km [insert] srecode-prefix-map))
  124. km)
  125. "Keymap for srecode minor mode.")
  126. ;;;###autoload
  127. (define-minor-mode srecode-minor-mode
  128. "Toggle srecode minor mode.
  129. With prefix argument ARG, turn on if positive, otherwise off. The
  130. minor mode can be turned on only if semantic feature is available and
  131. the current buffer was set up for parsing. Return non-nil if the
  132. minor mode is enabled.
  133. \\{srecode-mode-map}"
  134. :keymap srecode-mode-map
  135. ;; If we are turning things on, make sure we have templates for
  136. ;; this mode first.
  137. (when srecode-minor-mode
  138. (when (not (apply
  139. 'append
  140. (mapcar (lambda (map)
  141. (srecode-map-entries-for-mode map major-mode))
  142. (srecode-get-maps))))
  143. (setq srecode-minor-mode nil))))
  144. ;;;###autoload
  145. (define-minor-mode global-srecode-minor-mode
  146. "Toggle global use of srecode minor mode.
  147. If ARG is positive or nil, enable, if it is negative, disable."
  148. :global t :group 'srecode
  149. ;; Not needed because it's autoloaded instead.
  150. ;; :require 'srecode/mode
  151. (semantic-toggle-minor-mode-globally
  152. 'srecode-minor-mode (if global-srecode-minor-mode 1 -1)))
  153. ;; Use the semantic minor mode magic stuff.
  154. (semantic-add-minor-mode 'srecode-minor-mode "")
  155. ;;; Menu Filters
  156. ;;
  157. (defun srecode-minor-mode-templates-menu (menu-def)
  158. "Create a menu item of cascading filters active for this mode.
  159. MENU-DEF is the menu to bind this into."
  160. ;; Doing this SEGVs Emacs on windows.
  161. ;;(srecode-load-tables-for-mode major-mode)
  162. (let* ((modetable (srecode-get-mode-table major-mode))
  163. (subtab (when modetable (oref modetable :tables)))
  164. (context nil)
  165. (active nil)
  166. (ltab nil)
  167. (temp nil)
  168. (alltabs nil)
  169. )
  170. (if (not subtab)
  171. ;; No tables, show a "load the tables" option.
  172. (list (vector "Load Mode Tables..."
  173. (lambda ()
  174. (interactive)
  175. (srecode-load-tables-for-mode major-mode))
  176. ))
  177. ;; Build something
  178. (setq context (car-safe (srecode-calculate-context)))
  179. (while subtab
  180. (when (srecode-template-table-in-project-p (car subtab))
  181. (setq ltab (oref (car subtab) templates))
  182. (while ltab
  183. (setq temp (car ltab))
  184. ;; Do something with this template.
  185. (let* ((ctxt (oref temp context))
  186. (ctxtcons (assoc ctxt alltabs))
  187. (bind (if (slot-boundp temp 'binding)
  188. (oref temp binding)))
  189. (name (object-name-string temp)))
  190. (when (not ctxtcons)
  191. (if (string= context ctxt)
  192. ;; If this context is not in the current list of contexts
  193. ;; is equal to the current context, then manage the
  194. ;; active list instead
  195. (setq active
  196. (setq ctxtcons (or active (cons ctxt nil))))
  197. ;; This is not an active context, add it to alltabs.
  198. (setq ctxtcons (cons ctxt nil))
  199. (setq alltabs (cons ctxtcons alltabs))))
  200. (let ((new (vector
  201. (if bind
  202. (concat name " (" bind ")")
  203. name)
  204. `(lambda () (interactive)
  205. (srecode-insert (concat ,ctxt ":" ,name)))
  206. t)))
  207. (setcdr ctxtcons (cons
  208. new
  209. (cdr ctxtcons)))))
  210. (setq ltab (cdr ltab))))
  211. (setq subtab (cdr subtab)))
  212. ;; Now create the menu
  213. (easy-menu-filter-return
  214. (easy-menu-create-menu
  215. "Semantic Recoder Filters"
  216. (append (cdr active)
  217. alltabs)
  218. ))
  219. )))
  220. (defvar srecode-minor-mode-generators nil
  221. "List of code generators to be displayed in the srecoder menu.")
  222. (defun srecode-minor-mode-generate-menu (menu-def)
  223. "Create a menu item of cascading filters active for this mode.
  224. MENU-DEF is the menu to bind this into."
  225. ;; Doing this SEGVs Emacs on windows.
  226. ;;(srecode-load-tables-for-mode major-mode)
  227. (let ((allgeneratorapps nil))
  228. (dolist (gen srecode-minor-mode-generators)
  229. (setq allgeneratorapps
  230. (cons (vector (cdr gen) (car gen))
  231. allgeneratorapps))
  232. (message "Adding %S to srecode menu" (car gen))
  233. )
  234. (easy-menu-filter-return
  235. (easy-menu-create-menu
  236. "Semantic Recoder Generate Filters"
  237. allgeneratorapps)))
  238. )
  239. ;;; Minor Mode commands
  240. ;;
  241. (defun srecode-bind-insert ()
  242. "Bound insert for Srecode macros.
  243. This command will insert whichever srecode template has a binding
  244. to the current key."
  245. (interactive)
  246. (srecode-load-tables-for-mode major-mode)
  247. (let* ((k last-command-event)
  248. (ctxt (srecode-calculate-context))
  249. ;; Find the template with the binding K
  250. (template (srecode-template-get-table-for-binding
  251. (srecode-table) k ctxt)))
  252. ;; test it.
  253. (when (not template)
  254. (error "No template bound to %c" k))
  255. ;; insert
  256. (srecode-insert template)
  257. ))
  258. (defun srecode-edit (template-name)
  259. "Switch to the template buffer for TEMPLATE-NAME.
  260. Template is chosen based on the mode of the starting buffer."
  261. ;; @todo - Get a template stack from the last run template, and show
  262. ;; those too!
  263. (interactive (list (srecode-read-template-name
  264. "Template Name: "
  265. (car srecode-read-template-name-history))))
  266. (if (not (srecode-table))
  267. (error "No template table found for mode %s" major-mode))
  268. (let ((temp (srecode-template-get-table (srecode-table) template-name)))
  269. (if (not temp)
  270. (error "No Template named %s" template-name))
  271. ;; We need a template specific table, since tables chain.
  272. (let ((tab (oref temp :table))
  273. (names nil)
  274. )
  275. (find-file (oref tab :file))
  276. (setq names (semantic-find-tags-by-name (oref temp :object-name)
  277. (current-buffer)))
  278. (cond ((= (length names) 1)
  279. (semantic-go-to-tag (car names))
  280. (semantic-momentary-highlight-tag (car names)))
  281. ((> (length names) 1)
  282. (let* ((ctxt (semantic-find-tags-by-name (oref temp :context)
  283. (current-buffer)))
  284. (cls (semantic-find-tags-by-class 'context ctxt))
  285. )
  286. (while (and names
  287. (< (semantic-tag-start (car names))
  288. (semantic-tag-start (car cls))))
  289. (setq names (cdr names)))
  290. (if names
  291. (progn
  292. (semantic-go-to-tag (car names))
  293. (semantic-momentary-highlight-tag (car names)))
  294. (error "Can't find template %s" template-name))
  295. ))
  296. (t (error "Can't find template %s" template-name)))
  297. )))
  298. (defun srecode-add-code-generator (function name &optional binding)
  299. "Add the srecoder code generator FUNCTION with NAME to the menu.
  300. Optional BINDING specifies the keybinding to use in the srecoder map.
  301. BINDING should be a capital letter. Lower case letters are reserved
  302. for individual templates.
  303. Optional MODE specifies a major mode this function applies to.
  304. Do not specify a mode if this function could be applied to most
  305. programming modes."
  306. ;; Update the menu generating part.
  307. (let ((remloop nil))
  308. (while (setq remloop (assoc function srecode-minor-mode-generators))
  309. (setq srecode-minor-mode-generators
  310. (remove remloop srecode-minor-mode-generators))))
  311. (add-to-list 'srecode-minor-mode-generators
  312. (cons function name))
  313. ;; Remove this function from any old bindings.
  314. (when binding
  315. (let ((oldkey (where-is-internal function
  316. (list srecode-prefix-map)
  317. t t t)))
  318. (if (or (not oldkey)
  319. (and (= (length oldkey) 1)
  320. (= (length binding) 1)
  321. (= (aref oldkey 0) (aref binding 0))))
  322. ;; Its the same.
  323. nil
  324. ;; Remove the old binding
  325. (define-key srecode-prefix-map oldkey nil)
  326. )))
  327. ;; Update Keybindings
  328. (let ((oldbinding (lookup-key srecode-prefix-map binding)))
  329. ;; During development, allow overrides.
  330. (when (and oldbinding
  331. (not (eq oldbinding function))
  332. (or (eq this-command 'eval-defun) (eq this-command 'checkdoc-eval-defun))
  333. (y-or-n-p (format "Override old binding %s? " oldbinding)))
  334. (setq oldbinding nil))
  335. (if (not oldbinding)
  336. (define-key srecode-prefix-map binding function)
  337. (if (eq function oldbinding)
  338. nil
  339. ;; Not the same.
  340. (message "Conflict binding %S binding to srecode map."
  341. binding))))
  342. )
  343. ;; Add default code generators:
  344. (srecode-add-code-generator 'srecode-document-insert-comment "Comments" "C")
  345. (srecode-add-code-generator 'srecode-insert-getset "Get/Set" "G")
  346. (provide 'srecode/mode)
  347. ;; Local variables:
  348. ;; generated-autoload-file: "loaddefs.el"
  349. ;; generated-autoload-load-name: "srecode/mode"
  350. ;; End:
  351. ;;; srecode/mode.el ends here