]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/make-mode.el
(grep-default-command): Use find-tag-default.
[gnu-emacs] / lisp / progmodes / make-mode.el
index f7b51ad1faca2a9e13ee39d36f7c726b5b4037a6..c887b14496508ba4535a619e84d3c37ac86be1f9 100644 (file)
@@ -1,6 +1,6 @@
 ;;; make-mode.el --- makefile editing commands for Emacs
 
 ;;; make-mode.el --- makefile editing commands for Emacs
 
-;; Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1992,94,99,2000,2001, 2002, 2003  Free Software Foundation, Inc.
 
 ;; Author: Thomas Neumann <tom@smart.bo.open.de>
 ;;     Eric S. Raymond <esr@snark.thyrsus.com>
 
 ;; Author: Thomas Neumann <tom@smart.bo.open.de>
 ;;     Eric S. Raymond <esr@snark.thyrsus.com>
@@ -8,11 +8,6 @@
 ;; Adapted-By: ESR
 ;; Keywords: unix, tools
 
 ;; Adapted-By: ESR
 ;; Keywords: unix, tools
 
-;; RMS:
-;; This needs work.
-;; Also, the doc strings need fixing: the first line doesn't stand alone,
-;; and other usage is not high quality.  Symbol names don't have `...'.
-
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
@@ -63,6 +58,7 @@
 ;;
 ;; To Do:
 ;;
 ;;
 ;; To Do:
 ;;
+;; * Add missing doc strings, improve terse doc strings.
 ;; * Eliminate electric stuff entirely.
 ;; * It might be nice to highlight targets differently depending on
 ;;   whether they are up-to-date or not.  Not sure how this would
 ;; * Eliminate electric stuff entirely.
 ;; * It might be nice to highlight targets differently depending on
 ;;   whether they are up-to-date or not.  Not sure how this would
 
 ;;; Code:
 
 
 ;;; Code:
 
-(provide 'makefile)
-
 ;; Sadly we need this for a macro.
 (eval-when-compile
 ;; Sadly we need this for a macro.
 (eval-when-compile
-  (require 'imenu))
+  (require 'imenu)
+  (require 'dabbrev)
+  (require 'add-log))
 
 ;;; ------------------------------------------------------------
 ;;; Configurable stuff
 
 ;;; ------------------------------------------------------------
 ;;; Configurable stuff
 
 (defface makefile-space-face
    '((((class color)) (:background  "hotpink"))
 
 (defface makefile-space-face
    '((((class color)) (:background  "hotpink"))
-         (t (:reverse-video t)))
+     (t (:reverse-video t)))
   "Face to use for highlighting leading spaces in Font-Lock mode."
   :group 'faces
   "Face to use for highlighting leading spaces in Font-Lock mode."
   :group 'faces
-  :group 'makemode)
+  :group 'makefile)
 
 (defcustom makefile-browser-buffer-name "*Macros and Targets*"
 
 (defcustom makefile-browser-buffer-name "*Macros and Targets*"
-  "Name of the macro- and target browser buffer."
+  "*Name of the macro- and target browser buffer."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-target-colon ":"
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-target-colon ":"
-  "String to append to all target names inserted by `makefile-insert-target'.
+  "*String to append to all target names inserted by `makefile-insert-target'.
 \":\" or \"::\" are common values."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-macro-assign " = "
 \":\" or \"::\" are common values."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-macro-assign " = "
-  "String to append to all macro names inserted by `makefile-insert-macro'.
+  "*String to append to all macro names inserted by `makefile-insert-macro'.
 The normal value should be \" = \", since this is what
 The normal value should be \" = \", since this is what
-standard make expects. However, newer makes such as dmake
+standard make expects.  However, newer makes such as dmake
 allow a larger variety of different macro assignments, so you
 might prefer to use \" += \" or \" := \" ."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-electric-keys nil
 allow a larger variety of different macro assignments, so you
 might prefer to use \" += \" or \" := \" ."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-electric-keys nil
-  "If non-nil, Makefile mode should install electric keybindings.
+  "*If non-nil, Makefile mode should install electric keybindings.
 Default is nil."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-use-curly-braces-for-macros-p nil
 Default is nil."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-use-curly-braces-for-macros-p nil
-  "Controls the style of generated macro references.
+  "*Controls the style of generated macro references.
 Non-nil means macro references should use curly braces, like `${this}'.
 nil means use parentheses, like `$(this)'."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-tab-after-target-colon t
 Non-nil means macro references should use curly braces, like `${this}'.
 nil means use parentheses, like `$(this)'."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-tab-after-target-colon t
-  "If non-nil, insert a TAB after a target colon.
+  "*If non-nil, insert a TAB after a target colon.
 Otherwise, a space is inserted.
 The default is t."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-browser-leftmost-column 10
 Otherwise, a space is inserted.
 The default is t."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-browser-leftmost-column 10
-  "Number of blanks to the left of the browser selection mark."
+  "*Number of blanks to the left of the browser selection mark."
   :type 'integer
   :group 'makefile)
 
 (defcustom makefile-browser-cursor-column 10
   :type 'integer
   :group 'makefile)
 
 (defcustom makefile-browser-cursor-column 10
-  "Column the cursor goes to when it moves up or down in the Makefile browser."
+  "*Column the cursor goes to when it moves up or down in the Makefile browser."
   :type 'integer
   :group 'makefile)
 
   :type 'integer
   :group 'makefile)
 
@@ -166,46 +162,51 @@ The default is t."
   :group 'makefile)
 
 (defcustom makefile-backslash-align t
   :group 'makefile)
 
 (defcustom makefile-backslash-align t
-  "If non-nil, `makefile-backslash-region' will align backslashes."
+  "*If non-nil, `makefile-backslash-region' will align backslashes."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-browser-selected-mark "+  "
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-browser-selected-mark "+  "
-  "String used to mark selected entries in the Makefile browser."
+  "*String used to mark selected entries in the Makefile browser."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-browser-unselected-mark "   "
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-browser-unselected-mark "   "
-  "String used to mark unselected entries in the Makefile browser."
+  "*String used to mark unselected entries in the Makefile browser."
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-browser-auto-advance-after-selection-p t
   :type 'string
   :group 'makefile)
 
 (defcustom makefile-browser-auto-advance-after-selection-p t
-  "If non-nil, cursor will move after item is selected in Makefile browser."
+  "*If non-nil, cursor will move after item is selected in Makefile browser."
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-pickup-everything-picks-up-filenames-p nil
   :type 'boolean
   :group 'makefile)
 
 (defcustom makefile-pickup-everything-picks-up-filenames-p nil
-  "If non-nil, `makefile-pickup-everything' picks up filenames as targets.
+  "*If non-nil, `makefile-pickup-everything' picks up filenames as targets.
 This means it calls `makefile-pickup-filenames-as-targets'.
 Otherwise filenames are omitted."
   :type 'boolean
   :group 'makefile)
 
 This means it calls `makefile-pickup-filenames-as-targets'.
 Otherwise filenames are omitted."
   :type 'boolean
   :group 'makefile)
 
-(defcustom makefile-cleanup-continuations-p t
-  "If non-nil, automatically clean up continuation lines when saving.
+(defcustom makefile-cleanup-continuations nil
+  "*If non-nil, automatically clean up continuation lines when saving.
 A line is cleaned up by removing all whitespace following a trailing
 backslash.  This is done silently.
 A line is cleaned up by removing all whitespace following a trailing
 backslash.  This is done silently.
-IMPORTANT: Please note that enabling this option causes makefile-mode
+IMPORTANT: Please note that enabling this option causes Makefile mode
 to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\"."
   :type 'boolean
   :group 'makefile)
 
 to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\"."
   :type 'boolean
   :group 'makefile)
 
+(defcustom makefile-mode-hook nil
+  "*Normal hook run by `makefile-mode'."
+  :type 'hook
+  :group 'makefile)
+
 (defvar makefile-browser-hook '())
 
 ;;
 ;; Special targets for DMake, Sun's make ...
 (defvar makefile-browser-hook '())
 
 ;;
 ;; Special targets for DMake, Sun's make ...
-;; 
+;;
 (defcustom makefile-special-targets-list
   '(("DEFAULT")      ("DONE")        ("ERROR")        ("EXPORT")
     ("FAILED")       ("GROUPEPILOG") ("GROUPPROLOG")  ("IGNORE")
 (defcustom makefile-special-targets-list
   '(("DEFAULT")      ("DONE")        ("ERROR")        ("EXPORT")
     ("FAILED")       ("GROUPEPILOG") ("GROUPPROLOG")  ("IGNORE")
@@ -215,33 +216,33 @@ to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\"."
     ("SCCS_GET")     ("SILENT")      ("SOURCE")       ("SUFFIXES")
     ("WAIT")         ("c.o")         ("C.o")          ("m.o")
     ("el.elc")       ("y.c")         ("s.o"))
     ("SCCS_GET")     ("SILENT")      ("SOURCE")       ("SUFFIXES")
     ("WAIT")         ("c.o")         ("C.o")          ("m.o")
     ("el.elc")       ("y.c")         ("s.o"))
-  "List of special targets.
+  "*List of special targets.
 You will be offered to complete on one of those in the minibuffer whenever
 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."
+you enter a \".\" at the beginning of a line in `makefile-mode'."
   :type '(repeat (list string))
   :group 'makefile)
 
 (defcustom makefile-runtime-macros-list
   '(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$"))
   :type '(repeat (list string))
   :group 'makefile)
 
 (defcustom makefile-runtime-macros-list
   '(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$"))
-  "List of macros that are resolved by make at runtime.
-If you insert a macro reference using makefile-insert-macro-ref, the name
-of the macro is checked against this list. If it can be found its name will
+  "*List of macros that are resolved by make at runtime.
+If you insert a macro reference using `makefile-insert-macro-ref', the name
+of the macro is checked against this list.  If it can be found its name will
 not be enclosed in { } or ( )."
   :type '(repeat (list string))
   :group 'makefile)
 
 ;; Note that the first big subexpression is used by font lock.  Note
 not be enclosed in { } or ( )."
   :type '(repeat (list string))
   :group 'makefile)
 
 ;; Note that the first big subexpression is used by font lock.  Note
-;; that if you change this regexp you must fix the imenu index
-;; function defined at the end of the file.
+;; that if you change this regexp you might have to fix the imenu
+;; index in makefile-imenu-generic-expression.
 (defconst makefile-dependency-regex
 (defconst makefile-dependency-regex
-  "^ *\\([^ \n\t#:=]+\\([ \t]+[^ \t\n#:=]+\\)*\\)[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)"
+  "^ *\\([^ \n\t#:=]+\\([ \t]+\\([^ \t\n#:=]+\\|\\$[({][^ \t\n#})]+[})]\\)\\)*\\)[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)"
   "Regex used to find dependency lines in a makefile.")
 
   "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 must fix the imenu index function
-;; defined at the end of the file.
+;; 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-macroassign-regex
 (defconst makefile-macroassign-regex
-  "^ *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*[*:+]?:?="
+  "^ *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*[*:+]?[:?]?="
   "Regex used to find macro assignment lines in a makefile.")
 
 (defconst makefile-ignored-files-in-pickup-regex
   "Regex used to find macro assignment lines in a makefile.")
 
 (defconst makefile-ignored-files-in-pickup-regex
@@ -255,15 +256,33 @@ not be enclosed in { } or ( )."
 
 (defconst makefile-font-lock-keywords
   (list
 
 (defconst makefile-font-lock-keywords
   (list
+
    ;; Do macro assignments.  These get the "variable-name" face rather
    ;; arbitrarily.
    (list makefile-macroassign-regex 1 'font-lock-variable-name-face)
    ;; Do macro assignments.  These get the "variable-name" face rather
    ;; arbitrarily.
    (list makefile-macroassign-regex 1 'font-lock-variable-name-face)
-   ;;
+
    ;; Do dependencies.  These get the function name face.
    (list makefile-dependency-regex 1 'font-lock-function-name-face)
    ;; Do dependencies.  These get the function name face.
    (list makefile-dependency-regex 1 'font-lock-function-name-face)
-   ;;
-   ;; Variable references even in targets/strings/comments:
-   '("\\$[({]\\([-a-zA-Z0-9_.]+\\)[}):]" 1 font-lock-constant-face prepend)
+
+   ;; Variable references even in targets/strings/comments.
+   '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\|[@%<?^+*][FD]?\\)[}):]"
+     1 font-lock-constant-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)
+
+   ;; 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.
 
    ;; Highlight lines that contain just whitespace.
    ;; They can cause trouble, especially if they start with a tab.
@@ -277,6 +296,22 @@ not be enclosed in { } or ( )."
    ;; They can make a tab fail to be effective.
    '("^\\( +\\)\t" 1 makefile-space-face)))
 
    ;; They can make a tab fail to be effective.
    '("^\\( +\\)\t" 1 makefile-space-face)))
 
+(defconst makefile-font-lock-syntactic-keywords
+  ;; From sh-script.el.
+  ;; A `#' begins a comment in sh when it is unquoted and at the beginning
+  ;; of a word.  In the shell, words are separated by metacharacters.
+  ;; The list of special chars is taken from the single-unix spec of the
+  ;; shell command language (under `quoting') but with `$' removed.
+  '(("[^|&;<>()`\\\"' \t\n]\\(#+\\)" 1 "_")
+    ;; Change the syntax of a quoted newline so that it does not end a comment.
+    ("\\\\\n" 0 ".")))
+
+(defvar makefile-imenu-generic-expression
+  (list
+   (list "Dependencies" makefile-dependency-regex  1)
+   (list "Macro Assignment" makefile-macroassign-regex 1))
+  "Imenu generic expression for Makefile mode.  See `imenu-generic-expression'.")
+
 ;;; ------------------------------------------------------------
 ;;; The following configurable variables are used in the
 ;;; up-to-date overview .
 ;;; ------------------------------------------------------------
 ;;; The following configurable variables are used in the
 ;;; up-to-date overview .
@@ -298,20 +333,20 @@ not be enclosed in { } or ( )."
 ;;; ------------------------------------------------------------
 
 (defcustom makefile-brave-make "make"
 ;;; ------------------------------------------------------------
 
 (defcustom makefile-brave-make "make"
-  "How to invoke make, for `makefile-query-targets'.
+  "*How to invoke make, for `makefile-query-targets'.
 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
 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
-  "Function to call to determine whether a make target is up to date.
+  "*Function to call to determine whether a make target is up to date.
 The function must satisfy this calling convention:
 
 * As its first argument, it must accept the name of the target to
   be checked, as a string.
 
 * As its second argument, it may accept the name of a makefile
 The function must satisfy this calling convention:
 
 * As its first argument, it must accept the name of the target to
   be checked, as a string.
 
 * As its second argument, it may accept the name of a makefile
-  as a string. Depending on what you're going to do you may
+  as a string.  Depending on what you're going to do you may
   not need this.
 
 * It must return the integer value 0 (zero) if the given target
   not need this.
 
 * It must return the integer value 0 (zero) if the given target
@@ -321,12 +356,18 @@ The function must satisfy this calling convention:
   :group 'makefile)
 
 (defcustom makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*"
   :group 'makefile)
 
 (defcustom makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*"
-  "Name of the Up-to-date overview buffer."
+  "*Name of the Up-to-date overview buffer."
   :type 'string
   :group 'makefile)
 
 ;;; --- end of up-to-date-overview configuration ------------------
 
   :type 'string
   :group 'makefile)
 
 ;;; --- end of up-to-date-overview configuration ------------------
 
+(defvar makefile-mode-abbrev-table nil
+  "Abbrev table in use in Makefile buffers.")
+(if makefile-mode-abbrev-table
+    ()
+  (define-abbrev-table 'makefile-mode-abbrev-table ()))
+
 (defvar makefile-mode-map nil
   "The keymap that is used in Makefile mode.")
 
 (defvar makefile-mode-map nil
   "The keymap that is used in Makefile mode.")
 
@@ -374,17 +415,17 @@ The function must satisfy this calling convention:
     ()
   (setq makefile-browser-map (make-sparse-keymap))
   (define-key makefile-browser-map "n"    'makefile-browser-next-line)
     ()
   (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 "\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 "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 "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-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))  
+  (define-key makefile-browser-map "\C-f" 'undefined))
 
 
 (defvar makefile-mode-syntax-table nil)
 
 
 (defvar makefile-mode-syntax-table nil)
@@ -395,7 +436,7 @@ The function must satisfy this calling convention:
   (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 ?\' "\"     " 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)
@@ -471,73 +512,76 @@ In the browser, use the following keys:
 
 Makefile mode can be configured by modifying the following variables:
 
 
 Makefile mode can be configured by modifying the following variables:
 
-makefile-browser-buffer-name:
+`makefile-browser-buffer-name':
     Name of the macro- and target browser buffer.
 
     Name of the macro- and target browser buffer.
 
-makefile-target-colon:
+`makefile-target-colon':
     The string that gets appended to all target names
     inserted by `makefile-insert-target'.
     \":\" or \"::\" are quite common values.
 
     The string that gets appended to all target names
     inserted by `makefile-insert-target'.
     \":\" or \"::\" are quite common values.
 
-makefile-macro-assign:
+`makefile-macro-assign':
    The string that gets appended to all macro names
    inserted by `makefile-insert-macro'.
    The normal value should be \" = \", since this is what
    The string that gets appended to all macro names
    inserted by `makefile-insert-macro'.
    The normal value should be \" = \", since this is what
-   standard make expects. However, newer makes such as dmake
+   standard make expects.  However, newer makes such as dmake
    allow a larger variety of different macro assignments, so you
    might prefer to use \" += \" or \" := \" .
 
    allow a larger variety of different macro assignments, so you
    might prefer to use \" += \" or \" := \" .
 
-makefile-tab-after-target-colon:
+`makefile-tab-after-target-colon':
    If you want a TAB (instead of a space) to be appended after the
    target colon, then set this to a non-nil value.
 
    If you want a TAB (instead of a space) to be appended after the
    target colon, then set this to a non-nil value.
 
-makefile-browser-leftmost-column:
+`makefile-browser-leftmost-column':
    Number of blanks to the left of the browser selection mark.
 
    Number of blanks to the left of the browser selection mark.
 
-makefile-browser-cursor-column:
+`makefile-browser-cursor-column':
    Column in which the cursor is positioned when it moves
    up or down in the browser.
 
    Column in which the cursor is positioned when it moves
    up or down in the browser.
 
-makefile-browser-selected-mark:
+`makefile-browser-selected-mark':
    String used to mark selected entries in the browser.
 
    String used to mark selected entries in the browser.
 
-makefile-browser-unselected-mark:
+`makefile-browser-unselected-mark':
    String used to mark unselected entries in the browser.
 
    String used to mark unselected entries in the browser.
 
-makefile-browser-auto-advance-after-selection-p:
+`makefile-browser-auto-advance-after-selection-p':
    If this variable is set to a non-nil value the cursor
    will automagically advance to the next line after an item
    has been selected in the browser.
 
    If this variable is set to a non-nil value the cursor
    will automagically advance to the next line after an item
    has been selected in the browser.
 
-makefile-pickup-everything-picks-up-filenames-p:
+`makefile-pickup-everything-picks-up-filenames-p':
    If this variable is set to a non-nil value then
    `makefile-pickup-everything' also picks up filenames as targets
    (i.e. it calls `makefile-pickup-filenames-as-targets'), otherwise
    filenames are omitted.
 
    If this variable is set to a non-nil value then
    `makefile-pickup-everything' also picks up filenames as targets
    (i.e. it calls `makefile-pickup-filenames-as-targets'), otherwise
    filenames are omitted.
 
-makefile-cleanup-continuations-p:
-   If this variable is set to a non-nil value then makefile-mode
+`makefile-cleanup-continuations':
+   If this variable is set to a non-nil value then Makefile mode
    will assure that no line in the file ends with a backslash
    (the continuation character) followed by any whitespace.
    This is done by silently removing the trailing whitespace, leaving
    the backslash itself intact.
    will assure that no line in the file ends with a backslash
    (the continuation character) followed by any whitespace.
    This is done by silently removing the trailing whitespace, leaving
    the backslash itself intact.
-   IMPORTANT: Please note that enabling this option causes makefile-mode
+   IMPORTANT: Please note that enabling this option causes Makefile mode
    to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\".
 
    to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\".
 
-makefile-browser-hook:
+`makefile-browser-hook':
    A function or list of functions to be called just before the
    browser is entered. This is executed in the makefile buffer.
 
    A function or list of functions to be called just before the
    browser is entered. This is executed in the makefile buffer.
 
-makefile-special-targets-list:
+`makefile-special-targets-list':
    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."
 
   (interactive)
   (kill-all-local-variables)
    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."
 
   (interactive)
   (kill-all-local-variables)
-  (make-local-variable 'local-write-file-hooks)
-  (setq local-write-file-hooks
-       '(makefile-cleanup-continuations makefile-warn-suspicious-lines))
+  (add-hook 'write-file-functions
+           'makefile-warn-suspicious-lines nil t)
+  (add-hook 'write-file-functions
+           'makefile-warn-continuations nil t)
+  (add-hook 'write-file-functions
+           'makefile-cleanup-continuations nil t)
   (make-local-variable 'makefile-target-table)
   (make-local-variable 'makefile-macro-table)
   (make-local-variable 'makefile-has-prereqs)
   (make-local-variable 'makefile-target-table)
   (make-local-variable 'makefile-macro-table)
   (make-local-variable 'makefile-has-prereqs)
@@ -546,20 +590,31 @@ makefile-special-targets-list:
 
   ;; Font lock.
   (make-local-variable 'font-lock-defaults)
 
   ;; Font lock.
   (make-local-variable 'font-lock-defaults)
-  (setq font-lock-defaults '(makefile-font-lock-keywords))
+  (setq font-lock-defaults
+       ;; SYNTAX-BEGIN set to backward-paragraph to avoid slow-down
+       ;; near the end of a large buffer, due to parse-partial-sexp's
+       ;; trying to parse all the way till the beginning of buffer.
+       '(makefile-font-lock-keywords
+         nil nil
+         ((?$ . "."))
+         backward-paragraph
+         (font-lock-syntactic-keywords . makefile-font-lock-syntactic-keywords)))
 
   ;; Add-log.
   (make-local-variable 'add-log-current-defun-function)
   (setq add-log-current-defun-function 'makefile-add-log-defun)
 
   ;; Imenu.
 
   ;; Add-log.
   (make-local-variable 'add-log-current-defun-function)
   (setq add-log-current-defun-function 'makefile-add-log-defun)
 
   ;; Imenu.
-  (make-local-variable 'imenu-create-index-function)
-  (setq imenu-create-index-function 'makefile-menu-index-function)
+  (make-local-variable 'imenu-generic-expression)
+  (setq imenu-generic-expression makefile-imenu-generic-expression)
 
   ;; Dabbrev.
   (make-local-variable 'dabbrev-abbrev-skip-leading-regexp)
   (setq dabbrev-abbrev-skip-leading-regexp "\\$")
 
 
   ;; Dabbrev.
   (make-local-variable 'dabbrev-abbrev-skip-leading-regexp)
   (setq dabbrev-abbrev-skip-leading-regexp "\\$")
 
+  ;; Other abbrevs.
+  (setq local-abbrev-table makefile-mode-abbrev-table)
+
   ;; Filling.
   (make-local-variable 'fill-paragraph-function)
   (setq fill-paragraph-function 'makefile-fill-paragraph)
   ;; Filling.
   (make-local-variable 'fill-paragraph-function)
   (setq fill-paragraph-function 'makefile-fill-paragraph)
@@ -572,6 +627,9 @@ makefile-special-targets-list:
   (make-local-variable 'comment-start-skip)
   (setq comment-start-skip "#+[ \t]*")
 
   (make-local-variable 'comment-start-skip)
   (setq comment-start-skip "#+[ \t]*")
 
+  ;; Make sure TAB really inserts \t.
+  (set (make-local-variable 'indent-line-function) 'indent-to-left-margin)
+
   ;; become the current major mode
   (setq major-mode 'makefile-mode)
   (setq mode-name "Makefile")
   ;; become the current major mode
   (setq major-mode 'makefile-mode)
   (setq mode-name "Makefile")
@@ -675,7 +733,7 @@ Anywhere else just self-inserts."
        (makefile-remember-target target-name))))
 
 (defun makefile-insert-target-ref (target-name)
        (makefile-remember-target target-name))))
 
 (defun makefile-insert-target-ref (target-name)
-  "Complete on a list of known targets, then insert target-ref at point."
+  "Complete on a list of known targets, then insert TARGET-NAME at point."
   (interactive
    (list
     (progn
   (interactive
    (list
     (progn
@@ -709,7 +767,7 @@ Anywhere else just self-inserts."
     (setq makefile-has-prereqs nil)
     (save-excursion
       (goto-char (point-min))
     (setq makefile-has-prereqs nil)
     (save-excursion
       (goto-char (point-min))
-      (while (re-search-forward makefile-dependency-regex (point-max) t)
+      (while (re-search-forward makefile-dependency-regex nil t)
        (makefile-add-this-line-targets)))
     (message "Read targets OK.")))
 
        (makefile-add-this-line-targets)))
     (message "Read targets OK.")))
 
@@ -743,7 +801,7 @@ Anywhere else just self-inserts."
     (setq makefile-macro-table nil)
     (save-excursion
       (goto-char (point-min))
     (setq makefile-macro-table nil)
     (save-excursion
       (goto-char (point-min))
-      (while (re-search-forward makefile-macroassign-regex (point-max) t)
+      (while (re-search-forward makefile-macroassign-regex nil t)
        (makefile-add-this-line-macro)
        (forward-line 1)))
     (message "Read macros OK.")))
        (makefile-add-this-line-macro)
        (forward-line 1)))
     (message "Read macros OK.")))
@@ -752,15 +810,15 @@ Anywhere else just self-inserts."
   (save-excursion
     (beginning-of-line)
     (skip-chars-forward " \t")
   (save-excursion
     (beginning-of-line)
     (skip-chars-forward " \t")
-    (if (not (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))))))
+    (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.
 
 (defun makefile-pickup-everything (arg)
   "Notice names of all macros and targets in Makefile.
@@ -784,7 +842,7 @@ and adds all qualifying names to the list of known targets."
         (raw-filename-list (if dir
                                (file-name-all-completions "" dir)
                              (file-name-all-completions "" ""))))
         (raw-filename-list (if dir
                                (file-name-all-completions "" dir)
                              (file-name-all-completions "" ""))))
-    (mapcar '(lambda (name)
+    (mapcar (lambda (name)
               (if (and (not (file-directory-p name))
                        (not (string-match makefile-ignored-files-in-pickup-regex
                                           name)))
               (if (and (not (file-directory-p name))
                        (not (string-match makefile-ignored-files-in-pickup-regex
                                           name)))
@@ -896,7 +954,7 @@ The context determines which are considered."
 With no argument, inserts backslashes and aligns existing backslashes.
 With an argument, deletes the backslashes.
 
 With no argument, inserts backslashes and aligns existing backslashes.
 With an argument, deletes the backslashes.
 
-This function does not modify the last line of the region if the region ends 
+This function does not modify the last line of the region if the region ends
 right at the start of the following line; it does not modify blank lines
 at the start of the region.  So you can put the region around an entire macro
 definition and conveniently use this command."
 right at the start of the following line; it does not modify blank lines
 at the start of the region.  So you can put the region around an entire macro
 definition and conveniently use this command."
@@ -971,22 +1029,34 @@ definition and conveniently use this command."
     (beginning-of-line)
     (cond
      ((looking-at "^#+ ")
     (beginning-of-line)
     (cond
      ((looking-at "^#+ ")
-      ;; Found a comment.  Set the fill prefix and then fill.
-      (let ((fill-prefix (buffer-substring-no-properties (match-beginning 0)
-                                                        (match-end 0)))
+      ;; 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))
            (fill-paragraph-function nil))
-       (fill-paragraph nil)
-       t))
+       (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))))
 
      ;; Must look for backslashed-region before looking for variable
      ;; assignment.
 
      ;; Must look for backslashed-region before looking for variable
      ;; assignment.
-     ((save-excursion
-       (end-of-line)
-       (or
-        (= (preceding-char) ?\\)
-        (progn
-          (end-of-line -1)
-          (= (preceding-char) ?\\))))
+     ((or (eq (char-before (line-end-position 1)) ?\\)
+         (eq (char-before (line-end-position 0)) ?\\))
       ;; A backslash region.  Find beginning and end, remove
       ;; backslashes, fill, and then reapply backslahes.
       (end-of-line)
       ;; A backslash region.  Find beginning and end, remove
       ;; backslashes, fill, and then reapply backslahes.
       (end-of-line)
@@ -1016,10 +1086,7 @@ definition and conveniently use this command."
       ;; Have a macro assign.  Fill just this line, and then backslash
       ;; resulting region.
       (save-restriction
       ;; Have a macro assign.  Fill just this line, and then backslash
       ;; resulting region.
       (save-restriction
-       (narrow-to-region (point) (save-excursion
-                                   (end-of-line)
-                                   (forward-char)
-                                   (point)))
+       (narrow-to-region (point) (line-beginning-position 2))
        (let ((fill-paragraph-function nil))
          (fill-paragraph nil))
        (makefile-backslash-region (point-min) (point-max) nil)))))
        (let ((fill-paragraph-function nil))
          (fill-paragraph nil))
        (makefile-backslash-region (point-min) (point-max) nil)))))
@@ -1100,7 +1167,7 @@ definition and conveniently use this command."
   (let ((my-client makefile-browser-client))
     (setq makefile-browser-client nil) ; we quitted, so NO client!
     (set-buffer-modified-p nil)
   (let ((my-client makefile-browser-client))
     (setq makefile-browser-client nil) ; we quitted, so NO client!
     (set-buffer-modified-p nil)
-    (kill-buffer (current-buffer))
+    (quit-window t)
     (pop-to-buffer my-client)))
 
 ;;;
     (pop-to-buffer my-client)))
 
 ;;;
@@ -1146,8 +1213,7 @@ This is most useful in the process of creating continued lines when copying
 large dependencies from the browser to the client buffer.
 \(point) advances accordingly in the client buffer."
   (interactive)
 large dependencies from the browser to the client buffer.
 \(point) advances accordingly in the client buffer."
   (interactive)
-  (save-excursion
-    (set-buffer makefile-browser-client)
+  (with-current-buffer makefile-browser-client
     (end-of-line)
     (insert "\\\n\t")))
 
     (end-of-line)
     (insert "\\\n\t")))
 
@@ -1192,11 +1258,10 @@ Insertion takes place at point."
        (message "No macros or targets to browse! Consider running 'makefile-pickup-everything\'"))
     (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name)))
        (pop-to-buffer browser-buffer)
        (message "No macros or targets to browse! Consider running 'makefile-pickup-everything\'"))
     (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name)))
        (pop-to-buffer browser-buffer)
-       (make-variable-buffer-local 'makefile-browser-selection-vector)
        (makefile-browser-fill targets macros)
        (shrink-window-if-larger-than-buffer)
        (makefile-browser-fill targets macros)
        (shrink-window-if-larger-than-buffer)
-       (setq makefile-browser-selection-vector
-             (make-vector (+ (length targets) (length macros)) nil))
+       (set (make-local-variable 'makefile-browser-selection-vector)
+            (make-vector (+ (length targets) (length macros)) nil))
        (makefile-browser-start-interaction))))
 
 (defun makefile-switch-to-browser ()
        (makefile-browser-start-interaction))))
 
 (defun makefile-switch-to-browser ()
@@ -1289,7 +1354,7 @@ and generates the overview, one line per target name."
     (function (lambda (item)
                (let* ((target-name (car item))
                       (no-prereqs (not (member target-name prereq-list)))
     (function (lambda (item)
                (let* ((target-name (car item))
                       (no-prereqs (not (member target-name prereq-list)))
-                      (needs-rebuild (or no-prereqs 
+                      (needs-rebuild (or no-prereqs
                                          (funcall
                                           makefile-query-one-target-method
                                           target-name
                                          (funcall
                                           makefile-query-one-target-method
                                           target-name
@@ -1305,7 +1370,7 @@ and generates the overview, one line per target name."
   (delete-file filename))              ; remove the tmpfile
 
 (defun makefile-query-by-make-minus-q (target &optional filename)
   (delete-file filename))              ; remove the tmpfile
 
 (defun makefile-query-by-make-minus-q (target &optional filename)
-  (not (zerop
+  (not (eq 0
        (call-process makefile-brave-make nil nil nil
                      "-f" filename "-q" target))))
 
        (call-process makefile-brave-make nil nil nil
                      "-f" filename "-q" target))))
 
@@ -1317,11 +1382,11 @@ and generates the overview, one line per target name."
 
 (defun makefile-cleanup-continuations ()
   (if (eq major-mode 'makefile-mode)
 
 (defun makefile-cleanup-continuations ()
   (if (eq major-mode 'makefile-mode)
-      (if (and makefile-cleanup-continuations-p
+      (if (and makefile-cleanup-continuations
               (not buffer-read-only))
          (save-excursion
            (goto-char (point-min))
               (not buffer-read-only))
          (save-excursion
            (goto-char (point-min))
-           (while (re-search-forward "\\\\[ \t]+$" (point-max) t)
+           (while (re-search-forward "\\\\[ \t]+$" nil t)
              (replace-match "\\" t t))))))
 
 
              (replace-match "\\" t t))))))
 
 
@@ -1330,21 +1395,23 @@ and generates the overview, one line per target name."
 ;;; ------------------------------------------------------------
 
 (defun makefile-warn-suspicious-lines ()
 ;;; ------------------------------------------------------------
 
 (defun makefile-warn-suspicious-lines ()
-  (let ((dont-save nil))
-    (if (eq major-mode 'makefile-mode)
-       (let ((suspicious
-              (save-excursion
-                (goto-char (point-min))
-                (re-search-forward
-                 "\\(^[\t]+$\\)\\|\\(^[ ]+[\t]\\)" (point-max) t))))
-         (if suspicious
-             (let ((line-nr (count-lines (point-min) suspicious)))
-               (setq dont-save
-                     (not (y-or-n-p
-                           (format "Suspicious line %d. Save anyway "
-                                   line-nr))))))))
-    dont-save))
-         
+  ;; Returning non-nil cancels the save operation
+  (if (eq major-mode 'makefile-mode)
+      (save-excursion
+       (goto-char (point-min))
+       (if (re-search-forward "^\\(\t+$\\| +\t\\)" nil t)
+           (not (y-or-n-p
+                 (format "Suspicious line %d. Save anyway? "
+                         (count-lines (point-min) (point)))))))))
+
+(defun makefile-warn-continuations ()
+  (if (eq major-mode 'makefile-mode)
+      (save-excursion
+       (goto-char (point-min))
+       (if (re-search-forward "\\\\[ \t]+$" nil t)
+           (not (y-or-n-p
+                 (format "Suspicious continuation in line %d. Save anyway? "
+                         (count-lines (point-min) (point)))))))))
 \f
 
 ;;; ------------------------------------------------------------
 \f
 
 ;;; ------------------------------------------------------------
@@ -1419,20 +1486,20 @@ This acts according to the value of `makefile-tab-after-target-colon'."
   "Determine if point is on a macro line in the browser."
   (save-excursion
     (beginning-of-line)
   "Determine if point is on a macro line in the browser."
   (save-excursion
     (beginning-of-line)
-    (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t)))
+    (re-search-forward "\\$[{(]" (line-end-position) t)))
 
 (defun makefile-browser-this-line-target-name ()
   "Extract the target name from a line in the browser."
   (save-excursion
     (end-of-line)
     (skip-chars-backward "^ \t")
 
 (defun makefile-browser-this-line-target-name ()
   "Extract the target name from a line in the browser."
   (save-excursion
     (end-of-line)
     (skip-chars-backward "^ \t")
-    (buffer-substring (point) (1- (makefile-end-of-line-point)))))
+    (buffer-substring (point) (1- (line-end-position)))))
 
 (defun makefile-browser-this-line-macro-name ()
   "Extract the macro name from a line in the browser."
   (save-excursion
     (beginning-of-line)
 
 (defun makefile-browser-this-line-macro-name ()
   "Extract the macro name from a line in the browser."
   (save-excursion
     (beginning-of-line)
-    (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t)
+    (re-search-forward "\\$[{(]" (line-end-position) t)
     (let ((macro-start (point)))
       (skip-chars-forward "^})")
       (buffer-substring macro-start (point)))))
     (let ((macro-start (point)))
       (skip-chars-forward "^})")
       (buffer-substring macro-start (point)))))
@@ -1456,25 +1523,15 @@ Uses `makefile-use-curly-braces-for-macros-p'."
 (defun makefile-browser-toggle-state-for-line (n)
   (makefile-browser-set-state-for-line n (not (makefile-browser-get-state-for-line n))))
 
 (defun makefile-browser-toggle-state-for-line (n)
   (makefile-browser-set-state-for-line n (not (makefile-browser-get-state-for-line n))))
 
-(defun makefile-beginning-of-line-point ()
-  (save-excursion
-    (beginning-of-line)
-    (point)))
-
-(defun makefile-end-of-line-point ()
-  (save-excursion
-    (end-of-line)
-    (point)))
-
 (defun makefile-last-line-p ()
 (defun makefile-last-line-p ()
-  (= (makefile-end-of-line-point) (point-max)))
+  (= (line-end-position) (point-max)))
 
 (defun makefile-first-line-p ()
 
 (defun makefile-first-line-p ()
-  (= (makefile-beginning-of-line-point) (point-min)))
+  (= (line-beginning-position) (point-min)))
 
 \f
 
 
 \f
 
-;;; Support for other packages, like add-log and imenu.
+;;; Support for other packages, like add-log.
 
 (defun makefile-add-log-defun ()
   "Return name of target or variable assignment that point is in.
 
 (defun makefile-add-log-defun ()
   "Return name of target or variable assignment that point is in.
@@ -1485,42 +1542,16 @@ If it isn't in one, return nil."
       ;; Scan back line by line, noticing when we come to a
       ;; variable or rule definition, and giving up when we see
       ;; a line that is not part of either of those.
       ;; Scan back line by line, noticing when we come to a
       ;; variable or rule definition, and giving up when we see
       ;; a line that is not part of either of those.
-      (while (not found)
-       (cond
-        ((looking-at makefile-macroassign-regex)
-         (setq found (buffer-substring-no-properties (match-beginning 1)
-                                                       (match-end 1))))
-        ((looking-at makefile-dependency-regex)
-         (setq found (buffer-substring-no-properties (match-beginning 1)
-                                                     (match-end 1))))
-        ;; Don't keep looking across a blank line or comment.  Give up.
-        ((looking-at "$\\|#")
-         (setq found 'bobp))
-        ((bobp)
-         (setq found 'bobp)))
-       (or found
-           (forward-line -1)))
-      (if (stringp found) found))))
-
-;; FIXME it might be nice to have them separated by macro vs target.
-(defun makefile-menu-index-function ()
-  ;; "Generate alist of indices for imenu."
-  (let (alist
-       stupid
-       (re (concat makefile-dependency-regex
-                   "\\|"
-                   makefile-macroassign-regex)))
-    (imenu-progress-message stupid 0)
-    (goto-char (point-min))
-    (while (re-search-forward re nil t)
-      (imenu-progress-message stupid)
-      (let ((n (if (match-beginning 1) 1 5)))
-       (setq alist (cons
-                    (cons (buffer-substring (match-beginning n)
-                                            (match-end n))
-                          (match-beginning n))
-                    alist))))
-    (imenu-progress-message stupid 100)
-    (nreverse alist)))
-
+      (while (not (or (setq found
+                           (when (or (looking-at makefile-macroassign-regex)
+                                     (looking-at makefile-dependency-regex))
+                             (match-string-no-properties 1)))
+                     ;; Don't keep looking across a blank line or comment.
+                     (looking-at "$\\|#")
+                     (not (zerop (forward-line -1))))))
+      found)))
+
+(provide 'make-mode)
+
+;;; arch-tag: bd23545a-de91-44fb-b1b2-feafbb2635a0
 ;;; make-mode.el ends here
 ;;; make-mode.el ends here