X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/93d7a3669284221c9272784875f69c047873fe04..efee6a6d9cec2af824b8355c93d8f47b72a685a8:/lisp/progmodes/make-mode.el diff --git a/lisp/progmodes/make-mode.el b/lisp/progmodes/make-mode.el index 05c3ac5078..594462d512 100644 --- a/lisp/progmodes/make-mode.el +++ b/lisp/progmodes/make-mode.el @@ -1,6 +1,7 @@ ;;; make-mode.el --- makefile editing commands for Emacs -;; Copyright (C) 1992,94,99,2000,2001, 2002, 2003 Free Software Foundation, Inc. +;; Copyright (C) 1992, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, +;; 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. ;; Author: Thomas Neumann ;; Eric S. Raymond @@ -10,10 +11,10 @@ ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify +;; 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. +;; the Free Software Foundation, either version 3 of the License, 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 @@ -21,9 +22,7 @@ ;; 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. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -96,38 +95,39 @@ (defgroup makefile nil "Makefile editing commands for Emacs." + :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) :group 'tools :prefix "makefile-") -(defface makefile-space-face +(defface makefile-space '((((class color)) (:background "hotpink")) (t (:reverse-video t))) "Face to use for highlighting leading spaces in Font-Lock mode." - :group 'faces :group 'makefile) +(define-obsolete-face-alias 'makefile-space-face 'makefile-space "22.1") -(defface makefile-targets-face +(defface makefile-targets ;; This needs to go along both with foreground and background colors (i.e. shell) - '((t (:underline t))) + '((t (:inherit font-lock-function-name-face))) "Face to use for additionally highlighting rule targets in Font-Lock mode." - :group 'faces - :group 'makefile) + :group 'makefile + :version "22.1") -(defface makefile-shell-face - '((((class color) (background light)) (:background "seashell1")) - (((class color) (background dark)) (:background "seashell4")) - (t (:reverse-video t))) +(defface makefile-shell + () + ;;'((((class color) (min-colors 88) (background light)) (:background "seashell1")) + ;; (((class color) (min-colors 88) (background dark)) (:background "seashell4"))) "Face to use for additionally highlighting Shell commands in Font-Lock mode." - :group 'faces - :group 'makefile) + :group 'makefile + :version "22.1") -(defface makefile-makepp-perl-face +(defface makefile-makepp-perl '((((class color) (background light)) (:background "LightBlue1")) ; Camel Book (((class color) (background dark)) (:background "DarkBlue")) (t (:reverse-video t))) "Face to use for additionally highlighting Perl code in Font-Lock mode." - :group 'faces - :group 'makefile) + :group 'makefile + :version "22.1") (defcustom makefile-browser-buffer-name "*Macros and Targets*" "*Name of the macro- and target browser buffer." @@ -231,19 +231,20 @@ to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\"." ;; Special targets for DMake, Sun's make ... ;; (defcustom makefile-special-targets-list - '(("DEFAULT") ("DONE") ("ERROR") ("EXPORT") - ("FAILED") ("GROUPEPILOG") ("GROUPPROLOG") ("IGNORE") - ("IMPORT") ("INCLUDE") ("INCLUDEDIRS") ("INIT") - ("KEEP_STATE") ("MAKEFILES") ("MAKE_VERSION") ("NO_PARALLEL") - ("PARALLEL") ("PHONY") ("PRECIOUS") ("REMOVE") - ("SCCS_GET") ("SILENT") ("SOURCE") ("SUFFIXES") - ("WAIT") ("c.o") ("C.o") ("m.o") - ("el.elc") ("y.c") ("s.o")) - "*List of special targets. + '("DEFAULT" "DONE" "ERROR" "EXPORT" + "FAILED" "GROUPEPILOG" "GROUPPROLOG" "IGNORE" + "IMPORT" "INCLUDE" "INCLUDEDIRS" "INIT" + "KEEP_STATE" "MAKEFILES" "MAKE_VERSION" "NO_PARALLEL" + "PARALLEL" "PHONY" "PRECIOUS" "REMOVE" + "SCCS_GET" "SILENT" "SOURCE" "SUFFIXES" + "WAIT" "c.o" "C.o" "m.o" + "el.elc" "y.c" "s.o") + "List of special targets. You will be offered to complete on one of those in the minibuffer whenever you enter a \".\" at the beginning of a line in `makefile-mode'." :type '(repeat (list string)) :group 'makefile) +(put 'makefile-special-targets-list 'risky-local-variable t) (defcustom makefile-runtime-macros-list '(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$")) @@ -259,21 +260,40 @@ not be enclosed in { } or ( )." ;; index in makefile-imenu-generic-expression. (defvar makefile-dependency-regex ;; Allow for two nested levels $(v1:$(v2:$(v3:a=b)=c)=d) - "^ *\\(\\(?: *\\$\\(?:[({]\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[^({]\\|.[^\n$#})]+?[})]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\| *[^ \n$#:=]+\\)+?\\)[ \t]*\\(:\\)\\(?:[ \t]*$\\|[^=\n]\\(?:[^#\n]*?;[ \t]*\\(.+\\)\\)?\\)" + "^\\(\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[^({]\\|.[^\n$#})]+?[})]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#:=]\\)+?\\)\\(:\\)\\(?:[ \t]*$\\|[^=\n]\\(?:[^#\n]*?;[ \t]*\\(.+\\)\\)?\\)" "Regex used to find dependency lines in a makefile.") +(defconst makefile-bsdmake-dependency-regex + (progn (string-match (regexp-quote "\\(:\\)") makefile-dependency-regex) + (replace-match "\\([:!]\\)" t t makefile-dependency-regex)) + "Regex used to find dependency lines in a BSD makefile.") + (defvar makefile-dependency-skip "^:" "Characters to skip to find a line that might be a dependency.") (defvar makefile-rule-action-regex - "^\t[ \t]*\\([-@]*\\)[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)" + "^\t[ \t]*\\(?:\\([-@]+\\)[ \t]*\\)\\(.*\\(?:\\\\\n.*\\)*\\)" "Regex used to highlight rule action lines in font lock mode.") +(defconst makefile-makepp-rule-action-regex + ;; Don't care about initial tab, but I don't know how to font-lock correctly without. + "^\t[ \t]*\\(\\(?:\\(?:noecho\\|ignore[-_]error\\|[-@]+\\)[ \t]*\\)*\\)\\(\\(&\\S +\\)?\\(?:.*\\\\\n\\)*.*\\)" + "Regex used to highlight makepp rule action lines in font lock mode.") + +(defconst makefile-bsdmake-rule-action-regex + (progn (string-match "-@" makefile-rule-action-regex) + (replace-match "-+@" t t makefile-rule-action-regex)) + "Regex used to highlight BSD rule action lines in font lock mode.") + ;; Note that the first and second subexpression is used by font lock. Note ;; that if you change this regexp you might have to fix the imenu index in ;; makefile-imenu-generic-expression. (defconst makefile-macroassign-regex - "^ *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*\\(?:!=[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)\\|[*:+]?[:?]?=[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)\\)" + ;; We used to match not just the varname but also the whole value + ;; (spanning potentially several lines). + ;; "^ *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*\\(?:!=[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)\\|[*:+]?[:?]?=[ \t]*\\(\\(?:.*\\\\\n\\)*.*\\)\\)" + ;; What about the define statement? What about differentiating this for makepp? + "\\(?:^\\|^export\\|^override\\|:\\|: *override\\) *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*\\(?:!=\\|[*:+]?[:?]?=\\)" "Regex used to find macro assignment lines in a makefile.") (defconst makefile-var-use-regex @@ -284,9 +304,7 @@ not be enclosed in { } or ( )." "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)" "Regex for filenames that will NOT be included in the target list.") -(if (fboundp 'facemenu-unlisted-faces) - (add-to-list 'facemenu-unlisted-faces 'makefile-space-face)) -(defvar makefile-space-face 'makefile-space-face +(defvar makefile-space 'makefile-space "Face to use for highlighting leading spaces in Font-Lock mode.") ;; These lists were inspired by the old solution. But they are silly, because @@ -299,9 +317,9 @@ not be enclosed in { } or ( )." "List of keywords understood by automake.") (defconst makefile-gmake-statements - `("-sinclude" "sinclude" "override" "vpath" + `("-sinclude" "sinclude" "vpath" ; makefile-makepp-statements takes rest "ifdef" "ifndef" "ifeq" "ifneq" "-include" "define" "endef" "export" - "unexport" + "override define" "override" "unexport" ,@(cdr makefile-automake-statements)) "List of keywords understood by gmake.") @@ -310,13 +328,14 @@ not be enclosed in { } or ( )." `("and ifdef" "and ifndef" "and ifeq" "and ifneq" "and ifperl" "and ifmakeperl" "and ifsys" "and ifnsys" "build_cache" "build_check" "else ifdef" "else ifndef" "else ifeq" "else ifneq" "else ifperl" - "else ifmakeperl" "else ifsys" "else ifnsys" "enddef" "load_makefile" - "ifperl" "ifmakeperl" "ifsys" "ifnsys" "_include" "makeperl" "makesub" - "no_implicit_load" "perl" "perl-begin" "perl_begin" "perl-end" "perl_end" - "prebuild" "or ifdef" "or ifndef" "or ifeq" "or ifneq" "or ifperl" - "or ifmakeperl" "or ifsys" "or ifnsys" "register_command_parser" + "else ifmakeperl" "else ifsys" "else ifnsys" "enddef" "global" + "load_makefile" "ifperl" "ifmakeperl" "ifsys" "ifnsys" "_include" + "makeperl" "makesub" "no_implicit_load" "perl" "perl-begin" "perl_begin" + "perl-end" "perl_end" "prebuild" "or ifdef" "or ifndef" "or ifeq" + "or ifneq" "or ifperl" "or ifmakeperl" "or ifsys" "or ifnsys" + "override export" "override global" "register_command_parser" "register_scanner" "repository" "runtime" "signature" "sub" - ,@(nthcdr 4 makefile-gmake-statements)) + ,@(nthcdr 3 makefile-gmake-statements)) "List of keywords understood by gmake.") (defconst makefile-bsdmake-statements @@ -331,14 +350,15 @@ not be enclosed in { } or ( )." (,makefile-macroassign-regex (1 font-lock-variable-name-face) ;; This is for after != - (2 'makefile-shell-face prepend t) + (2 'makefile-shell prepend t) ;; This is for after normal assignment (3 'font-lock-string-face prepend t)) ;; Rule actions. + ;; FIXME: When this spans multiple lines we need font-lock-multiline. (makefile-match-action - (1 font-lock-type-face) - (2 'makefile-shell-face prepend) + (1 font-lock-type-face nil t) + (2 'makefile-shell prepend) ;; Only makepp has builtin commands. (3 font-lock-builtin-face prepend t)) @@ -350,7 +370,7 @@ not be enclosed in { } or ( )." ("[^$]\\$\\([@%\\)" 1 font-lock-constant-face prepend) ("[^$]\\(\\$[@%*]\\)" - 1 'makefile-targets-face prepend) + 1 'makefile-targets append) ;; Fontify conditionals and includes. (,(concat "^\\(?: [ \t]*\\)?" @@ -365,22 +385,22 @@ not be enclosed in { } or ( )." ,@(if space '(;; Highlight lines that contain just whitespace. ;; They can cause trouble, especially if they start with a tab. - ("^[ \t]+$" . makefile-space-face) + ("^[ \t]+$" . makefile-space) ;; Highlight shell comments that Make treats as commands, ;; since these can fool people. - ("^\t+#" 0 makefile-space-face t) + ("^\t+#" 0 makefile-space t) ;; Highlight spaces that precede tabs. ;; They can make a tab fail to be effective. - ("^\\( +\\)\t" 1 makefile-space-face))) + ("^\\( +\\)\t" 1 makefile-space))) ,@font-lock-keywords ;; Do dependencies. (makefile-match-dependency - (1 'makefile-targets-face prepend) - (3 'makefile-shell-face prepend t)))) + (1 'makefile-targets prepend) + (3 'makefile-shell prepend t)))) (defconst makefile-font-lock-keywords (makefile-make-font-lock-keywords @@ -402,7 +422,7 @@ not be enclosed in { } or ( )." "^\\(?: [ \t]*\\)?if\\(n\\)\\(?:def\\|eq\\)\\>" '("[^$]\\(\\$[({][@%*][DF][})]\\)" - 1 'makefile-targets-face prepend) + 1 'makefile-targets append) ;; $(function ...) ${function ...} '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\s \\)" @@ -411,7 +431,7 @@ not be enclosed in { } or ( )." ;; $(shell ...) ${shell ...} '("[^$]\\$\\([({]\\)shell[ \t]+" makefile-match-function-end nil nil - (1 'makefile-shell-face prepend t)))) + (1 'makefile-shell prepend t)))) (defconst makefile-makepp-font-lock-keywords (makefile-make-font-lock-keywords @@ -420,8 +440,8 @@ not be enclosed in { } or ( )." nil "^\\(?: [ \t]*\\)?\\(?:and[ \t]+\\|else[ \t]+\\|or[ \t]+\\)?if\\(n\\)\\(?:def\\|eq\\|sys\\)\\>" - '("[^$]\\(\\$[({]\\(?:target\\|output\\)s?\\_>.*?[})]\\)" - 1 'makefile-targets-face prepend) + '("[^$]\\(\\$[({]\\(?:output\\|stem\\|target\\)s?\\_>.*?[})]\\)" + 1 'makefile-targets append) ;; Colon modifier keywords. '("\\(:\\s *\\)\\(build_c\\(?:ache\\|heck\\)\\|env\\(?:ironment\\)?\\|foreach\\|signature\\|scanner\\|quickscan\\|smartscan\\)\\>\\([^:\n]*\\)" @@ -436,32 +456,32 @@ not be enclosed in { } or ( )." ;; $(shell ...) $((shell ...)) ${shell ...} ${{shell ...}} '("[^$]\\$\\(((?\\|{{?\\)shell\\(?:[-_]\\(?:global[-_]\\)?once\\)?[ \t]+" makefile-match-function-end nil nil - (1 'makefile-shell-face prepend t)) + (1 'makefile-shell prepend t)) ;; $(perl ...) $((perl ...)) ${perl ...} ${{perl ...}} '("[^$]\\$\\(((?\\|{{?\\)makeperl[ \t]+" makefile-match-function-end nil nil - (1 'makefile-makepp-perl-face prepend t)) + (1 'makefile-makepp-perl prepend t)) '("[^$]\\$\\(((?\\|{{?\\)perl[ \t]+" makefile-match-function-end nil nil - (1 'makefile-makepp-perl-face t t)) + (1 'makefile-makepp-perl t t)) ;; Can we unify these with (if (match-end 1) 'prepend t)? - '("ifmakeperl\\s +\\(.*\\)" 1 'makefile-makepp-perl-face prepend) - '("ifperl\\s +\\(.*\\)" 1 'makefile-makepp-perl-face t) + '("ifmakeperl\\s +\\(.*\\)" 1 'makefile-makepp-perl prepend) + '("ifperl\\s +\\(.*\\)" 1 'makefile-makepp-perl t) ;; Perl block single- or multiline, as statement or rule action. ;; Don't know why the initial newline in 2nd variant of group 2 doesn't get skipped. '("\\" - 1 'makefile-makepp-perl-face t))) + 1 'makefile-makepp-perl t))) (defconst makefile-bsdmake-font-lock-keywords (makefile-make-font-lock-keywords @@ -472,6 +492,19 @@ not be enclosed in { } or ( )." "^\\(?: [ \t]*\\)?\\.\\(?:el\\)?if\\(n?\\)\\(?:def\\|make\\)?\\>[ \t]*\\(!?\\)" '("^[ \t]*\\.for[ \t].+[ \t]\\(in\\)\\>" 1 font-lock-keyword-face))) +(defconst makefile-imake-font-lock-keywords + (append + (makefile-make-font-lock-keywords + makefile-var-use-regex + makefile-statements + t + nil + '("^XCOMM.*$" . font-lock-comment-face) + '("XVAR\\(?:use\\|def\\)[0-9]" 0 font-lock-keyword-face prepend) + '("@@" . font-lock-preprocessor-face) + ) + cpp-font-lock-keywords)) + (defconst makefile-font-lock-syntactic-keywords ;; From sh-script.el. @@ -514,7 +547,8 @@ This should identify a `make' command that can handle the `-q' option." :type 'string :group 'makefile) -(defcustom makefile-query-one-target-method 'makefile-query-by-make-minus-q +(defcustom makefile-query-one-target-method-function + 'makefile-query-by-make-minus-q "*Function to call to determine whether a make target is up to date. The function must satisfy this calling convention: @@ -530,6 +564,8 @@ The function must satisfy this calling convention: makefile, any nonzero integer value otherwise." :type 'function :group 'makefile) +(defvaralias 'makefile-query-one-target-method + 'makefile-query-one-target-method-function) (defcustom makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*" "*Name of the Up-to-date overview buffer." @@ -545,7 +581,8 @@ The function must satisfy this calling convention: (define-abbrev-table 'makefile-mode-abbrev-table ())) (defvar makefile-mode-map - (let ((map (make-sparse-keymap))) + (let ((map (make-sparse-keymap)) + (opt-map (make-sparse-keymap))) ;; set up the keymap (define-key map "\C-c:" 'makefile-insert-target-ref) (if makefile-electric-keys @@ -564,6 +601,7 @@ The function must satisfy this calling convention: (define-key map "\C-c\C-m\C-a" 'makefile-automake-mode) (define-key map "\C-c\C-m\C-b" 'makefile-bsdmake-mode) (define-key map "\C-c\C-m\C-g" 'makefile-gmake-mode) + (define-key map "\C-c\C-m\C-i" 'makefile-imake-mode) (define-key map "\C-c\C-m\C-m" 'makefile-mode) (define-key map "\C-c\C-m\C-p" 'makefile-makepp-mode) (define-key map "\M-p" 'makefile-previous-dependency) @@ -574,53 +612,108 @@ The function must satisfy this calling convention: (define-key map [menu-bar makefile-mode] (cons "Makefile" (make-sparse-keymap "Makefile"))) + (define-key map [menu-bar makefile-mode makefile-type] + (cons "Switch Makefile Type" opt-map)) + (define-key opt-map [makefile-makepp-mode] + '(menu-item "Makepp" makefile-makepp-mode + :help "An adapted `makefile-mode' that knows about makepp" + :button (:radio . (eq major-mode 'makefile-makepp-mode)))) + (define-key opt-map [makefile-imake-mode] + '(menu-item "Imake" makefile-imake-mode + :help "An adapted `makefile-mode' that knows about imake" + :button (:radio . (eq major-mode 'makefile-imake-mode)))) + (define-key opt-map [makefile-mode] + '(menu-item "Classic" makefile-mode + :help "`makefile-mode' with no special functionality" + :button (:radio . (eq major-mode 'makefile-mode)))) + (define-key opt-map [makefile-bsdmake-mode] + '(menu-item "BSD" makefile-bsdmake-mode + :help "An adapted `makefile-mode' that knows about BSD make" + :button (:radio . (eq major-mode 'makefile-bsdmake-mode)))) + (define-key opt-map [makefile-automake-mode] + '(menu-item "Automake" makefile-automake-mode + :help "An adapted `makefile-mode' that knows about automake" + :button (:radio . (eq major-mode 'makefile-automake-mode)))) + (define-key opt-map [makefile-gmake-mode] + '(menu-item "GNU make" makefile-gmake-mode + :help "An adapted `makefile-mode' that knows about GNU make" + :button (:radio . (eq major-mode 'makefile-gmake-mode)))) (define-key map [menu-bar makefile-mode browse] - '("Pop up Makefile Browser" . makefile-switch-to-browser)) - (define-key map [menu-bar makefile-mode complete] - '("Complete Target or Macro" . makefile-complete)) + '(menu-item "Pop up Makefile Browser" makefile-switch-to-browser + ;; XXX: this needs a better string, the function is not documented... + :help "Pop up Makefile Browser")) + (define-key map [menu-bar makefile-mode overview] + '(menu-item "Up To Date Overview" makefile-create-up-to-date-overview + :help "Create a buffer containing an overview of the state of all known targets")) + ;; Target related + (define-key map [menu-bar makefile-mode separator1] '("----")) + (define-key map [menu-bar makefile-mode pickup-file] + '(menu-item "Pick File Name as Target" makefile-pickup-filenames-as-targets + :help "Scan the current directory for filenames to use as targets")) + (define-key map [menu-bar makefile-mode function] + '(menu-item "Insert GNU make function" makefile-insert-gmake-function + :help "Insert a GNU make function call")) (define-key map [menu-bar makefile-mode pickup] - '("Find Targets and Macros" . makefile-pickup-everything)) - + '(menu-item "Find Targets and Macros" makefile-pickup-everything + :help "Notice names of all macros and targets in Makefile")) + (define-key map [menu-bar makefile-mode complete] + '(menu-item "Complete Target or Macro" makefile-complete + :help "Perform completion on Makefile construct preceding point")) + (define-key map [menu-bar makefile-mode backslash] + '(menu-item "Backslash Region" makefile-backslash-region + :help "Insert, align, or delete end-of-line backslashes on the lines in the region")) + ;; Motion + (define-key map [menu-bar makefile-mode separator] '("----")) (define-key map [menu-bar makefile-mode prev] - '("Move to Previous Dependency" . makefile-previous-dependency)) + '(menu-item "Move to Previous Dependency" makefile-previous-dependency + :help "Move point to the beginning of the previous dependency line")) (define-key map [menu-bar makefile-mode next] - '("Move to Next Dependency" . makefile-next-dependency)) + '(menu-item "Move to Next Dependency" makefile-next-dependency + :help "Move point to the beginning of the next dependency line")) map) "The keymap that is used in Makefile mode.") -(defvar makefile-browser-map nil + +(defvar makefile-browser-map + (let ((map (make-sparse-keymap))) + (define-key map "n" 'makefile-browser-next-line) + (define-key map "\C-n" 'makefile-browser-next-line) + (define-key map "p" 'makefile-browser-previous-line) + (define-key map "\C-p" 'makefile-browser-previous-line) + (define-key map " " 'makefile-browser-toggle) + (define-key map "i" 'makefile-browser-insert-selection) + (define-key map "I" 'makefile-browser-insert-selection-and-quit) + (define-key map "\C-c\C-m" 'makefile-browser-insert-continuation) + (define-key map "q" 'makefile-browser-quit) + ;; disable horizontal movement + (define-key map "\C-b" 'undefined) + (define-key map "\C-f" 'undefined) + map) "The keymap that is used in the macro- and target browser.") -(if makefile-browser-map - () - (setq makefile-browser-map (make-sparse-keymap)) - (define-key makefile-browser-map "n" 'makefile-browser-next-line) - (define-key makefile-browser-map "\C-n" 'makefile-browser-next-line) - (define-key makefile-browser-map "p" 'makefile-browser-previous-line) - (define-key makefile-browser-map "\C-p" 'makefile-browser-previous-line) - (define-key makefile-browser-map " " 'makefile-browser-toggle) - (define-key makefile-browser-map "i" 'makefile-browser-insert-selection) - (define-key makefile-browser-map "I" 'makefile-browser-insert-selection-and-quit) - (define-key makefile-browser-map "\C-c\C-m" 'makefile-browser-insert-continuation) - (define-key makefile-browser-map "q" 'makefile-browser-quit) - ;; disable horizontal movement - (define-key makefile-browser-map "\C-b" 'undefined) - (define-key makefile-browser-map "\C-f" 'undefined)) - - -(defvar makefile-mode-syntax-table nil) -(if makefile-mode-syntax-table + + +(defvar makefile-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\( "() " st) + (modify-syntax-entry ?\) ")( " st) + (modify-syntax-entry ?\[ "(] " st) + (modify-syntax-entry ?\] ")[ " st) + (modify-syntax-entry ?\{ "(} " st) + (modify-syntax-entry ?\} "){ " st) + (modify-syntax-entry ?\' "\" " st) + (modify-syntax-entry ?\` "\" " st) + (modify-syntax-entry ?# "< " st) + (modify-syntax-entry ?\n "> " st) + st)) + +(defvar makefile-imake-mode-syntax-table (copy-syntax-table + makefile-mode-syntax-table)) +(if makefile-imake-mode-syntax-table () - (setq makefile-mode-syntax-table (make-syntax-table)) - (modify-syntax-entry ?\( "() " makefile-mode-syntax-table) - (modify-syntax-entry ?\) ")( " makefile-mode-syntax-table) - (modify-syntax-entry ?\[ "(] " makefile-mode-syntax-table) - (modify-syntax-entry ?\] ")[ " makefile-mode-syntax-table) - (modify-syntax-entry ?\{ "(} " makefile-mode-syntax-table) - (modify-syntax-entry ?\} "){ " makefile-mode-syntax-table) - (modify-syntax-entry ?\' "\" " makefile-mode-syntax-table) - (modify-syntax-entry ?\` "\" " makefile-mode-syntax-table) - (modify-syntax-entry ?# "< " makefile-mode-syntax-table) - (modify-syntax-entry ?\n "> " makefile-mode-syntax-table)) + (modify-syntax-entry ?/ ". 14" makefile-imake-mode-syntax-table) + (modify-syntax-entry ?* ". 23" makefile-imake-mode-syntax-table) + (modify-syntax-entry ?# "'" makefile-imake-mode-syntax-table) + (modify-syntax-entry ?\n ". b" makefile-imake-mode-syntax-table)) ;;; ------------------------------------------------------------ @@ -630,9 +723,11 @@ The function must satisfy this calling convention: (defvar makefile-target-table nil "Table of all target names known for this buffer.") +(put 'makefile-target-table 'risky-local-variable t) (defvar makefile-macro-table nil "Table of all macro names known for this buffer.") +(put 'makefile-macro-table 'risky-local-variable t) (defvar makefile-browser-client "A buffer in Makefile mode that is currently using the browser.") @@ -684,10 +779,10 @@ The function must satisfy this calling convention: If you are editing a file for a different make, try one of the variants `makefile-automake-mode', `makefile-gmake-mode', -`makefile-makepp-mode' or `makefile-bsdmake-mode'. All but the -last should be correctly chosen based on the file name, except if -it is *.mk. This function ends by invoking the function(s) -`makefile-mode-hook'. +`makefile-makepp-mode', `makefile-bsdmake-mode' or, +`makefile-imake-mode'. All but the last should be correctly +chosen based on the file name, except if it is *.mk. This +function ends by invoking the function(s) `makefile-mode-hook'. It is strongly recommended to use `font-lock-mode', because that provides additional parsing information. This is used for @@ -788,8 +883,8 @@ Makefile mode can be configured by modifying the following variables: nil nil ((?$ . ".")) backward-paragraph - (font-lock-syntactic-keywords . makefile-font-lock-syntactic-keywords) - (font-lock-support-mode))) ; JIT breaks on long series of continuation lines. + (font-lock-syntactic-keywords + . makefile-font-lock-syntactic-keywords))) ;; Add-log. (make-local-variable 'add-log-current-defun-function) @@ -849,10 +944,8 @@ Makefile mode can be configured by modifying the following variables: ;;;###autoload (define-derived-mode makefile-makepp-mode makefile-mode "Makeppfile" "An adapted `makefile-mode' that knows about makepp." - (set (make-local-variable 'makefile-rule-action-regex) - ;; Don't care about initial tab, but I don't know how to font-lock correctly without. - "^\t[ \t]*\\(\\(?:\\(?:noecho\\|ignore[-_]error\\|[-@]+\\)[ \t]*\\)*\\)\\(\\(&\\S +\\)?\\(?:.+\\\\\n\\)*.+\\)") - + (set (make-local-variable 'makefile-rule-action-regex) + makefile-makepp-rule-action-regex) (setq font-lock-defaults `(makefile-makepp-font-lock-keywords ,@(cdr font-lock-defaults)) imenu-generic-expression @@ -863,14 +956,27 @@ Makefile mode can be configured by modifying the following variables: (define-derived-mode makefile-bsdmake-mode makefile-mode "BSDmakefile" "An adapted `makefile-mode' that knows about BSD make." (set (make-local-variable 'makefile-dependency-regex) - ;; Identical to default, except allows `!' instead of `:'. - "^ *\\(\\(?: *\\$\\(?:[({]\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[^({]\\|.[^\n$#})]+?[})]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\| *[^ \n$#:=]+\\)+?\\)[ \t]*\\([:!]\\)\\(?:[ \t]*$\\|[^=\n]\\(?:[^#\n]*?;[ \t]*\\(.+\\)\\)?\\)") + makefile-bsdmake-dependency-regex) (set (make-local-variable 'makefile-dependency-skip) "^:!") (set (make-local-variable 'makefile-rule-action-regex) - "^\t[ \t]*\\([-+@]*\\)[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)") + makefile-bsdmake-rule-action-regex) (setq font-lock-defaults `(makefile-bsdmake-font-lock-keywords ,@(cdr font-lock-defaults)))) +;;;###autoload +(define-derived-mode makefile-imake-mode makefile-mode "Imakefile" + "An adapted `makefile-mode' that knows about imake." + :syntax-table makefile-imake-mode-syntax-table + (let ((base `(makefile-imake-font-lock-keywords ,@(cdr font-lock-defaults))) + new) + ;; Remove `font-lock-syntactic-keywords' entry from font-lock-defaults. + (mapc (lambda (elt) + (unless (and (consp elt) + (eq (car elt) 'font-lock-syntactic-keywords)) + (setq new (cons elt new)))) + base) + (setq font-lock-defaults (nreverse new)))) + ;;; Motion code. @@ -897,6 +1003,8 @@ Makefile mode can be configured by modifying the following variables: (backward-char)) (get-text-property (point) 'face) (beginning-of-line) + (if (> (point) (+ (point-min) 2)) + (eq (char-before (1- (point))) ?\\)) (if (looking-at makefile-dependency-regex) (throw 'found t)))) (goto-char pt) @@ -1078,87 +1186,34 @@ The context determines which are considered." (skip-chars-backward "^$(){}:#= \t\n") (point))) (try (buffer-substring beg (point))) - (do-macros nil) - (paren nil)) - - (save-excursion - (goto-char beg) - (let ((pc (preceding-char))) - (cond - ;; Beginning of line means anything. - ((bolp) - ()) - - ;; Preceding "$" means macros only. - ((= pc ?$) - (setq do-macros t)) - - ;; Preceding "$(" or "${" means macros only. - ((and (or (= pc ?{) - (= pc ?\()) - (progn - (setq paren pc) - (backward-char) - (and (not (bolp)) - (= (preceding-char) ?$)))) - (setq do-macros t))))) - - ;; Try completion. - (let* ((table (append (if do-macros - '() - makefile-target-table) - makefile-macro-table)) - (completion (try-completion try table))) - (cond - ;; Exact match, so insert closing paren or colon. - ((eq completion t) - (insert (if do-macros - (if (eq paren ?{) - ?} - ?\)) - (if (save-excursion - (goto-char beg) - (bolp)) - ":" - " ")))) - - ;; No match. - ((null completion) - (message "Can't find completion for \"%s\"" try) - (ding)) - - ;; Partial completion. - ((not (string= try completion)) - ;; FIXME it would be nice to supply the closing paren if an - ;; exact, unambiguous match were found. That is not possible - ;; right now. Ditto closing ":" for targets. - (delete-region beg (point)) - - ;; DO-MACROS means doing macros only. If not that, then check - ;; to see if this completion is a macro. Special insertion - ;; must be done for macros. - (if (or do-macros - (assoc completion makefile-macro-table)) - (let ((makefile-use-curly-braces-for-macros-p - (or (eq paren ?{) - makefile-use-curly-braces-for-macros-p))) - (delete-backward-char 2) - (makefile-do-macro-insertion completion) - (delete-backward-char 1)) - - ;; Just insert targets. - (insert completion))) - - ;; Can't complete any more, so make completion list. FIXME - ;; this doesn't do the right thing when the completion is - ;; actually inserted. I don't think there is an easy way to do - ;; that. - (t - (message "Making completion list...") - (let ((list (all-completions try table))) - (with-output-to-temp-buffer "*Completions*" - (display-completion-list list))) - (message "Making completion list...done")))))) + (paren nil) + (do-macros + (save-excursion + (goto-char beg) + (let ((pc (preceding-char))) + (cond + ;; Preceding "$" means macros only. + ((= pc ?$) + t) + + ;; Preceding "$(" or "${" means macros only. + ((and (memq pc '(?\{ ?\()) + (progn + (setq paren (if (eq paren ?\{) ?\} ?\))) + (backward-char) + (= (preceding-char) ?$))) + t))))) + + (table (apply-partially 'completion-table-with-terminator + (cond + (do-macros (or paren "")) + ((save-excursion (goto-char beg) (bolp)) ":") + (t " ")) + (append (if do-macros + '() + makefile-target-table) + makefile-macro-table)))) + (completion-in-region beg (point) table))) @@ -1243,30 +1298,9 @@ definition and conveniently use this command." (save-excursion (beginning-of-line) (cond - ((looking-at "^#+") - ;; Found a comment. Set the fill prefix, and find the paragraph - ;; boundaries by searching for lines that look like comment-only - ;; lines. - (let ((fill-prefix (match-string-no-properties 0)) - (fill-paragraph-function nil)) - (save-excursion - (save-restriction - (narrow-to-region - ;; Search backwards. - (save-excursion - (while (and (zerop (forward-line -1)) - (looking-at "^#"))) - ;; We may have gone too far. Go forward again. - (or (looking-at "^#") - (forward-line 1)) - (point)) - ;; Search forwards. - (save-excursion - (while (looking-at "^#") - (forward-line)) - (point))) - (fill-paragraph nil) - t)))) + ((looking-at "^[ \t]*#+\\s-*") + ;; Found a comment. Return nil to let normal filling take place. + nil) ;; Must look for backslashed-region before looking for variable ;; assignment. @@ -1295,7 +1329,9 @@ definition and conveniently use this command." (makefile-backslash-region (point-min) (point-max) nil) (goto-char (point-max)) (if (< (skip-chars-backward "\n") 0) - (delete-region (point) (point-max)))))) + (delete-region (point) (point-max))))) + ;; Return non-nil to indicate it's been filled. + t) ((looking-at makefile-macroassign-regex) ;; Have a macro assign. Fill just this line, and then backslash @@ -1304,10 +1340,13 @@ definition and conveniently use this command." (narrow-to-region (point) (line-beginning-position 2)) (let ((fill-paragraph-function nil)) (fill-paragraph nil)) - (makefile-backslash-region (point-min) (point-max) nil))))) + (makefile-backslash-region (point-min) (point-max) nil)) + ;; Return non-nil to indicate it's been filled. + t) - ;; Always return non-nil so we don't fill anything else. - t) + (t + ;; Return non-nil so we don't fill anything else. + t)))) @@ -1395,9 +1434,10 @@ definition and conveniently use this command." (let ((this-line (count-lines (point-min) (point)))) (setq this-line (max 1 this-line)) (makefile-browser-toggle-state-for-line this-line) - (goto-line this-line) + (goto-char (point-min)) + (forward-line (1- this-line)) (let ((inhibit-read-only t)) - (beginning-of-line) + (beginning-of-line) ; redundant? (if (makefile-browser-on-macro-line-p) (let ((macro-name (makefile-browser-this-line-macro-name))) (delete-region (point) (progn (end-of-line) (point))) @@ -1437,7 +1477,7 @@ large dependencies from the browser to the client buffer. Insertion takes place at point." (interactive) (save-excursion - (goto-line 1) + (goto-char (point-min)) (let ((current-line 1)) (while (not (eobp)) (if (makefile-browser-get-state-for-line current-line) @@ -1562,7 +1602,8 @@ with the generated name!" (defun makefile-query-targets (filename target-table prereq-list) "Fill the up-to-date overview buffer. -Checks each target in TARGET-TABLE using `makefile-query-one-target-method' +Checks each target in TARGET-TABLE using +`makefile-query-one-target-method-function' and generates the overview, one line per target name." (insert (mapconcat @@ -1571,7 +1612,7 @@ and generates the overview, one line per target name." (no-prereqs (not (member target-name prereq-list))) (needs-rebuild (or no-prereqs (funcall - makefile-query-one-target-method + makefile-query-one-target-method-function target-name filename)))) (format "\t%s%s" @@ -1596,7 +1637,7 @@ and generates the overview, one line per target name." ;;; ------------------------------------------------------------ (defun makefile-cleanup-continuations () - (if (eq major-mode 'makefile-mode) + (if (derived-mode-p 'makefile-mode) (if (and makefile-cleanup-continuations (not buffer-read-only)) (save-excursion @@ -1611,7 +1652,7 @@ and generates the overview, one line per target name." (defun makefile-warn-suspicious-lines () ;; Returning non-nil cancels the save operation - (if (eq major-mode 'makefile-mode) + (if (derived-mode-p 'makefile-mode) (save-excursion (goto-char (point-min)) (if (re-search-forward "^\\(\t+$\\| +\t\\)" nil t) @@ -1620,7 +1661,7 @@ and generates the overview, one line per target name." (count-lines (point-min) (point))))))))) (defun makefile-warn-continuations () - (if (eq major-mode 'makefile-mode) + (if (derived-mode-p 'makefile-mode) (save-excursion (goto-char (point-min)) (if (re-search-forward "\\\\[ \t]+$" nil t) @@ -1669,11 +1710,12 @@ Then prompts for all required parameters." "To be called as an anchored matcher by font-lock. The anchor must have matched the opening parens in the first group." (let ((s (match-string-no-properties 1))) - (setq s (cond ((string= s "(") "\\(.*?\\)[ \t]*)") - ((string= s "{") "\\(.*?\\)[ \t]*}") - ((string= s "((") "\\(.*?\\)[ \t]*))") - ((string= s "{{") "\\(.*?\\)[ \t]*}}"))) - (if s (looking-at s)))) + ;; FIXME forward-sexp or somesuch would be better? + (if (setq s (cond ((string= s "(") ")") + ((string= s "{") "}") + ((string= s "((") "))") + ((string= s "{{") "}}"))) + (re-search-forward (concat "\\(.*\\)[ \t]*" s) (line-end-position) t)))) (defun makefile-match-dependency (bound) "Search for `makefile-dependency-regex' up to BOUND. @@ -1686,9 +1728,24 @@ matched in a rule action." (forward-char) (or (eq (char-after) ?=) (get-text-property (1- (point)) 'face) + (if (> (line-beginning-position) (+ (point-min) 2)) + (eq (char-before (line-end-position 0)) ?\\)) (when (save-excursion (beginning-of-line) (looking-at makefile-dependency-regex)) + (save-excursion + (let ((deps-end (match-end 1)) + (match-data (match-data))) + (goto-char deps-end) + (skip-chars-backward " \t") + (setq deps-end (point)) + (beginning-of-line) + (skip-chars-forward " \t") + ;; Alter the bounds recorded for subexp 1, + ;; which is what is supposed to match the targets. + (setcar (nthcdr 2 match-data) (point)) + (setcar (nthcdr 3 match-data) deps-end) + (store-match-data match-data))) (end-of-line) (throw 'found (point))))) (goto-char pt)) @@ -1799,9 +1856,13 @@ If it isn't in one, return nil." ;; Don't keep looking across a blank line or comment. (looking-at "$\\|#") (not (zerop (forward-line -1)))))) + ;; Remove leading and trailing whitespace. + (when found + (setq found (replace-regexp-in-string "[ \t]+\\'" "" found)) + (setq found (replace-regexp-in-string "\\`[ \t]+" "" found))) found))) (provide 'make-mode) -;;; arch-tag: bd23545a-de91-44fb-b1b2-feafbb2635a0 +;; arch-tag: bd23545a-de91-44fb-b1b2-feafbb2635a0 ;;; make-mode.el ends here