(defvar generic-font-lock-keywords nil
"Keywords for `font-lock-defaults' in a generic mode.")
(make-variable-buffer-local 'generic-font-lock-keywords)
(define-obsolete-variable-alias 'generic-font-lock-defaults 'generic-font-lock-keywords "22.1")
(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).")
(defmacro define-generic-mode (mode comment-list keyword-list
font-lock-list auto-mode-list
function-list &optional docstring)
"Create a new generic mode MODE.
MODE is the name of the command for the generic mode; don't quote it.
The optional DOCSTRING is the documentation for the mode command. If
you do not supply it, `define-generic-mode' uses a default
documentation string instead.
COMMENT-LIST is a list in which each element is either a character, a
string of one or two characters, or a cons cell. A character or a
string is set up in the mode's syntax table as a \"comment starter\".
If the entry is a cons cell, the `car' is set up as a \"comment
starter\" and the `cdr' as a \"comment ender\". (Use nil for the
latter if you want comments to end at the end of the line.) Note that
the syntax table has limitations about what comment starters and
enders are actually possible.
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
element of this list should have the same form as an element of
`font-lock-keywords'.
AUTO-MODE-LIST is a list of regular expressions to add to
`auto-mode-alist'. These regular expressions are added when Emacs
runs the macro expansion.
FUNCTION-LIST is a list of functions to call to do some additional
setup. The mode command calls these functions just before it runs the
mode hook `MODE-hook'.
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))
(when (eq (car-safe mode) 'quote)
(setq mode (eval mode)))
(let* ((name (symbol-name mode))
(pretty-name (capitalize (replace-regexp-in-string
"-mode\\'" "" name))))
`(progn
(add-to-list 'generic-mode-list ,name)
(dolist (re ,auto-mode-list)
(add-to-list 'auto-mode-alist (cons re ',mode)))
(defun ,mode ()
,(or docstring
(concat pretty-name " mode.\n"
"This a generic mode defined with `define-generic-mode'.\n"
"It runs `" name "-hook' as the last thing it does."))
(interactive)
(generic-mode-internal ',mode ,comment-list ,keyword-list
,font-lock-list ,function-list)))))
(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)
(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))
(mapcar 'funcall function-list)
(run-mode-hooks mode-hook)))
(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)))
(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)
(dolist (start comment-list)
(let (end (comstyle ""))
(when (consp start)
(setq end (cdr start))
(setq start (car start)))
(when (char-valid-p start) (setq start (char-to-string start)))
(cond
((char-valid-p end) (setq end (char-to-string end)))
((zerop (length end)) (setq end "\n")))
(if comment-start
(progn
(setq comstyle "b")
(setq comment-start-skip
(concat comment-start-skip "\\|" (regexp-quote start) "+\\s-*")))
(setq comment-start start)
(setq comment-end (if (string-equal end "\n") "" end))
(setq comment-start-skip (concat (regexp-quote start) "+\\s-*")))
(setq comstyle
(or (cdr (assoc start comstyles))
(cdr (assoc end comstyles))
comstyle))
(push (cons start comstyle) comstyles)
(push (cons end comstyle) comstyles)
(if (= (length start) 1)
(modify-syntax-entry (string-to-char start)
(concat "< " comstyle) st)
(let ((c0 (elt start 0)) (c1 (elt start 1)))
(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)))
(push (cons c0 (concat (cdr (assoc c0 chars))
(concat "3" comstyle))) chars)
(push (cons c1 (concat (cdr (assoc c1 chars)) "4")) chars)))))
(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))
(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 "\\_<"
(regexp-opt keyword-list t)
"\\_>" suffix)
1
face))
(provide 'generic)