# HG changeset patch # User Daniel Pfeiffer # Date 1116274389 0 # Node ID 6ac7ed8e212be7450a3ab0bd502c370ca155f644 # Parent fbdd9998e4ce9757137d590e2f452915e83ffdbe (makefile-dependency-regex): Turn it into a var, and refine it to mask one more level of nested vars. (makefile-rule-action-regex): Turn it into a var, and refine it so it recognizes backslashed continuation lines as belonging to the same command. (makefile-macroassign-regex): Refine it so it recognizes backslashed continuation lines as belonging to the same command. (makefile-var-use-regex): Don't look at the next char, because it might be the same one to be skipped by the initial [^$], leading to an overlooked variable use. (makefile-make-font-lock-keywords): Remove two parameters, which are now variables that some of the modes set locally. Handle dependency and rule action matching through functions, because regexps alone match too often. Dependency matching now comes last, so it can check, whether a colon already matched something else. (makefile-mode): Inform that font-lock improves makefile parsing capabilities. (makefile-match-dependency, makefile-match-action): New functions. diff -r fbdd9998e4ce -r 6ac7ed8e212b lisp/progmodes/make-mode.el --- a/lisp/progmodes/make-mode.el Mon May 16 18:23:25 2005 +0000 +++ b/lisp/progmodes/make-mode.el Mon May 16 20:13:09 2005 +0000 @@ -257,26 +257,24 @@ ;; Note that the first big 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-dependency-regex - ;; Allow for one nested level $($(var:a=b):c=d) - ;; Scan non-$ constructs char by char, so we don't miss a $ while allowing $$. - ;; Since we must allow space between targets, I then don't know how to evite a command starting with :. - "^ *\\(\\(?:\\$[({]\\(?:\\$[({][^ \t\n#})]+?[})]\\|[^\n#]\\)+?[})]\\|[^\n#:=]\\)+?\\)[ \t]*:\\(?:[ \t]*$\\|[^=\n].*$\\)" +(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]*\\(.+\\)\\)?\\)" "Regex used to find dependency lines in a makefile.") -(defconst makefile-rule-action-regex - "^\t[ \t]*\\([-@]*\\)[ \t]*\\(.+\\)" +(defvar makefile-rule-action-regex + "^\t[ \t]*\\([-@]*\\)[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)" "Regex used to highlight 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][^:#= \t\n]*\\)[ \t]*\\(?:!=[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)\\|[*:+]?[:?]?=\\)" "Regex used to find macro assignment lines in a makefile.") (defconst makefile-var-use-regex - "[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\|[@%[ \t]*\\([^: \t\n#]*\\)") (1 font-lock-keyword-face) (2 font-lock-variable-name-face)) - ,(if negation - `(,negation (1 font-lock-negation-char-face prepend) - (2 font-lock-negation-char-face prepend t))) + ,@(if negation + `((,negation (1 font-lock-negation-char-face prepend) + (2 font-lock-negation-char-face prepend t)))) ,@(if space '(;; Highlight lines that contain just whitespace. @@ -376,28 +371,27 @@ ;; They can make a tab fail to be effective. ("^\\( +\\)\t" 1 makefile-space-face))) - ,@font-lock-keywords)) + ,@font-lock-keywords + + ;; Do dependencies. + (makefile-match-dependency + (1 'makefile-targets-face prepend) + (3 'makefile-shell-face prepend t)))) (defconst makefile-font-lock-keywords (makefile-make-font-lock-keywords - makefile-dependency-regex - makefile-rule-action-regex makefile-var-use-regex makefile-statements t)) (defconst makefile-automake-font-lock-keywords (makefile-make-font-lock-keywords - makefile-dependency-regex - makefile-rule-action-regex makefile-var-use-regex makefile-automake-statements t)) (defconst makefile-gmake-font-lock-keywords (makefile-make-font-lock-keywords - makefile-dependency-regex - makefile-rule-action-regex makefile-var-use-regex makefile-gmake-statements t @@ -407,8 +401,8 @@ 1 'makefile-targets-face prepend) ;; $(function ...) ${function ...} - '("[^$]\\$[({]\\(\\S +\\s \\)" - 1 font-lock-function-name-face) + '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\s \\)" + 1 font-lock-function-name-face prepend) ;; $(shell ...) ${shell ...} '("[^$]\\$\\([({]\\)shell[ \t]+" @@ -417,24 +411,23 @@ (defconst makefile-makepp-font-lock-keywords (makefile-make-font-lock-keywords - makefile-dependency-regex - ;; Don't care about initial tab, but I don't know how to font-lock correctly without. - "^\t[ \t]*\\(\\(?:[ \t]*noecho\\>\\|[ \t]*ignore[-_]error\\>\\|[ \t]*[-@]+\\)*\\)[ \t]*\\(\\(&\\S +\\)?.+\\)" makefile-var-use-regex makefile-makepp-statements nil "^\\(?: [ \t]*\\)?\\(?:and[ \t]+\\|else[ \t]+\\|or[ \t]+\\)?if\\(n\\)\\(?:def\\|eq\\|sys\\)\\>" - '("[^$]\\(\\$[({]\\(?:target\\|output\\)s?[})]\\)" + '("[^$]\\(\\$[({]\\(?:target\\|output\\)s?\\_>.*?[})]\\)" 1 'makefile-targets-face prepend) ;; Colon modifier keywords. - '(":\\s *\\(build_c\\(?:ache\\|heck\\)\\|env\\(?:ironment\\)?\\|foreach\\|signature\\|scanner\\|quickscan\\|smartscan\\)\\>" - 1 font-lock-keyword-face t) + '("\\(:\\s *\\)\\(build_c\\(?:ache\\|heck\\)\\|env\\(?:ironment\\)?\\|foreach\\|signature\\|scanner\\|quickscan\\|smartscan\\)\\>\\([^:\n]*\\)" + (1 font-lock-type-face t) + (2 font-lock-keyword-face t) + (3 font-lock-variable-name-face t)) ;; $(function ...) $((function ...)) ${function ...} ${{function ...}} - '("[^$]\\$\\(((?\\|{{?\\)\\(\\S +\\s \\)" - 2 font-lock-function-name-face) + '("[^$]\\$\\(?:((?\\|{{?\\)\\([-a-zA-Z0-9_.]+\\s \\)" + 1 font-lock-function-name-face prepend) ;; $(shell ...) $((shell ...)) ${shell ...} ${{shell ...}} '("[^$]\\$\\(((?\\|{{?\\)shell\\(?:[-_]\\(?:global[-_]\\)?once\\)?[ \t]+" @@ -466,11 +459,9 @@ '("perl[-_]begin\\s *\\(?:\\s #.*\\)?\n\\(\\(?:.*\n\\)+?\\)\\s *perl[-_]end\\>" 1 'makefile-makepp-perl-face t))) -;; A lot more could be done for variables here: (defconst makefile-bsdmake-font-lock-keywords (makefile-make-font-lock-keywords - "^ *\\(\\(?:\\$[({]\\(?:\\$[({][^\n#})]+?[})]\\|[^\n#]\\)+?[})]\\|[^\n#:=]\\)+?\\)[ \t]*[:!]\\(?:[ \t]*$\\|[^=\n].*$\\)" - "^\t[ \t]*\\([-+@]*\\)[ \t]*\\(.+\\)" + ;; A lot more could be done for variables here: makefile-var-use-regex makefile-bsdmake-statements t @@ -489,9 +480,8 @@ ("\\\\\n" 0 "."))) (defvar makefile-imenu-generic-expression - (list - (list "Dependencies" makefile-dependency-regex 1) - (list "Macro Assignment" makefile-macroassign-regex 1)) + `(("Dependencies" ,makefile-dependency-regex 1) + ("Macro Assignment" ,makefile-macroassign-regex 1)) "Imenu generic expression for Makefile mode. See `imenu-generic-expression'.") ;;; ------------------------------------------------------------ @@ -695,6 +685,11 @@ 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 +example to see that a rule action `echo foo: bar' is a not rule +dependency, despite the colon. + \\{makefile-mode-map} In the browser, use the following keys: @@ -849,14 +844,26 @@ ;;;###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\\)*.+\\)") + (setq font-lock-defaults `(makefile-makepp-font-lock-keywords ,@(cdr font-lock-defaults)))) ;;;###autoload (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]*\\(.+\\)\\)?\\)") + (set (make-local-variable 'makefile-rule-action-regex) + "^\t[ \t]*\\([-+@]*\\)[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)") (setq font-lock-defaults - `(makefile-bsdmake-font-lock-keywords ,@(cdr font-lock-defaults)))) + `(makefile-bsdmake-font-lock-keywords ,@(cdr font-lock-defaults)) + imenu-generic-expression + `(("Dependencies" ,makefile-dependency-regex 1) + ,@(cdr imenu-generic-expression)))) @@ -867,7 +874,7 @@ (interactive) (let ((here (point))) (end-of-line) - (if (re-search-forward makefile-dependency-regex (point-max) t) + (if (makefile-match-dependency (point-max)) (progn (beginning-of-line) t) ; indicate success (goto-char here) nil))) @@ -876,7 +883,7 @@ (interactive) (let ((here (point))) (beginning-of-line) - (if (re-search-backward makefile-dependency-regex (point-min) t) + (if (makefile-match-dependency (point-min) t) (progn (beginning-of-line) t) ; indicate success (goto-char here) nil))) @@ -983,7 +990,7 @@ (setq makefile-has-prereqs nil) (save-excursion (goto-char (point-min)) - (while (re-search-forward makefile-dependency-regex nil t) + (while (makefile-match-dependency nil) (makefile-add-this-line-targets))) (message "Read targets OK."))) @@ -1676,6 +1683,23 @@ ((string= s "{{") "\\(.*?\\)[ \t]*}}"))) (if s (looking-at s)))) +(defun makefile-match-dependency (bound &optional backward) + "Search for `makefile-dependency-regex' up to BOUND. +Optionally search BACKWARD. +Checks that the colon has not already been fontified, else we +matched in a rule action." + (catch 'found + (while (funcall (if backward 're-search-backward 're-search-forward) + makefile-dependency-regex bound t) + (or (get-text-property (match-beginning 2) 'face) + (throw 'found t))))) + +(defun makefile-match-action (bound) + (catch 'found + (while (re-search-forward makefile-rule-action-regex bound t) + (or (eq ?\\ (char-after (- (match-beginning 0) 2))) + (throw 'found t))))) + (defun makefile-do-macro-insertion (macro-name) "Insert a macro reference." (if (not (zerop (length macro-name)))