From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Lute Kamstra Newsgroups: gmane.emacs.devel Subject: Re: lisp/generic.el patch. Date: Thu, 17 Mar 2005 17:34:04 +0100 Message-ID: <873buup6yr.fsf@xs4all.nl> References: <87y8co96uz.fsf@xs4all.nl> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1111078926 6935 80.91.229.2 (17 Mar 2005 17:02:06 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Thu, 17 Mar 2005 17:02:06 +0000 (UTC) Cc: Stefan Monnier , "Richard M. Stallman" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Mar 17 18:02:05 2005 Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1DByE5-0004MG-QL for ged-emacs-devel@m.gmane.org; Thu, 17 Mar 2005 17:52:05 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DByUO-0005V6-IE for ged-emacs-devel@m.gmane.org; Thu, 17 Mar 2005 12:08:52 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1DByPI-0003n6-9t for emacs-devel@gnu.org; Thu, 17 Mar 2005 12:03:36 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1DByPG-0003mH-KI for emacs-devel@gnu.org; Thu, 17 Mar 2005 12:03:35 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DByMS-0002Sa-M1 for emacs-devel@gnu.org; Thu, 17 Mar 2005 12:00:41 -0500 Original-Received: from [194.109.24.23] (helo=smtp-vbr3.xs4all.nl) by monty-python.gnu.org with esmtp (Exim 4.34) id 1DBxwl-0005eL-BN; Thu, 17 Mar 2005 11:34:08 -0500 Original-Received: from pijl (a80-127-67-124.adsl.xs4all.nl [80.127.67.124]) by smtp-vbr3.xs4all.nl (8.12.11/8.12.11) with ESMTP id j2HGY4Ji071567; Thu, 17 Mar 2005 17:34:05 +0100 (CET) (envelope-from Lute.Kamstra@xs4all.nl) Original-Received: from lute by pijl with local (Exim 3.36 #1 (Debian)) id 1DBxwi-0002Q9-00; Thu, 17 Mar 2005 17:34:04 +0100 Original-To: emacs-devel@gnu.org In-Reply-To: <87y8co96uz.fsf@xs4all.nl> (Lute Kamstra's message of "Tue, 15 Mar 2005 18:06:12 +0100") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) Original-Lines: 573 X-Virus-Scanned: by XS4ALL Virus Scanner X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org X-MailScanner-To: ged-emacs-devel@m.gmane.org Xref: news.gmane.org gmane.emacs.devel:34669 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:34669 Here is an updated patch that incorporates the feedback of Stefan and Richard. I also changed three other things: I removed the (eval-when-compile (require 'cl)) as that is not needed. I changed define-generic-mode so that the name of the mode command need not be quoted (while retaining backward compatibility). This makes define-generic-mode more like other defining forms. I updated the docstring of define-generic-mode to reflect this change. I changed the default docstring of a generic mode. Ok to commit? Lute. 2005-03-17 Lute Kamstra * generic.el: Fix commentary section. Don't require cl for compilation. (generic-mode-list): Add autoload cookie. (generic-use-find-file-hook, generic-lines-to-scan) (generic-find-file-regexp, generic-ignore-files-regexp) (generic-mode, generic-mode-find-file-hook) (generic-mode-ini-file-find-file-hook): Fix docstrings. (define-generic-mode): Make it a defmacro. Fix docstring. (generic-mode-internal): Code cleanup. Add autoload cookie. (generic-mode-set-comments): Code cleanup. Index: lisp/generic.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/generic.el,v retrieving revision 1.27 diff -c -r1.27 generic.el *** lisp/generic.el 14 Mar 2005 11:06:20 -0000 1.27 --- lisp/generic.el 17 Mar 2005 16:29:31 -0000 *************** *** 34,60 **** ;; Generic-mode is a meta-mode which 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 one-character string ! ;; 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. ;; --- 34,64 ---- ;; Generic-mode is a meta-mode which 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. ;; *************** *** 79,113 **** ;; Use the `define-generic-mode' function to define new modes. ;; For example: ;; - ;; (require 'generic) ;; (define-generic-mode 'foo-generic-mode ! ;; (list ?% ) ! ;; (list "keyword") ! ;; nil ! ;; (list "\\.FOO\\'") ! ;; (list 'foo-setup-function)) ;; ;; defines 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. ;; ;; AUTOMATICALLY ENTERING GENERIC MODE: ;; ! ;; Generic-mode provides a hook which automatically puts a ! ;; file into default-generic-mode if the first few lines of a file in ! ;; fundamental mode start with a hash comment character. To disable ;; this functionality, set the variable `generic-use-find-file-hook' ! ;; to nil BEFORE loading generic-mode. See the variables ! ;; `generic-lines-to-scan' and `generic-find-file-regexp' for customization ! ;; options. ;; ;; 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: --- 83,117 ---- ;; Use the `define-generic-mode' function to define new modes. ;; For example: ;; ;; (define-generic-mode 'foo-generic-mode ! ;; (list ?%) ! ;; (list "keyword") ! ;; nil ! ;; (list "\\.FOO\\'") ! ;; (list 'foo-setup-function)) ;; ;; defines 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. ;; ;; AUTOMATICALLY ENTERING GENERIC MODE: ;; ! ;; Generic-mode provides a hook which automatically puts a file into ! ;; default-generic-mode if the first few lines of a file in ! ;; fundamental mode start with a hash comment character. To disable ;; this functionality, set the variable `generic-use-find-file-hook' ! ;; to nil BEFORE loading generic-mode. See the variables ! ;; `generic-lines-to-scan' and `generic-find-file-regexp' for ! ;; customization options. ;; ;; 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: *************** *** 117,125 **** ;; ;;; Code: - (eval-when-compile - (require 'cl)) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Internal Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; --- 121,126 ---- *************** *** 128,133 **** --- 129,135 ---- "Global defaults for font-lock in a generic mode.") (make-variable-buffer-local 'generic-font-lock-defaults) + ;;;###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' *************** *** 143,281 **** :group 'extensions) (defcustom generic-use-find-file-hook t ! "*If non-nil, add a hook to enter default-generic-mode automatically. ! This is done if the first few lines of a file in fundamental mode start ! with a hash comment character." :group 'generic ! :type 'boolean ! ) (defcustom generic-lines-to-scan 3 "*Number of lines that `generic-mode-find-file-hook' looks at. ! Relevant when deciding whether to enter `generic-mode' automatically. This variable should be set to a small positive number." :group 'generic ! :type 'integer ! ) (defcustom generic-find-file-regexp "^#" "*Regular expression used by `generic-mode-find-file-hook'. ! Files in fundamental mode whose first few lines contain a match for ! this regexp, should be put into `default-generic-mode' instead. ! The number of lines tested for the matches is specified by the value ! of the variable `generic-lines-to-scan', which see." :group 'generic ! :type 'regexp ! ) (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'" "*Regular expression used by `generic-mode-find-file-hook'. Files whose names match this regular expression should not be put ! into `default-generic-mode', even if they have lines which match the ! regexp in `generic-find-file-regexp'. If the value is nil, `generic-mode-find-file-hook' does not check the file names." :group 'generic ! :type '(choice (const :tag "Don't check file names" nil) regexp) ! ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;###autoload ! (defun define-generic-mode (name comment-list keyword-list font-lock-list ! auto-mode-list function-list ! &optional description) ! "Create a new generic mode with NAME. ! ! NAME should be a symbol; its string representation is used as the function ! name. If DESCRIPTION is provided, it is used as the docstring for the new ! function. ! ! 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 one-character 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; any old regexps with the same name are removed. ! FUNCTION-LIST is a list of functions to call to do some additional setup. See the file generic-x.el for some examples of `define-generic-mode'." ! ;; Add a new entry ! (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))) ! ) ! (defun generic-mode-internal (mode comments keywords font-lock-list funs) ! "Go into the generic-mode MODE." ! (let* ((generic-mode-hooks (intern (concat (symbol-name mode) "-hook"))) ! (modename (symbol-name mode)) ! (name (if (string-match "-mode\\'" modename) ! (substring modename 0 (match-beginning 0)) ! modename)) ! ) - ;; Put this after the point where we read generic-mode-name! (kill-all-local-variables) ! (setq ! major-mode mode ! mode-name (capitalize name) ! ) ! (generic-mode-set-comments comments) ;; Font-lock functionality ;; Font-lock-defaults are always set even if there are no keywords ;; or font-lock expressions, so comments can be highlighted. (setq generic-font-lock-defaults nil) ! (generic-mode-set-font-lock keywords font-lock-list) ! (make-local-variable 'font-lock-defaults) (setq font-lock-defaults (list 'generic-font-lock-defaults nil)) ;; Call a list of functions (mapcar 'funcall funs) ! (run-hooks generic-mode-hooks) ! ) ! ) ;;;###autoload ! (defun generic-mode (type) ! "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 Type: " generic-mode-list nil t))) ! (funcall (intern type))) ;;; Comment Functionality (defun generic-mode-set-comments (comment-list) --- 145,284 ---- :group 'extensions) (defcustom generic-use-find-file-hook t ! "*If non-nil, add a hook to enter Default-Generic mode automatically. ! This is done if the first few lines of a file in fundamental mode ! start with a hash comment character." :group 'generic ! :type 'boolean) (defcustom generic-lines-to-scan 3 "*Number of lines that `generic-mode-find-file-hook' looks at. ! Relevant when deciding whether to enter Default-Generic mode automatically. This variable should be set to a small positive number." :group 'generic ! :type 'integer) (defcustom generic-find-file-regexp "^#" "*Regular expression used by `generic-mode-find-file-hook'. ! Files in fundamental mode whose first few lines contain a match ! for this regexp, should be put into Default-Generic mode instead. ! The number of lines tested for the matches is specified by the ! value of the variable `generic-lines-to-scan', which see." :group 'generic ! :type 'regexp) (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'" "*Regular expression used by `generic-mode-find-file-hook'. Files whose names match this regular expression should not be put ! into Default-Generic mode, even if they have lines which match ! the regexp in `generic-find-file-regexp'. If the value is nil, `generic-mode-find-file-hook' does not check the file names." :group 'generic ! :type '(choice (const :tag "Don't check file names" nil) regexp)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;###autoload ! (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; 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. See the file generic-x.el for some examples of `define-generic-mode'." + (let* ((name-unquoted (if (eq (car-safe mode) 'quote) ; Backward compatibility. + (eval mode) + mode)) + (name-string (symbol-name name-unquoted)) + (pretty-name (capitalize (replace-regexp-in-string + "-mode\\'" "" name-string)))) + + `(progn + ;; Add a new entry. + (add-to-list 'generic-mode-list ,name-string) + + ;; Add it to auto-mode-alist + (dolist (re ,auto-mode-list) + (add-to-list 'auto-mode-alist (cons re ',name-unquoted))) + + (defun ,name-unquoted () + ,(or docstring + (concat pretty-name " mode.\n" + "This a generic mode defined with `define-generic-mode'.")) + (interactive) + (generic-mode-internal ',name-unquoted ,comment-list ,keyword-list + ,font-lock-list ,function-list))))) ! ;;;###autoload (defun generic-mode-internal (mode comments keywords font-lock-list funs) ! "Go into the generic mode MODE." ! (let* ((modename (symbol-name mode)) ! (generic-mode-hooks (intern (concat modename "-hook"))) ! (pretty-name (capitalize (replace-regexp-in-string ! "-mode\\'" "" modename)))) (kill-all-local-variables) ! (setq major-mode mode ! mode-name pretty-name) ! (generic-mode-set-comments comments) ;; Font-lock functionality ;; Font-lock-defaults are always set even if there are no keywords ;; or font-lock expressions, so comments can be highlighted. (setq generic-font-lock-defaults nil) ! (generic-mode-set-font-lock keywords font-lock-list) ! (make-local-variable 'font-lock-defaults) (setq font-lock-defaults (list 'generic-font-lock-defaults nil)) ;; Call a list of functions (mapcar 'funcall funs) ! (run-hooks generic-mode-hooks))) ;;;###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) *************** *** 283,298 **** (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 nil) (comstyle "")) ;; Normalize (when (consp start) ! (setq end (or (cdr start) end)) (setq start (car start))) (when (char-valid-p start) (setq start (char-to-string start))) (cond --- 286,301 ---- (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 (char-valid-p start) (setq start (char-to-string start))) (cond *************** *** 360,377 **** imenu-case-fold-search t)) ;; This generic mode is always defined ! (define-generic-mode 'default-generic-mode (list ?#) nil nil nil nil) ;; A more general solution would allow us to enter generic-mode for ;; *any* comment character, but would require us to synthesize a new ;; generic-mode on the fly. I think this gives us most of what we ;; want. (defun generic-mode-find-file-hook () ! "Hook function to enter `default-generic-mode' automatically. ! Done if the first few lines of a file in `fundamental-mode' start with ! a match for the regexp in `generic-find-file-regexp', unless the ! file's name matches the regexp which is the value of the variable ! `generic-ignore-files-regexp'. This hook will be installed if the variable `generic-use-find-file-hook' is non-nil. The variable `generic-lines-to-scan' determines the number of lines to look at." --- 363,382 ---- imenu-case-fold-search t)) ;; This generic mode is always defined ! (define-generic-mode default-generic-mode (list ?#) nil nil nil nil) ;; A more general solution would allow us to enter generic-mode for ;; *any* comment character, but would require us to synthesize a new ;; generic-mode on the fly. I think this gives us most of what we ;; want. (defun generic-mode-find-file-hook () ! "Hook function to enter Default-Generic mode automatically. ! ! Done if the first few lines of a file in Fundamental mode start ! with a match for the regexp in `generic-find-file-regexp', unless ! the file's name matches the regexp which is the value of the ! variable `generic-ignore-files-regexp'. ! This hook will be installed if the variable `generic-use-find-file-hook' is non-nil. The variable `generic-lines-to-scan' determines the number of lines to look at." *************** *** 390,397 **** (default-generic-mode))))) (defun generic-mode-ini-file-find-file-hook () ! "Hook function to enter default-generic-mode automatically for INI files. ! Done if the first few lines of a file in `fundamental-mode' look like an INI file. This hook is NOT installed by default." (and (eq major-mode 'fundamental-mode) (save-excursion --- 395,402 ---- (default-generic-mode))))) (defun generic-mode-ini-file-find-file-hook () ! "Hook function to enter Default-Generic mode automatically for INI files. ! Done if the first few lines of a file in Fundamental mode look like an INI file. This hook is NOT installed by default." (and (eq major-mode 'fundamental-mode) (save-excursion