;;; 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 <tom@smart.bo.open.de>
;; Eric S. Raymond <esr@snark.thyrsus.com>
;; 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
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;; prerequisites.
;;
;; The command C-c C-b pops up a browser window listing all target and
-;; macro names. You can mark or unmark items wit C-c SPC, and insert
+;; macro names. You can mark or unmark items with C-c SPC, and insert
;; all marked items back in the Makefile with C-c TAB.
;;
;; The command C-c TAB in the makefile buffer inserts a GNU make builtin.
(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
- '((((class color)) (:background "hotpink"))
- (t (:reverse-video t)))
+(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
+ ;; This needs to go along both with foreground and background colors (i.e. shell)
+ '((t (:inherit font-lock-function-name-face)))
+ "Face to use for additionally highlighting rule targets in Font-Lock mode."
+ :group 'makefile
+ :version "22.1")
+
+(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 'makefile
+ :version "22.1")
+
+(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 'makefile
+ :version "22.1")
(defcustom makefile-browser-buffer-name "*Macros and Targets*"
"*Name of the macro- and target browser buffer."
;; 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
'(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$"))
;; 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
- "^ *\\([^ \n\t#:=]+\\([ \t]+\\([^ \t\n#:=]+\\|\\$[({][^ \t\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]*$\\|[^=\n]\\(?:[^#\n]*?;[ \t]*\\(.+\\)\\)?\\)"
"Regex used to find dependency lines in a makefile.")
-;; Note that the first 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-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.*\\)*\\)"
+ "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]*[*:+]?[:?]?="
+ ;; 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
+ "[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\|[@%<?^+*][FD]?\\)"
+ "Regex used to find $(macro) uses in a makefile.")
+
(defconst makefile-ignored-files-in-pickup-regex
"\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,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.")
-(defconst makefile-font-lock-keywords
- (list
+;; These lists were inspired by the old solution. But they are silly, because
+;; you can't differentiate what follows. They need to be split up.
+(defconst makefile-statements '("include")
+ "List of keywords understood by standard make.")
+
+(defconst makefile-automake-statements
+ `("if" "else" "endif" ,@makefile-statements)
+ "List of keywords understood by automake.")
+
+(defconst makefile-gmake-statements
+ `("-sinclude" "sinclude" "vpath" ; makefile-makepp-statements takes rest
+ "ifdef" "ifndef" "ifeq" "ifneq" "-include" "define" "endef" "export"
+ "override define" "override" "unexport"
+ ,@(cdr makefile-automake-statements))
+ "List of keywords understood by gmake.")
+
+;; These are even more silly, because you can have more spaces in between.
+(defconst makefile-makepp-statements
+ `("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" "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 3 makefile-gmake-statements))
+ "List of keywords understood by gmake.")
+
+(defconst makefile-bsdmake-statements
+ `(".elif" ".elifdef" ".elifmake" ".elifndef" ".elifnmake" ".else" ".endfor"
+ ".endif" ".for" ".if" ".ifdef" ".ifmake" ".ifndef" ".ifnmake" ".undef")
+ "List of keywords understood by BSD make.")
+
+(defun makefile-make-font-lock-keywords (var keywords space
+ &optional negation
+ &rest font-lock-keywords)
+ `(;; Do macro assignments. These get the "variable-name" face.
+ (,makefile-macroassign-regex
+ (1 font-lock-variable-name-face)
+ ;; This is for after !=
+ (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 nil t)
+ (2 'makefile-shell prepend)
+ ;; Only makepp has builtin commands.
+ (3 font-lock-builtin-face prepend t))
+
+ ;; Variable references even in targets/strings/comments.
+ (,var 1 font-lock-variable-name-face prepend)
+
+ ;; Automatic variable references and single character variable references,
+ ;; but not shell variables references.
+ ("[^$]\\$\\([@%<?^+*_]\\|[a-zA-Z0-9]\\>\\)"
+ 1 font-lock-constant-face prepend)
+ ("[^$]\\(\\$[@%*]\\)"
+ 1 'makefile-targets append)
- ;; Do macro assignments. These get the "variable-name" face rather
- ;; arbitrarily.
- (list makefile-macroassign-regex 1 'font-lock-variable-name-face)
+ ;; Fontify conditionals and includes.
+ (,(concat "^\\(?: [ \t]*\\)?"
+ (regexp-opt keywords t)
+ "\\>[ \t]*\\([^: \t\n#]*\\)")
+ (1 font-lock-keyword-face) (2 font-lock-variable-name-face))
- ;; Do dependencies. These get the function name face.
- (list makefile-dependency-regex 1 'font-lock-function-name-face)
+ ,@(if negation
+ `((,negation (1 font-lock-negation-char-face prepend)
+ (2 font-lock-negation-char-face prepend t))))
- ;; Variable references even in targets/strings/comments.
- '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\|[@%<?^+*][FD]?\\)[}):]"
- 1 font-lock-constant-face prepend)
+ ,@(if space
+ '(;; Highlight lines that contain just whitespace.
+ ;; They can cause trouble, especially if they start with a tab.
+ ("^[ \t]+$" . makefile-space)
- ;; Automatic variable references and single character variable references,
- ;; but not shell variables references.
- '("[^$]\\$\\([@%<?^+*_]\\|[a-zA-Z0-9]\\>\\)"
- 1 font-lock-constant-face prepend)
+ ;; Highlight shell comments that Make treats as commands,
+ ;; since these can fool people.
+ ("^\t+#" 0 makefile-space t)
+
+ ;; Highlight spaces that precede tabs.
+ ;; They can make a tab fail to be effective.
+ ("^\\( +\\)\t" 1 makefile-space)))
+
+ ,@font-lock-keywords
+
+ ;; Do dependencies.
+ (makefile-match-dependency
+ (1 'makefile-targets prepend)
+ (3 'makefile-shell prepend t))))
+
+(defconst makefile-font-lock-keywords
+ (makefile-make-font-lock-keywords
+ makefile-var-use-regex
+ makefile-statements
+ t))
+
+(defconst makefile-automake-font-lock-keywords
+ (makefile-make-font-lock-keywords
+ makefile-var-use-regex
+ makefile-automake-statements
+ t))
+
+(defconst makefile-gmake-font-lock-keywords
+ (makefile-make-font-lock-keywords
+ makefile-var-use-regex
+ makefile-gmake-statements
+ t
+ "^\\(?: [ \t]*\\)?if\\(n\\)\\(?:def\\|eq\\)\\>"
+
+ '("[^$]\\(\\$[({][@%*][DF][})]\\)"
+ 1 'makefile-targets append)
+
+ ;; $(function ...) ${function ...}
+ '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\s \\)"
+ 1 font-lock-function-name-face prepend)
+
+ ;; $(shell ...) ${shell ...}
+ '("[^$]\\$\\([({]\\)shell[ \t]+"
+ makefile-match-function-end nil nil
+ (1 'makefile-shell prepend t))))
+
+(defconst makefile-makepp-font-lock-keywords
+ (makefile-make-font-lock-keywords
+ makefile-var-use-regex
+ makefile-makepp-statements
+ nil
+ "^\\(?: [ \t]*\\)?\\(?:and[ \t]+\\|else[ \t]+\\|or[ \t]+\\)?if\\(n\\)\\(?:def\\|eq\\|sys\\)\\>"
+
+ '("[^$]\\(\\$[({]\\(?:output\\|stem\\|target\\)s?\\_>.*?[})]\\)"
+ 1 'makefile-targets append)
+
+ ;; Colon modifier keywords.
+ '("\\(:\\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 ...}}
+ '("[^$]\\$\\(?:((?\\|{{?\\)\\([-a-zA-Z0-9_.]+\\s \\)"
+ 1 font-lock-function-name-face prepend)
+
+ ;; $(shell ...) $((shell ...)) ${shell ...} ${{shell ...}}
+ '("[^$]\\$\\(((?\\|{{?\\)shell\\(?:[-_]\\(?:global[-_]\\)?once\\)?[ \t]+"
+ makefile-match-function-end nil nil
+ (1 'makefile-shell prepend t))
+
+ ;; $(perl ...) $((perl ...)) ${perl ...} ${{perl ...}}
+ '("[^$]\\$\\(((?\\|{{?\\)makeperl[ \t]+"
+ makefile-match-function-end nil nil
+ (1 'makefile-makepp-perl prepend t))
+ '("[^$]\\$\\(((?\\|{{?\\)perl[ \t]+"
+ makefile-match-function-end nil nil
+ (1 'makefile-makepp-perl t t))
+
+ ;; Can we unify these with (if (match-end 1) 'prepend 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.
+ '("\\<make\\(?:perl\\|sub\\s +\\S +\\)\\s *\n?\\s *{\\(?:{\\s *\n?\\(\\(?:.*\n\\)+?\\)\\s *}\\|\\s *\\(\\(?:.*?\\|\n?\\(?:.*\n\\)+?\\)\\)\\)}"
+ (1 'makefile-makepp-perl prepend t)
+ (2 'makefile-makepp-perl prepend t))
+ '("\\<\\(?:perl\\|sub\\s +\\S +\\)\\s *\n?\\s *{\\(?:{\\s *\n?\\(\\(?:.*\n\\)+?\\)\\s *}\\|\\s *\\(\\(?:.*?\\|\n?\\(?:.*\n\\)+?\\)\\)\\)}"
+ (1 'makefile-makepp-perl t t)
+ (2 'makefile-makepp-perl t t))
+
+ ;; Statement style perl block.
+ '("perl[-_]begin\\s *\\(?:\\s #.*\\)?\n\\(\\(?:.*\n\\)+?\\)\\s *perl[-_]end\\>"
+ 1 'makefile-makepp-perl t)))
+
+(defconst makefile-bsdmake-font-lock-keywords
+ (makefile-make-font-lock-keywords
+ ;; A lot more could be done for variables here:
+ makefile-var-use-regex
+ makefile-bsdmake-statements
+ t
+ "^\\(?: [ \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))
- ;; Fontify conditionals and includes.
- ;; Note that plain `if' is an automake conditional, and not a bug.
- (list
- (concat "^\\(?: [ \t]*\\)?"
- (regexp-opt '("-include" "-sinclude" "include" "sinclude" "ifeq"
- "if" "ifneq" "ifdef" "ifndef" "endif" "else"
- "define" "endef" "override"
- "export" "unexport" "vpath") t)
- "\\>[ \t]*\\([^: \t\n#]*\\)")
- '(1 font-lock-keyword-face) '(2 font-lock-variable-name-face))
-
- ;; Highlight lines that contain just whitespace.
- ;; They can cause trouble, especially if they start with a tab.
- '("^[ \t]+$" . makefile-space-face)
-
- ;; Highlight shell comments that Make treats as commands,
- ;; since these can fool people.
- '("^\t+#" 0 makefile-space-face t)
-
- ;; Highlight spaces that precede tabs.
- ;; They can make a tab fail to be effective.
- '("^\\( +\\)\t" 1 makefile-space-face)))
(defconst makefile-font-lock-syntactic-keywords
;; From sh-script.el.
("\\\\\n" 0 ".")))
(defvar makefile-imenu-generic-expression
- (list
- (list "Dependencies" makefile-dependency-regex 1)
- (list "Macro Assignment" makefile-macroassign-regex 1))
+ `(("Dependencies" makefile-previous-dependency 1)
+ ("Macro Assignment" ,makefile-macroassign-regex 1))
"Imenu generic expression for Makefile mode. See `imenu-generic-expression'.")
;;; ------------------------------------------------------------
: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:
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."
()
(define-abbrev-table 'makefile-mode-abbrev-table ()))
-(defvar makefile-mode-map nil
+(defvar makefile-mode-map
+ (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
+ (progn
+ (define-key map "$" 'makefile-insert-macro-ref)
+ (define-key map ":" 'makefile-electric-colon)
+ (define-key map "=" 'makefile-electric-equal)
+ (define-key map "." 'makefile-electric-dot)))
+ (define-key map "\C-c\C-f" 'makefile-pickup-filenames-as-targets)
+ (define-key map "\C-c\C-b" 'makefile-switch-to-browser)
+ (define-key map "\C-c\C-c" 'comment-region)
+ (define-key map "\C-c\C-p" 'makefile-pickup-everything)
+ (define-key map "\C-c\C-u" 'makefile-create-up-to-date-overview)
+ (define-key map "\C-c\C-i" 'makefile-insert-gmake-function)
+ (define-key map "\C-c\C-\\" 'makefile-backslash-region)
+ (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)
+ (define-key map "\M-n" 'makefile-next-dependency)
+ (define-key map "\e\t" 'makefile-complete)
+
+ ;; Make menus.
+ (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]
+ '(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]
+ '(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]
+ '(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]
+ '(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.")
-(if makefile-mode-map
- ()
- (setq makefile-mode-map (make-sparse-keymap))
- ;; set up the keymap
- (define-key makefile-mode-map "\C-c:" 'makefile-insert-target-ref)
- (if makefile-electric-keys
- (progn
- (define-key makefile-mode-map "$" 'makefile-insert-macro-ref)
- (define-key makefile-mode-map ":" 'makefile-electric-colon)
- (define-key makefile-mode-map "=" 'makefile-electric-equal)
- (define-key makefile-mode-map "." 'makefile-electric-dot)))
- (define-key makefile-mode-map "\C-c\C-f" 'makefile-pickup-filenames-as-targets)
- (define-key makefile-mode-map "\C-c\C-b" 'makefile-switch-to-browser)
- (define-key makefile-mode-map "\C-c\C-c" 'comment-region)
- (define-key makefile-mode-map "\C-c\C-p" 'makefile-pickup-everything)
- (define-key makefile-mode-map "\C-c\C-u" 'makefile-create-up-to-date-overview)
- (define-key makefile-mode-map "\C-c\C-i" 'makefile-insert-gmake-function)
- (define-key makefile-mode-map "\C-c\C-\\" 'makefile-backslash-region)
- (define-key makefile-mode-map "\M-p" 'makefile-previous-dependency)
- (define-key makefile-mode-map "\M-n" 'makefile-next-dependency)
- (define-key makefile-mode-map "\e\t" 'makefile-complete)
-
- ;; Make menus.
- (define-key makefile-mode-map [menu-bar makefile-mode]
- (cons "Makefile" (make-sparse-keymap "Makefile")))
-
- (define-key makefile-mode-map [menu-bar makefile-mode browse]
- '("Pop up Makefile Browser" . makefile-switch-to-browser))
- (define-key makefile-mode-map [menu-bar makefile-mode complete]
- '("Complete Target or Macro" . makefile-complete))
- (define-key makefile-mode-map [menu-bar makefile-mode pickup]
- '("Find Targets and Macros" . makefile-pickup-everything))
-
- (define-key makefile-mode-map [menu-bar makefile-mode prev]
- '("Move to Previous Dependency" . makefile-previous-dependency))
- (define-key makefile-mode-map [menu-bar makefile-mode next]
- '("Move to Next Dependency" . makefile-next-dependency)))
-
-(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))
;;; ------------------------------------------------------------
(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.")
;;;###autoload
(defun makefile-mode ()
- "Major mode for editing Makefiles.
-This function ends by invoking the function(s) `makefile-mode-hook'.
+ "Major mode for editing standard Makefiles.
+
+If you are editing a file for a different make, try one of the
+variants `makefile-automake-mode', `makefile-gmake-mode',
+`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
+example to see that a rule action `echo foo: bar' is a not rule
+dependency, despite the colon.
\\{makefile-mode-map}
nil nil
((?$ . "."))
backward-paragraph
- (font-lock-syntactic-keywords . makefile-font-lock-syntactic-keywords)))
+ (font-lock-syntactic-keywords
+ . makefile-font-lock-syntactic-keywords)))
;; Add-log.
(make-local-variable 'add-log-current-defun-function)
;; Real TABs are important in makefiles
(setq indent-tabs-mode t)
- (run-hooks 'makefile-mode-hook))
+ (run-mode-hooks 'makefile-mode-hook))
+
+;; These should do more than just differentiate font-lock.
+;;;###autoload
+(define-derived-mode makefile-automake-mode makefile-mode "Makefile.am"
+ "An adapted `makefile-mode' that knows about automake."
+ (setq font-lock-defaults
+ `(makefile-automake-font-lock-keywords ,@(cdr font-lock-defaults))))
+
+;;;###autoload
+(define-derived-mode makefile-gmake-mode makefile-mode "GNUmakefile"
+ "An adapted `makefile-mode' that knows about gmake."
+ (setq font-lock-defaults
+ `(makefile-gmake-font-lock-keywords ,@(cdr font-lock-defaults))))
+
+;;;###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)
+ makefile-makepp-rule-action-regex)
+ (setq font-lock-defaults
+ `(makefile-makepp-font-lock-keywords ,@(cdr font-lock-defaults))
+ imenu-generic-expression
+ `(("Functions" "^[ \t]*\\(?:make\\)?sub[ \t]+\\([A-Za-z0-9_]+\\)" 1)
+ ,@imenu-generic-expression)))
+
+;;;###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)
+ makefile-bsdmake-dependency-regex)
+ (set (make-local-variable 'makefile-dependency-skip) "^:!")
+ (set (make-local-variable 'makefile-rule-action-regex)
+ 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))))
\f
(interactive)
(let ((here (point)))
(end-of-line)
- (if (re-search-forward makefile-dependency-regex (point-max) t)
+ (if (makefile-match-dependency nil)
(progn (beginning-of-line) t) ; indicate success
(goto-char here) nil)))
(defun makefile-previous-dependency ()
"Move point to the beginning of the previous dependency line."
(interactive)
- (let ((here (point)))
+ (let ((pt (point)))
(beginning-of-line)
- (if (re-search-backward makefile-dependency-regex (point-min) t)
- (progn (beginning-of-line) t) ; indicate success
- (goto-char here) nil)))
+ ;; makefile-match-dependency done backwards:
+ (catch 'found
+ (while (progn (skip-chars-backward makefile-dependency-skip)
+ (not (bobp)))
+ (or (prog1 (eq (char-after) ?=)
+ (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)
+ nil)))
\f
(defun makefile-pickup-targets ()
"Notice names of all target definitions in Makefile."
(interactive)
- (if (not makefile-need-target-pickup)
- nil
- (setq makefile-need-target-pickup nil)
- (setq makefile-target-table nil)
- (setq makefile-has-prereqs nil)
+ (when makefile-need-target-pickup
+ (setq makefile-need-target-pickup nil
+ makefile-target-table nil
+ makefile-has-prereqs nil)
(save-excursion
(goto-char (point-min))
- (while (re-search-forward makefile-dependency-regex nil t)
- (makefile-add-this-line-targets)))
- (message "Read targets OK.")))
-
-(defun makefile-add-this-line-targets ()
- (save-excursion
- (beginning-of-line)
- (let ((done-with-line nil)
- (line-number (1+ (count-lines (point-min) (point)))))
- (while (not done-with-line)
- (skip-chars-forward " \t")
- (if (not (setq done-with-line (or (eolp)
- (char-equal (char-after (point)) ?:))))
- (progn
- (let* ((start-of-target-name (point))
- (target-name
- (progn
- (skip-chars-forward "^ \t:#")
- (buffer-substring start-of-target-name (point))))
+ (while (makefile-match-dependency nil)
+ (goto-char (match-beginning 1))
+ (while (let ((target-name
+ (buffer-substring-no-properties (point)
+ (progn
+ (skip-chars-forward "^ \t:#")
+ (point))))
(has-prereqs
(not (looking-at ":[ \t]*$"))))
- (if (makefile-remember-target target-name has-prereqs)
- (message "Picked up target \"%s\" from line %d"
- target-name line-number)))))))))
+ (if (makefile-remember-target target-name has-prereqs)
+ (message "Picked up target \"%s\" from line %d"
+ target-name (line-number-at-pos)))
+ (skip-chars-forward " \t")
+ (not (or (eolp) (eq (char-after) ?:)))))
+ (forward-line)))
+ (message "Read targets OK.")))
(defun makefile-pickup-macros ()
"Notice names of all macro definitions in Makefile."
(interactive)
- (if (not makefile-need-macro-pickup)
- nil
- (setq makefile-need-macro-pickup nil)
- (setq makefile-macro-table nil)
+ (when makefile-need-macro-pickup
+ (setq makefile-need-macro-pickup nil
+ makefile-macro-table nil)
(save-excursion
(goto-char (point-min))
(while (re-search-forward makefile-macroassign-regex nil t)
- (makefile-add-this-line-macro)
- (forward-line 1)))
+ (goto-char (match-beginning 1))
+ (let ((macro-name (buffer-substring-no-properties (point)
+ (progn
+ (skip-chars-forward "^ \t:#=*")
+ (point)))))
+ (if (makefile-remember-macro macro-name)
+ (message "Picked up macro \"%s\" from line %d"
+ macro-name (line-number-at-pos))))
+ (forward-line)))
(message "Read macros OK.")))
-(defun makefile-add-this-line-macro ()
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (unless (eolp)
- (let* ((start-of-macro-name (point))
- (line-number (1+ (count-lines (point-min) (point))))
- (macro-name (progn
- (skip-chars-forward "^ \t:#=*")
- (buffer-substring start-of-macro-name (point)))))
- (if (makefile-remember-macro macro-name)
- (message "Picked up macro \"%s\" from line %d"
- macro-name line-number))))))
-
(defun makefile-pickup-everything (arg)
"Notice names of all macros and targets in Makefile.
Prefix arg means force pickups to be redone."
(interactive "P")
(if arg
- (progn
- (setq makefile-need-target-pickup t)
- (setq makefile-need-macro-pickup t)))
+ (setq makefile-need-target-pickup t
+ makefile-need-macro-pickup t))
(makefile-pickup-macros)
(makefile-pickup-targets)
(if makefile-pickup-everything-picks-up-filenames-p
Checks each filename against `makefile-ignored-files-in-pickup-regex'
and adds all qualifying names to the list of known targets."
(interactive)
- (let* ((dir (file-name-directory (buffer-file-name)))
- (raw-filename-list (if dir
- (file-name-all-completions "" dir)
- (file-name-all-completions "" ""))))
- (mapcar (lambda (name)
- (if (and (not (file-directory-p name))
- (not (string-match makefile-ignored-files-in-pickup-regex
- name)))
- (if (makefile-remember-target name)
- (message "Picked up file \"%s\" as target" name))))
- raw-filename-list)))
+ (mapc (lambda (name)
+ (or (file-directory-p name)
+ (string-match makefile-ignored-files-in-pickup-regex name)
+ (if (makefile-remember-target name)
+ (message "Picked up file \"%s\" as target" name))))
+ (file-name-all-completions "" (or (file-name-directory (buffer-file-name)) ""))))
\f
(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)))
\f
(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.
(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
(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))))
\f
(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)))
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)
(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
(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"
;;; ------------------------------------------------------------
(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
(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)
(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)
;;; Utility functions
;;; ------------------------------------------------------------
+(defun makefile-match-function-end (end)
+ "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)))
+ ;; 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.
+Checks that the colon has not already been fontified, else we
+matched in a rule action."
+ (catch 'found
+ (let ((pt (point)))
+ (while (progn (skip-chars-forward makefile-dependency-skip bound)
+ (< (point) (or bound (point-max))))
+ (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))
+ nil))
+
+(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)))
;; 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