aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/emacs-lisp/generic.el
diff options
context:
space:
mode:
authorMiles Bader <[email protected]>2005-04-14 05:03:52 +0000
committerMiles Bader <[email protected]>2005-04-14 05:03:52 +0000
commit4a4ae7ad21e9e53ed9a0006c39d69108333bc896 (patch)
tree514ec70cdfdd49c518599e15b8fdf1e85850e7d7 /lisp/emacs-lisp/generic.el
parent6f14f88410854410caf4b402cfbe0f93a80c3f86 (diff)
parent24531f226fb1150c3a52a3ebf9273d1af36062ea (diff)
Revision: [email protected]/emacs--unicode--0--patch-37
Merge from emacs--cvs-trunk--0 Patches applied: * emacs--cvs-trunk--0 (patch 241-257) - Update from CVS - Merge from gnus--rel--5.10 * gnus--rel--5.10 (patch 59-65) - Update from CVS - Merge from emacs--cvs-trunk--0 - (mm-string-to-multibyte): Use Gnus trunk definition.
Diffstat (limited to 'lisp/emacs-lisp/generic.el')
-rw-r--r--lisp/emacs-lisp/generic.el345
1 files changed, 345 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/generic.el b/lisp/emacs-lisp/generic.el
new file mode 100644
index 0000000000..6851faeddd
--- /dev/null
+++ b/lisp/emacs-lisp/generic.el
@@ -0,0 +1,345 @@
+;;; generic.el --- defining simple major modes with comment and font-lock
+;;
+;; Copyright (C) 1997, 1999, 2004, 2005 Free Software Foundation, Inc.
+;;
+;; Author: Peter Breton <[email protected]>
+;; Created: Fri Sep 27 1996
+;; Keywords: generic, comment, font-lock
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; INTRODUCTION:
+;;
+;; The macro `define-generic-mode' can be used to define small modes
+;; which provide basic comment and font-lock support. These modes are
+;; intended for the many configuration files and such which are too
+;; small for a "real" mode, but still have a regular syntax, comment
+;; characters and the like.
+;;
+;; Each generic mode can define the following:
+;;
+;; * List of comment-characters. The entries in this list should be
+;; either a character, a one or two character string or a cons pair.
+;; If the entry is a character or a string, it is added to the
+;; mode's syntax table with `comment-start' syntax. If the entry is
+;; a cons pair, the elements of the pair are considered to be
+;; `comment-start' and `comment-end' respectively. (The latter
+;; should be nil if you want comments to end at end of line.)
+;; LIMITATIONS: Emacs does not support comment strings of more than
+;; two characters in length.
+;;
+;; * List of keywords to font-lock. Each keyword should be a string.
+;; If you have additional keywords which should be highlighted in a
+;; face different from `font-lock-keyword-face', you can use the
+;; convenience function `generic-make-keywords-list' (which see),
+;; and add the result to the following list:
+;;
+;; * Additional expressions to font-lock. This should be a list of
+;; expressions, each of which should be of the same form as those in
+;; `font-lock-keywords'.
+;;
+;; * List of regular expressions to be placed in auto-mode-alist.
+;;
+;; * List of functions to call to do some additional setup
+;;
+;; This should pretty much cover basic functionality; if you need much
+;; more than this, or you find yourself writing extensive customizations,
+;; perhaps you should be writing a major mode instead!
+;;
+;; EXAMPLE:
+;;
+;; You can use `define-generic-mode' like this:
+;;
+;; (define-generic-mode 'foo-generic-mode
+;; (list ?%)
+;; (list "keyword")
+;; nil
+;; (list "\\.FOO\\'")
+;; (list 'foo-setup-function))
+;;
+;; to define a new generic-mode `foo-generic-mode', which has '%' as a
+;; comment character, and "keyword" as a keyword. When files which
+;; end in '.FOO' are loaded, Emacs will go into foo-generic-mode and
+;; call foo-setup-function. You can also use the function
+;; `foo-generic-mode' (which is interactive) to put a buffer into
+;; foo-generic-mode.
+;;
+;; GOTCHAS:
+;;
+;; Be careful that your font-lock definitions are correct. Getting
+;; them wrong can cause Emacs to continually attempt to fontify! This
+;; problem is not specific to generic-mode.
+
+;; Credit for suggestions, brainstorming, help with debugging:
+;; [email protected] (Alfred Correira)
+;; Extensive cleanup by:
+;; Stefan Monnier (monnier+gnu/[email protected])
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Internal Variables
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar generic-font-lock-keywords nil
+ "Keywords for `font-lock-defaults' in a generic mode.")
+(make-variable-buffer-local 'generic-font-lock-keywords)
+(defvaralias 'generic-font-lock-defaults 'generic-font-lock-keywords)
+(make-obsolete-variable 'generic-font-lock-defaults 'generic-font-lock-keywords "22.1")
+
+;;;###autoload
+(defvar generic-mode-list nil
+ "A list of mode names for `generic-mode'.
+Do not add entries to this list directly; use `define-generic-mode'
+instead (which see).")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;###autoload
+(defmacro define-generic-mode (mode comment-list keyword-list
+ font-lock-list auto-mode-list
+ function-list &optional docstring
+ &rest custom-keyword-args)
+ "Create a new generic mode MODE.
+
+MODE is the name of the command for the generic mode; it need not
+be quoted. The optional DOCSTRING is the documentation for the
+mode command. If you do not supply it, a default documentation
+string will be used instead.
+
+COMMENT-LIST is a list, whose entries are either a single
+character, a one or two character string or a cons pair. If the
+entry is a character or a string, it is added to the mode's
+syntax table with `comment-start' syntax. If the entry is a cons
+pair, the elements of the pair are considered to be
+`comment-start' and `comment-end' respectively. (The latter
+should be nil if you want comments to end at end of line.) Note
+that Emacs has limitations regarding comment characters.
+
+KEYWORD-LIST is a list of keywords to highlight with
+`font-lock-keyword-face'. Each keyword should be a string.
+
+FONT-LOCK-LIST is a list of additional expressions to highlight.
+Each entry in the list should have the same form as an entry in
+`font-lock-keywords'.
+
+AUTO-MODE-LIST is a list of regular expressions to add to
+`auto-mode-alist'. These regexps are added to `auto-mode-alist'
+as soon as `define-generic-mode' is called.
+
+FUNCTION-LIST is a list of functions to call to do some
+additional setup.
+
+The optional CUSTOM-KEYWORD-ARGS are pairs of keywords and
+values. They will be passed to the generated `defcustom' form of
+the mode hook variable MODE-hook. Defaults to MODE without the
+possible trailing \"-mode\". (This default may not be a valid
+customization group defined with `defgroup'. Make sure it is.)
+You can specify keyword arguments without specifying a docstring.
+
+See the file generic-x.el for some examples of `define-generic-mode'."
+ (declare (debug (sexp def-form def-form def-form form def-form
+ [&optional stringp] &rest [keywordp form]))
+ (indent 1))
+
+ ;; Backward compatibility.
+ (when (eq (car-safe mode) 'quote)
+ (setq mode (eval mode)))
+
+ (when (and docstring (not (stringp docstring)))
+ ;; DOCSTRING is not a string so we assume that it's actually the
+ ;; first keyword of CUSTOM-KEYWORD-ARGS.
+ (push docstring custom-keyword-args)
+ (setq docstring nil))
+
+ (let* ((name (symbol-name mode))
+ (pretty-name (capitalize (replace-regexp-in-string
+ "-mode\\'" "" name)))
+ (mode-hook (intern (concat name "-hook"))))
+
+ (unless (plist-get custom-keyword-args :group)
+ (setq custom-keyword-args
+ (plist-put custom-keyword-args
+ :group `',(intern (replace-regexp-in-string
+ "-mode\\'" "" name)))))
+
+ `(progn
+ ;; Add a new entry.
+ (add-to-list 'generic-mode-list ,name)
+
+ ;; Add it to auto-mode-alist
+ (dolist (re ,auto-mode-list)
+ (add-to-list 'auto-mode-alist (cons re ',mode)))
+
+ (defcustom ,mode-hook nil
+ ,(concat "Hook run when entering " pretty-name " mode.")
+ :type 'hook
+ ,@custom-keyword-args)
+
+ (defun ,mode ()
+ ,(or docstring
+ (concat pretty-name " mode.\n"
+ "This a generic mode defined with `define-generic-mode'."))
+ (interactive)
+ (generic-mode-internal ',mode ,comment-list ,keyword-list
+ ,font-lock-list ,function-list)))))
+
+;;;###autoload
+(defun generic-mode-internal (mode comment-list keyword-list
+ font-lock-list function-list)
+ "Go into the generic mode MODE."
+ (let* ((name (symbol-name mode))
+ (pretty-name (capitalize (replace-regexp-in-string
+ "-mode\\'" "" name)))
+ (mode-hook (intern (concat name "-hook"))))
+
+ (kill-all-local-variables)
+
+ (setq major-mode mode
+ mode-name pretty-name)
+
+ (generic-mode-set-comments comment-list)
+
+ ;; Font-lock functionality.
+ ;; Font-lock-defaults is always set even if there are no keywords
+ ;; or font-lock expressions, so comments can be highlighted.
+ (setq generic-font-lock-keywords font-lock-list)
+ (when keyword-list
+ (push (concat "\\_<" (regexp-opt keyword-list t) "\\_>")
+ generic-font-lock-keywords))
+ (setq font-lock-defaults '(generic-font-lock-keywords nil))
+
+ ;; Call a list of functions
+ (mapcar 'funcall function-list)
+
+ (run-mode-hooks mode-hook)))
+
+;;;###autoload
+(defun generic-mode (mode)
+ "Enter generic mode MODE.
+
+Generic modes provide basic comment and font-lock functionality
+for \"generic\" files. (Files which are too small to warrant their
+own mode, but have comment characters, keywords, and the like.)
+
+To define a generic-mode, use the function `define-generic-mode'.
+Some generic modes are defined in `generic-x.el'."
+ (interactive
+ (list (completing-read "Generic mode: " generic-mode-list nil t)))
+ (funcall (intern mode)))
+
+;;; Comment Functionality
+(defun generic-mode-set-comments (comment-list)
+ "Set up comment functionality for generic mode."
+ (let ((st (make-syntax-table))
+ (chars nil)
+ (comstyles))
+ (make-local-variable 'comment-start)
+ (make-local-variable 'comment-start-skip)
+ (make-local-variable 'comment-end)
+
+ ;; Go through all the comments
+ (dolist (start comment-list)
+ (let (end (comstyle ""))
+ ;; Normalize
+ (when (consp start)
+ (setq end (cdr start))
+ (setq start (car start)))
+ (when (characterp start) (setq start (char-to-string start)))
+ (cond
+ ((characterp end) (setq end (char-to-string end)))
+ ((zerop (length end)) (setq end "\n")))
+
+ ;; Setup the vars for `comment-region'
+ (if comment-start
+ ;; We have already setup a comment-style, so use style b
+ (progn
+ (setq comstyle "b")
+ (setq comment-start-skip
+ (concat comment-start-skip "\\|" (regexp-quote start) "+\\s-*")))
+ ;; First comment-style
+ (setq comment-start start)
+ (setq comment-end (if (string-equal end "\n") "" end))
+ (setq comment-start-skip (concat (regexp-quote start) "+\\s-*")))
+
+ ;; Reuse comstyles if necessary
+ (setq comstyle
+ (or (cdr (assoc start comstyles))
+ (cdr (assoc end comstyles))
+ comstyle))
+ (push (cons start comstyle) comstyles)
+ (push (cons end comstyle) comstyles)
+
+ ;; Setup the syntax table
+ (if (= (length start) 1)
+ (modify-syntax-entry (string-to-char start)
+ (concat "< " comstyle) st)
+ (let ((c0 (elt start 0)) (c1 (elt start 1)))
+ ;; Store the relevant info but don't update yet
+ (push (cons c0 (concat (cdr (assoc c0 chars)) "1")) chars)
+ (push (cons c1 (concat (cdr (assoc c1 chars))
+ (concat "2" comstyle))) chars)))
+ (if (= (length end) 1)
+ (modify-syntax-entry (string-to-char end)
+ (concat ">" comstyle) st)
+ (let ((c0 (elt end 0)) (c1 (elt end 1)))
+ ;; Store the relevant info but don't update yet
+ (push (cons c0 (concat (cdr (assoc c0 chars))
+ (concat "3" comstyle))) chars)
+ (push (cons c1 (concat (cdr (assoc c1 chars)) "4")) chars)))))
+
+ ;; Process the chars that were part of a 2-char comment marker
+ (dolist (cs (nreverse chars))
+ (modify-syntax-entry (car cs)
+ (concat (char-to-string (char-syntax (car cs)))
+ " " (cdr cs))
+ st))
+ (set-syntax-table st)))
+
+(defun generic-bracket-support ()
+ "Imenu support for [KEYWORD] constructs found in INF, INI and Samba files."
+ (setq imenu-generic-expression
+ '((nil "^\\[\\(.*\\)\\]" 1))
+ imenu-case-fold-search t))
+
+;;;###autoload
+(defun generic-make-keywords-list (keyword-list face &optional prefix suffix)
+ "Return a `font-lock-keywords' construct that highlights KEYWORD-LIST.
+KEYWORD-LIST is a list of keyword strings that should be
+highlighted with face FACE. This function calculates a regular
+expression that matches these keywords and concatenates it with
+PREFIX and SUFFIX. Then it returns a construct based on this
+regular expression that can be used as an element of
+`font-lock-keywords'."
+ (unless (listp keyword-list)
+ (error "Keywords argument must be a list of strings"))
+ (list (concat prefix "\\_<"
+ ;; Use an optimized regexp.
+ (regexp-opt keyword-list t)
+ "\\_>" suffix)
+ 1
+ face))
+
+(provide 'generic)
+
+;; arch-tag: 239c1fc4-1303-48d9-9ac0-657d655669ea
+;;; generic.el ends here