PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/el/el-lib/generic.el

https://github.com/joelagnel/lisp
Emacs Lisp | 321 lines | 156 code | 45 blank | 120 comment | 10 complexity | 91df897f6212cff32646b88679355a12 MD5 | raw file
Possible License(s): GPL-2.0, MIT, BSD-3-Clause, MPL-2.0, AGPL-1.0, GPL-3.0
  1. ;;; generic.el --- defining simple major modes with comment and font-lock
  2. ;;
  3. ;; Copyright (C) 1997, 1999, 2002, 2003, 2004,
  4. ;; 2005, 2006 Free Software Foundation, Inc.
  5. ;;
  6. ;; Author: Peter Breton <pbreton@cs.umb.edu>
  7. ;; Created: Fri Sep 27 1996
  8. ;; Keywords: generic, comment, font-lock
  9. ;; This file is part of GNU Emacs.
  10. ;; GNU Emacs is free software; you can redistribute it and/or modify
  11. ;; it under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  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. ;; You should have received a copy of the GNU General Public License
  19. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  20. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. ;; Boston, MA 02110-1301, USA.
  22. ;;; Commentary:
  23. ;; INTRODUCTION:
  24. ;;
  25. ;; The macro `define-generic-mode' can be used to define small modes
  26. ;; which provide basic comment and font-lock support. These modes are
  27. ;; intended for the many configuration files and such which are too
  28. ;; small for a "real" mode, but still have a regular syntax, comment
  29. ;; characters and the like.
  30. ;;
  31. ;; Each generic mode can define the following:
  32. ;;
  33. ;; * List of comment-characters. The elements of this list should be
  34. ;; either a character, a one or two character string, or a cons
  35. ;; cell. If the entry is a character or a string, it is added to
  36. ;; the mode's syntax table with "comment starter" syntax. If the
  37. ;; entry is a cons cell, the `car' and `cdr' of the pair are
  38. ;; considered the "comment starter" and "comment ender"
  39. ;; respectively. (The latter should be nil if you want comments to
  40. ;; end at the end of the line.) Emacs does not support comment
  41. ;; strings of more than two characters in length.
  42. ;;
  43. ;; * List of keywords to font-lock. Each keyword should be a string.
  44. ;; If you have additional keywords which should be highlighted in a
  45. ;; face different from `font-lock-keyword-face', you can use the
  46. ;; convenience function `generic-make-keywords-list' (which see),
  47. ;; and add the result to the following list:
  48. ;;
  49. ;; * Additional expressions to font-lock. This should be a list of
  50. ;; expressions, each of which should be of the same form as those in
  51. ;; `font-lock-keywords'.
  52. ;;
  53. ;; * List of regular expressions to be placed in auto-mode-alist.
  54. ;;
  55. ;; * List of functions to call to do some additional setup
  56. ;;
  57. ;; This should pretty much cover basic functionality; if you need much
  58. ;; more than this, or you find yourself writing extensive customizations,
  59. ;; perhaps you should be writing a major mode instead!
  60. ;;
  61. ;; EXAMPLE:
  62. ;;
  63. ;; You can use `define-generic-mode' like this:
  64. ;;
  65. ;; (define-generic-mode 'foo-generic-mode
  66. ;; (list ?%)
  67. ;; (list "keyword")
  68. ;; nil
  69. ;; (list "\\.FOO\\'")
  70. ;; (list 'foo-setup-function))
  71. ;;
  72. ;; to define a new generic-mode `foo-generic-mode', which has '%' as a
  73. ;; comment character, and "keyword" as a keyword. When files which
  74. ;; end in '.FOO' are loaded, Emacs will go into foo-generic-mode and
  75. ;; call foo-setup-function. You can also use the function
  76. ;; `foo-generic-mode' (which is interactive) to put a buffer into
  77. ;; foo-generic-mode.
  78. ;;
  79. ;; GOTCHAS:
  80. ;;
  81. ;; Be careful that your font-lock definitions are correct. Getting
  82. ;; them wrong can cause Emacs to continually attempt to fontify! This
  83. ;; problem is not specific to generic-mode.
  84. ;; Credit for suggestions, brainstorming, help with debugging:
  85. ;; ACorreir@pervasive-sw.com (Alfred Correira)
  86. ;; Extensive cleanup by:
  87. ;; Stefan Monnier (monnier+gnu/emacs@flint.cs.yale.edu)
  88. ;;; Code:
  89. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  90. ;; Internal Variables
  91. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  92. (defvar generic-font-lock-keywords nil
  93. "Keywords for `font-lock-defaults' in a generic mode.")
  94. (make-variable-buffer-local 'generic-font-lock-keywords)
  95. (define-obsolete-variable-alias 'generic-font-lock-defaults 'generic-font-lock-keywords "22.1")
  96. ;;;###autoload
  97. (defvar generic-mode-list nil
  98. "A list of mode names for `generic-mode'.
  99. Do not add entries to this list directly; use `define-generic-mode'
  100. instead (which see).")
  101. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  102. ;; Functions
  103. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  104. ;;;###autoload
  105. (defmacro define-generic-mode (mode comment-list keyword-list
  106. font-lock-list auto-mode-list
  107. function-list &optional docstring)
  108. "Create a new generic mode MODE.
  109. MODE is the name of the command for the generic mode; don't quote it.
  110. The optional DOCSTRING is the documentation for the mode command. If
  111. you do not supply it, `define-generic-mode' uses a default
  112. documentation string instead.
  113. COMMENT-LIST is a list in which each element is either a character, a
  114. string of one or two characters, or a cons cell. A character or a
  115. string is set up in the mode's syntax table as a \"comment starter\".
  116. If the entry is a cons cell, the `car' is set up as a \"comment
  117. starter\" and the `cdr' as a \"comment ender\". (Use nil for the
  118. latter if you want comments to end at the end of the line.) Note that
  119. the syntax table has limitations about what comment starters and
  120. enders are actually possible.
  121. KEYWORD-LIST is a list of keywords to highlight with
  122. `font-lock-keyword-face'. Each keyword should be a string.
  123. FONT-LOCK-LIST is a list of additional expressions to highlight. Each
  124. element of this list should have the same form as an element of
  125. `font-lock-keywords'.
  126. AUTO-MODE-LIST is a list of regular expressions to add to
  127. `auto-mode-alist'. These regular expressions are added when Emacs
  128. runs the macro expansion.
  129. FUNCTION-LIST is a list of functions to call to do some additional
  130. setup. The mode command calls these functions just before it runs the
  131. mode hook `MODE-hook'.
  132. See the file generic-x.el for some examples of `define-generic-mode'."
  133. (declare (debug (sexp def-form def-form def-form form def-form
  134. [&optional stringp] &rest [keywordp form]))
  135. (indent 1))
  136. ;; Backward compatibility.
  137. (when (eq (car-safe mode) 'quote)
  138. (setq mode (eval mode)))
  139. (let* ((name (symbol-name mode))
  140. (pretty-name (capitalize (replace-regexp-in-string
  141. "-mode\\'" "" name))))
  142. `(progn
  143. ;; Add a new entry.
  144. (add-to-list 'generic-mode-list ,name)
  145. ;; Add it to auto-mode-alist
  146. (dolist (re ,auto-mode-list)
  147. (add-to-list 'auto-mode-alist (cons re ',mode)))
  148. (defun ,mode ()
  149. ,(or docstring
  150. (concat pretty-name " mode.\n"
  151. "This a generic mode defined with `define-generic-mode'.\n"
  152. "It runs `" name "-hook' as the last thing it does."))
  153. (interactive)
  154. (generic-mode-internal ',mode ,comment-list ,keyword-list
  155. ,font-lock-list ,function-list)))))
  156. ;;;###autoload
  157. (defun generic-mode-internal (mode comment-list keyword-list
  158. font-lock-list function-list)
  159. "Go into the generic mode MODE."
  160. (let* ((name (symbol-name mode))
  161. (pretty-name (capitalize (replace-regexp-in-string
  162. "-mode\\'" "" name)))
  163. (mode-hook (intern (concat name "-hook"))))
  164. (kill-all-local-variables)
  165. (setq major-mode mode
  166. mode-name pretty-name)
  167. (generic-mode-set-comments comment-list)
  168. ;; Font-lock functionality.
  169. ;; Font-lock-defaults is always set even if there are no keywords
  170. ;; or font-lock expressions, so comments can be highlighted.
  171. (setq generic-font-lock-keywords font-lock-list)
  172. (when keyword-list
  173. (push (concat "\\_<" (regexp-opt keyword-list t) "\\_>")
  174. generic-font-lock-keywords))
  175. (setq font-lock-defaults '(generic-font-lock-keywords))
  176. ;; Call a list of functions
  177. (mapcar 'funcall function-list)
  178. (run-mode-hooks mode-hook)))
  179. ;;;###autoload
  180. (defun generic-mode (mode)
  181. "Enter generic mode MODE.
  182. Generic modes provide basic comment and font-lock functionality
  183. for \"generic\" files. (Files which are too small to warrant their
  184. own mode, but have comment characters, keywords, and the like.)
  185. To define a generic-mode, use the function `define-generic-mode'.
  186. Some generic modes are defined in `generic-x.el'."
  187. (interactive
  188. (list (completing-read "Generic mode: " generic-mode-list nil t)))
  189. (funcall (intern mode)))
  190. ;;; Comment Functionality
  191. (defun generic-mode-set-comments (comment-list)
  192. "Set up comment functionality for generic mode."
  193. (let ((st (make-syntax-table))
  194. (chars nil)
  195. (comstyles))
  196. (make-local-variable 'comment-start)
  197. (make-local-variable 'comment-start-skip)
  198. (make-local-variable 'comment-end)
  199. ;; Go through all the comments
  200. (dolist (start comment-list)
  201. (let (end (comstyle ""))
  202. ;; Normalize
  203. (when (consp start)
  204. (setq end (cdr start))
  205. (setq start (car start)))
  206. (when (characterp start) (setq start (char-to-string start)))
  207. (cond
  208. ((characterp end) (setq end (char-to-string end)))
  209. ((zerop (length end)) (setq end "\n")))
  210. ;; Setup the vars for `comment-region'
  211. (if comment-start
  212. ;; We have already setup a comment-style, so use style b
  213. (progn
  214. (setq comstyle "b")
  215. (setq comment-start-skip
  216. (concat comment-start-skip "\\|" (regexp-quote start) "+\\s-*")))
  217. ;; First comment-style
  218. (setq comment-start start)
  219. (setq comment-end (if (string-equal end "\n") "" end))
  220. (setq comment-start-skip (concat (regexp-quote start) "+\\s-*")))
  221. ;; Reuse comstyles if necessary
  222. (setq comstyle
  223. (or (cdr (assoc start comstyles))
  224. (cdr (assoc end comstyles))
  225. comstyle))
  226. (push (cons start comstyle) comstyles)
  227. (push (cons end comstyle) comstyles)
  228. ;; Setup the syntax table
  229. (if (= (length start) 1)
  230. (modify-syntax-entry (string-to-char start)
  231. (concat "< " comstyle) st)
  232. (let ((c0 (elt start 0)) (c1 (elt start 1)))
  233. ;; Store the relevant info but don't update yet
  234. (push (cons c0 (concat (cdr (assoc c0 chars)) "1")) chars)
  235. (push (cons c1 (concat (cdr (assoc c1 chars))
  236. (concat "2" comstyle))) chars)))
  237. (if (= (length end) 1)
  238. (modify-syntax-entry (string-to-char end)
  239. (concat ">" comstyle) st)
  240. (let ((c0 (elt end 0)) (c1 (elt end 1)))
  241. ;; Store the relevant info but don't update yet
  242. (push (cons c0 (concat (cdr (assoc c0 chars))
  243. (concat "3" comstyle))) chars)
  244. (push (cons c1 (concat (cdr (assoc c1 chars)) "4")) chars)))))
  245. ;; Process the chars that were part of a 2-char comment marker
  246. (dolist (cs (nreverse chars))
  247. (modify-syntax-entry (car cs)
  248. (concat (char-to-string (char-syntax (car cs)))
  249. " " (cdr cs))
  250. st))
  251. (set-syntax-table st)))
  252. (defun generic-bracket-support ()
  253. "Imenu support for [KEYWORD] constructs found in INF, INI and Samba files."
  254. (setq imenu-generic-expression
  255. '((nil "^\\[\\(.*\\)\\]" 1))
  256. imenu-case-fold-search t))
  257. ;;;###autoload
  258. (defun generic-make-keywords-list (keyword-list face &optional prefix suffix)
  259. "Return a `font-lock-keywords' construct that highlights KEYWORD-LIST.
  260. KEYWORD-LIST is a list of keyword strings that should be
  261. highlighted with face FACE. This function calculates a regular
  262. expression that matches these keywords and concatenates it with
  263. PREFIX and SUFFIX. Then it returns a construct based on this
  264. regular expression that can be used as an element of
  265. `font-lock-keywords'."
  266. (unless (listp keyword-list)
  267. (error "Keywords argument must be a list of strings"))
  268. (list (concat prefix "\\_<"
  269. ;; Use an optimized regexp.
  270. (regexp-opt keyword-list t)
  271. "\\_>" suffix)
  272. 1
  273. face))
  274. (provide 'generic)
  275. ;; arch-tag: 239c1fc4-1303-48d9-9ac0-657d655669ea
  276. ;;; generic.el ends here