/[emacs]/emacs/lisp/generic.el
ViewVC logotype

Diff of /emacs/lisp/generic.el

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.27 by lute, Mon Mar 14 11:06:20 2005 UTC revision 1.28 by lute, Mon Mar 21 17:10:06 2005 UTC
# Line 34  Line 34 
34    
35  ;; Generic-mode is a meta-mode which can be used to define small modes  ;; Generic-mode is a meta-mode which can be used to define small modes
36  ;; which provide basic comment and font-lock support.  These modes are  ;; which provide basic comment and font-lock support.  These modes are
37  ;; intended for the many configuration files and such which are too small  ;; intended for the many configuration files and such which are too
38  ;; for a "real" mode, but still have a regular syntax, comment characters  ;; small for a "real" mode, but still have a regular syntax, comment
39  ;; and the like.  ;; characters and the like.
40  ;;  ;;
41  ;; Each generic mode can define the following:  ;; Each generic mode can define the following:
42  ;;  ;;
43  ;; * List of comment-characters.  The entries in this list should be  ;; * List of comment-characters.  The entries in this list should be
44  ;;   either a character, a one or two character string or a cons pair.  ;;   either a character, a one or two character string or a cons pair.
45  ;;   If the entry is a character or a one-character string  ;;   If the entry is a character or a string, it is added to the
46  ;;   LIMITATIONS:  Emacs does not support comment strings of more than  ;;   mode's syntax table with `comment-start' syntax.  If the entry is
47    ;;   a cons pair, the elements of the pair are considered to be
48    ;;   `comment-start' and `comment-end' respectively.  (The latter
49    ;;   should be nil if you want comments to end at end of line.)
50    ;;   LIMITATIONS: Emacs does not support comment strings of more than
51  ;;   two characters in length.  ;;   two characters in length.
52  ;;  ;;
53  ;; * List of keywords to font-lock.  Each keyword should be a string.  ;; * List of keywords to font-lock.  Each keyword should be a string.
54  ;;   If you have additional keywords which should be highlighted in a face  ;;   If you have additional keywords which should be highlighted in a
55  ;;   different from `font-lock-keyword-face', you can use the convenience  ;;   face different from `font-lock-keyword-face', you can use the
56  ;;   function `generic-make-keywords-list' (which see), and add the  ;;   convenience function `generic-make-keywords-list' (which see),
57  ;;   result to the following list:  ;;   and add the result to the following list:
58  ;;  ;;
59  ;; * Additional expressions to font-lock.  This should be a list of  ;; * Additional expressions to font-lock.  This should be a list of
60  ;;   expressions, each of which should be of the same form  ;;   expressions, each of which should be of the same form as those in
61  ;;   as those in `font-lock-keywords'.  ;;   `font-lock-keywords'.
62  ;;  ;;
63  ;; * List of regular expressions to be placed in auto-mode-alist.  ;; * List of regular expressions to be placed in auto-mode-alist.
64  ;;  ;;
# Line 79  Line 83 
83  ;; Use the `define-generic-mode' function to define new modes.  ;; Use the `define-generic-mode' function to define new modes.
84  ;; For example:  ;; For example:
85  ;;  ;;
 ;;   (require 'generic)  
86  ;;   (define-generic-mode 'foo-generic-mode  ;;   (define-generic-mode 'foo-generic-mode
87  ;;                        (list ?% )  ;;     (list ?%)
88  ;;                        (list "keyword")  ;;     (list "keyword")
89  ;;                        nil  ;;     nil
90  ;;                        (list "\\.FOO\\'")  ;;     (list "\\.FOO\\'")
91  ;;                        (list 'foo-setup-function))  ;;     (list 'foo-setup-function))
92  ;;  ;;
93  ;; defines a new generic-mode `foo-generic-mode', which has '%' as a  ;; defines a new generic-mode `foo-generic-mode', which has '%' as a
94  ;; comment character, and "keyword" as a keyword. When files which end in  ;; comment character, and "keyword" as a keyword.  When files which
95  ;; '.FOO' are loaded, Emacs will go into foo-generic-mode and call  ;; end in '.FOO' are loaded, Emacs will go into foo-generic-mode and
96  ;; foo-setup-function.  You can also use the function `foo-generic-mode'  ;; call foo-setup-function.  You can also use the function
97  ;; (which is interactive) to put a buffer into foo-generic-mode.  ;; `foo-generic-mode' (which is interactive) to put a buffer into
98    ;; foo-generic-mode.
99  ;;  ;;
100  ;; AUTOMATICALLY ENTERING GENERIC MODE:  ;; AUTOMATICALLY ENTERING GENERIC MODE:
101  ;;  ;;
102  ;; Generic-mode provides a hook which automatically puts a  ;; Generic-mode provides a hook which automatically puts a file into
103  ;; file into default-generic-mode if the first few lines of a file in  ;; default-generic-mode if the first few lines of a file in
104  ;; fundamental mode start with a hash comment character. To disable  ;; fundamental mode start with a hash comment character.  To disable
105  ;; this functionality, set the variable `generic-use-find-file-hook'  ;; this functionality, set the variable `generic-use-find-file-hook'
106  ;; to nil BEFORE loading generic-mode. See the variables  ;; to nil BEFORE loading generic-mode.  See the variables
107  ;; `generic-lines-to-scan' and `generic-find-file-regexp' for customization  ;; `generic-lines-to-scan' and `generic-find-file-regexp' for
108  ;; options.  ;; customization options.
109  ;;  ;;
110  ;; GOTCHAS:  ;; GOTCHAS:
111  ;;  ;;
112  ;; Be careful that your font-lock definitions are correct.  Getting them  ;; Be careful that your font-lock definitions are correct.  Getting
113  ;; wrong can cause emacs to continually attempt to fontify! This problem  ;; them wrong can cause Emacs to continually attempt to fontify! This
114  ;; is not specific to generic-mode.  ;; problem is not specific to generic-mode.
115  ;;  ;;
116    
117  ;; Credit for suggestions, brainstorming, help with debugging:  ;; Credit for suggestions, brainstorming, help with debugging:
# Line 117  Line 121 
121  ;;  ;;
122  ;;; Code:  ;;; Code:
123    
 (eval-when-compile  
   (require 'cl))  
   
124  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125  ;; Internal Variables  ;; Internal Variables
126  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
# Line 128  Line 129 
129    "Global defaults for font-lock in a generic mode.")    "Global defaults for font-lock in a generic mode.")
130  (make-variable-buffer-local 'generic-font-lock-defaults)  (make-variable-buffer-local 'generic-font-lock-defaults)
131    
132    ;;;###autoload
133  (defvar generic-mode-list nil  (defvar generic-mode-list nil
134    "A list of mode names for `generic-mode'.    "A list of mode names for `generic-mode'.
135  Do not add entries to this list directly; use `define-generic-mode'  Do not add entries to this list directly; use `define-generic-mode'
# Line 143  instead (which see).") Line 145  instead (which see).")
145    :group 'extensions)    :group 'extensions)
146    
147  (defcustom generic-use-find-file-hook t  (defcustom generic-use-find-file-hook t
148    "*If non-nil, add a hook to enter default-generic-mode automatically.    "*If non-nil, add a hook to enter `default-generic-mode' automatically.
149  This is done if the first few lines of a file in fundamental mode start  This is done if the first few lines of a file in fundamental mode
150  with a hash comment character."  start with a hash comment character."
151    :group 'generic    :group 'generic
152    :type  'boolean    :type  'boolean)
   )  
153    
154  (defcustom generic-lines-to-scan 3  (defcustom generic-lines-to-scan 3
155    "*Number of lines that `generic-mode-find-file-hook' looks at.    "*Number of lines that `generic-mode-find-file-hook' looks at.
156  Relevant when deciding whether to enter `generic-mode' automatically.  Relevant when deciding whether to enter Default-Generic mode automatically.
157  This variable should be set to a small positive number."  This variable should be set to a small positive number."
158    :group 'generic    :group 'generic
159    :type  'integer    :type  'integer)
   )  
160    
161  (defcustom generic-find-file-regexp "^#"  (defcustom generic-find-file-regexp "^#"
162    "*Regular expression used by `generic-mode-find-file-hook'.    "*Regular expression used by `generic-mode-find-file-hook'.
163  Files in fundamental mode whose first few lines contain a match for  Files in fundamental mode whose first few lines contain a match
164  this regexp, should be put into `default-generic-mode' instead.  for this regexp, should be put into Default-Generic mode instead.
165  The number of lines tested for the matches is specified by the value  The number of lines tested for the matches is specified by the
166  of the variable `generic-lines-to-scan', which see."  value of the variable `generic-lines-to-scan', which see."
167    :group 'generic    :group 'generic
168    :type  'regexp    :type  'regexp)
   )  
169    
170  (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'"  (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'"
171    "*Regular expression used by `generic-mode-find-file-hook'.    "*Regular expression used by `generic-mode-find-file-hook'.
172  Files whose names match this regular expression should not be put  Files whose names match this regular expression should not be put
173  into `default-generic-mode', even if they have lines which match the  into Default-Generic mode, even if they have lines which match
174  regexp in `generic-find-file-regexp'.  If the value is nil,  the regexp in `generic-find-file-regexp'.  If the value is nil,
175  `generic-mode-find-file-hook' does not check the file names."  `generic-mode-find-file-hook' does not check the file names."
176    :group 'generic    :group 'generic
177    :type  '(choice (const :tag "Don't check file names" nil) regexp)    :type  '(choice (const :tag "Don't check file names" nil) regexp))
   )  
178    
179  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
180  ;; Functions  ;; Functions
181  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182    
183  ;;;###autoload  ;;;###autoload
184  (defun define-generic-mode (name comment-list    keyword-list   font-lock-list  (defmacro define-generic-mode (mode comment-list keyword-list
185                                   auto-mode-list  function-list                                      font-lock-list auto-mode-list
186                                   &optional description)                                      function-list &optional docstring)
187    "Create a new generic mode with NAME.    "Create a new generic mode MODE.
188    
189  NAME should be a symbol; its string representation is used as the function  MODE is the name of the command for the generic mode; it need not
190  name. If DESCRIPTION is provided, it is used as the docstring for the new  be quoted.  The optional DOCSTRING is the documentation for the
191  function.  mode command.  If you do not supply it, a default documentation
192    string will be used instead.
193  COMMENT-LIST is a list, whose entries are either a single character,  
194  a one or two character string or a cons pair. If the entry is a character  COMMENT-LIST is a list, whose entries are either a single
195  or a one-character string, it is added to the mode's syntax table with  character, a one or two character string or a cons pair.  If the
196  `comment-start' syntax.  If the entry is a cons pair, the elements of the  entry is a character or a string, it is added to the mode's
197  pair are considered to be `comment-start' and `comment-end' respectively.  syntax table with `comment-start' syntax.  If the entry is a cons
198  \(The latter should be nil if you want comments to end at end of line.)  pair, the elements of the pair are considered to be
199  Note that Emacs has limitations regarding comment characters.  `comment-start' and `comment-end' respectively.  (The latter
200    should be nil if you want comments to end at end of line.)  Note
201  KEYWORD-LIST is a list of keywords to highlight with `font-lock-keyword-face'.  that Emacs has limitations regarding comment characters.
202  Each keyword should be a string.  
203    KEYWORD-LIST is a list of keywords to highlight with
204  FONT-LOCK-LIST is a list of additional expressions to highlight. Each entry  `font-lock-keyword-face'.  Each keyword should be a string.
205  in the list should have the same form as an entry in `font-lock-keywords'.  
206    FONT-LOCK-LIST is a list of additional expressions to highlight.
207  AUTO-MODE-LIST is a list of regular expressions to add to `auto-mode-alist'.  Each entry in the list should have the same form as an entry in
208  These regexps are added to `auto-mode-alist' as soon as `define-generic-mode'  `font-lock-keywords'.
209  is called; any old regexps with the same name are removed.  
210    AUTO-MODE-LIST is a list of regular expressions to add to
211    `auto-mode-alist'.  These regexps are added to `auto-mode-alist'
212    as soon as `define-generic-mode' is called.
213    
214  FUNCTION-LIST is a list of functions to call to do some additional setup.  FUNCTION-LIST is a list of functions to call to do some
215    additional setup.
216    
217  See the file generic-x.el for some examples of `define-generic-mode'."  See the file generic-x.el for some examples of `define-generic-mode'."
218      (let* ((name-unquoted (if (eq (car-safe mode) 'quote) ; Backward compatibility.
219                                (eval mode)
220                              mode))
221             (name-string (symbol-name name-unquoted))
222             (pretty-name (capitalize (replace-regexp-in-string
223                                       "-mode\\'" "" name-string))))
224    
225        `(progn
226           ;; Add a new entry.
227           (add-to-list 'generic-mode-list ,name-string)
228    
229           ;; Add it to auto-mode-alist
230           (dolist (re ,auto-mode-list)
231             (add-to-list 'auto-mode-alist (cons re ',name-unquoted)))
232    
233           (defun ,name-unquoted ()
234             ,(or docstring
235                  (concat pretty-name " mode.\n"
236                          "This a generic mode defined with `define-generic-mode'."))
237             (interactive)
238             (generic-mode-internal ',name-unquoted ,comment-list ,keyword-list
239                                    ,font-lock-list ,function-list)))))
240    
241    ;; Add a new entry  ;;;###autoload
   (add-to-list 'generic-mode-list (symbol-name name))  
   
   ;; Add it to auto-mode-alist  
   (dolist (re auto-mode-list)  
     (add-to-list 'auto-mode-alist (cons re name)))  
   
   ;; Define a function for it using `defalias' (not `fset') to make  
   ;; the mode appear on load-history.  
   (defalias name  
     `(lambda nil  
        ,(or description (concat "Generic mode for type " (symbol-name name)))  
        (interactive)  
        (generic-mode-internal ',name ',comment-list ',keyword-list  
                               ',font-lock-list ',function-list)))  
   )  
   
242  (defun generic-mode-internal (mode comments keywords font-lock-list funs)  (defun generic-mode-internal (mode comments keywords font-lock-list funs)
243    "Go into the generic-mode MODE."    "Go into the generic mode MODE."
244    (let* ((generic-mode-hooks (intern (concat (symbol-name mode) "-hook")))    (let* ((modename (symbol-name mode))
245           (modename (symbol-name mode))           (generic-mode-hooks (intern (concat modename "-hook")))
246           (name (if (string-match "-mode\\'" modename)           (pretty-name (capitalize (replace-regexp-in-string
247                     (substring modename 0 (match-beginning 0))                                     "-mode\\'" "" modename))))
                  modename))  
          )  
248    
     ;; Put this after the point where we read generic-mode-name!  
249      (kill-all-local-variables)      (kill-all-local-variables)
250    
251      (setq      (setq major-mode mode
252       major-mode                    mode            mode-name pretty-name)
      mode-name                     (capitalize name)  
      )  
253    
254      (generic-mode-set-comments     comments)      (generic-mode-set-comments comments)
255    
256      ;; Font-lock functionality      ;; Font-lock functionality
257      ;; Font-lock-defaults are always set even if there are no keywords      ;; Font-lock-defaults are always set even if there are no keywords
258      ;; or font-lock expressions, so comments can be highlighted.      ;; or font-lock expressions, so comments can be highlighted.
259      (setq generic-font-lock-defaults nil)      (setq generic-font-lock-defaults nil)
260      (generic-mode-set-font-lock      keywords font-lock-list)      (generic-mode-set-font-lock  keywords font-lock-list)
261      (make-local-variable            'font-lock-defaults)      (make-local-variable 'font-lock-defaults)
262      (setq font-lock-defaults (list 'generic-font-lock-defaults nil))      (setq font-lock-defaults (list 'generic-font-lock-defaults nil))
263    
264      ;; Call a list of functions      ;; Call a list of functions
265      (mapcar 'funcall funs)      (mapcar 'funcall funs)
266    
267      (run-hooks generic-mode-hooks)      (run-hooks generic-mode-hooks)))
     )  
   )  
268    
269  ;;;###autoload  ;;;###autoload
270  (defun generic-mode (type)  (defun generic-mode (mode)
271    "Basic comment and font-lock functionality for `generic' files.    "Enter generic mode MODE.
272  \(Files which are too small to warrant their own mode, but have  
273  comment characters, keywords, and the like.)  Generic modes provide basic comment and font-lock functionality
274    for \"generic\" files.  (Files which are too small to warrant their
275    own mode, but have comment characters, keywords, and the like.)
276    
277  To define a generic-mode, use the function `define-generic-mode'.  To define a generic-mode, use the function `define-generic-mode'.
278  Some generic modes are defined in `generic-x.el'."  Some generic modes are defined in `generic-x.el'."
279    (interactive    (interactive
280     (list (completing-read "Generic Type: " generic-mode-list nil t)))     (list (completing-read "Generic mode: " generic-mode-list nil t)))
281    (funcall (intern type)))    (funcall (intern mode)))
282    
283  ;;; Comment Functionality  ;;; Comment Functionality
284  (defun generic-mode-set-comments (comment-list)  (defun generic-mode-set-comments (comment-list)
# Line 283  Some generic modes are defined in `gener Line 286  Some generic modes are defined in `gener
286    (let ((st (make-syntax-table))    (let ((st (make-syntax-table))
287          (chars nil)          (chars nil)
288          (comstyles))          (comstyles))
289      (make-local-variable             'comment-start)      (make-local-variable 'comment-start)
290      (make-local-variable             'comment-start-skip)      (make-local-variable 'comment-start-skip)
291      (make-local-variable             'comment-end)      (make-local-variable 'comment-end)
292    
293      ;; Go through all the comments      ;; Go through all the comments
294      (dolist (start comment-list)      (dolist (start comment-list)
295        (let ((end nil) (comstyle ""))        (let (end (comstyle ""))
296          ;; Normalize          ;; Normalize
297          (when (consp start)          (when (consp start)
298            (setq end (or (cdr start) end))            (setq end (cdr start))
299            (setq start (car start)))            (setq start (car start)))
300          (when (char-valid-p start) (setq start (char-to-string start)))          (when (char-valid-p start) (setq start (char-to-string start)))
301          (cond          (cond
# Line 360  Some generic modes are defined in `gener Line 363  Some generic modes are defined in `gener
363          imenu-case-fold-search t))          imenu-case-fold-search t))
364    
365  ;; This generic mode is always defined  ;; This generic mode is always defined
366  (define-generic-mode 'default-generic-mode (list ?#)  nil nil nil nil)  (define-generic-mode default-generic-mode (list ?#) nil nil nil nil)
367    
368  ;; A more general solution would allow us to enter generic-mode for  ;; A more general solution would allow us to enter generic-mode for
369  ;; *any* comment character, but would require us to synthesize a new  ;; *any* comment character, but would require us to synthesize a new
370  ;; generic-mode on the fly. I think this gives us most of what we  ;; generic-mode on the fly. I think this gives us most of what we
371  ;; want.  ;; want.
372  (defun generic-mode-find-file-hook ()  (defun generic-mode-find-file-hook ()
373    "Hook function to enter `default-generic-mode' automatically.    "Hook function to enter Default-Generic mode automatically.
374  Done if the first few lines of a file in `fundamental-mode' start with  
375  a match for the regexp in `generic-find-file-regexp', unless the  Done if the first few lines of a file in Fundamental mode start
376  file's name matches the regexp which is the value of the variable  with a match for the regexp in `generic-find-file-regexp', unless
377  `generic-ignore-files-regexp'.  the file's name matches the regexp which is the value of the
378    variable `generic-ignore-files-regexp'.
379    
380  This hook will be installed if the variable  This hook will be installed if the variable
381  `generic-use-find-file-hook' is non-nil.  The variable  `generic-use-find-file-hook' is non-nil.  The variable
382  `generic-lines-to-scan' determines the number of lines to look at."  `generic-lines-to-scan' determines the number of lines to look at."
# Line 390  This hook will be installed if the varia Line 395  This hook will be installed if the varia
395          (default-generic-mode)))))          (default-generic-mode)))))
396    
397  (defun generic-mode-ini-file-find-file-hook ()  (defun generic-mode-ini-file-find-file-hook ()
398    "Hook function to enter default-generic-mode automatically for INI files.    "Hook function to enter Default-Generic mode automatically for INI files.
399  Done if the first few lines of a file in `fundamental-mode' look like an  Done if the first few lines of a file in Fundamental mode look like an
400  INI file.  This hook is NOT installed by default."  INI file.  This hook is NOT installed by default."
401    (and (eq major-mode 'fundamental-mode)    (and (eq major-mode 'fundamental-mode)
402         (save-excursion         (save-excursion

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.28

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26