Add arch taglines
[bpt/emacs.git] / lisp / progmodes / make-mode.el
index 973fabe..ae977b1 100644 (file)
@@ -1,6 +1,6 @@
 ;;; 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>
 
 ;;; Code:
 
-(provide 'makefile)
-
 ;; Sadly we need this for a macro.
 (eval-when-compile
-  (require 'imenu))
+  (require 'imenu)
+  (require 'dabbrev)
+  (require 'add-log))
 
 ;;; ------------------------------------------------------------
 ;;; Configurable stuff
 ;;; ------------------------------------------------------------
 
-(defvar makefile-browser-buffer-name "*Macros and Targets*"
-  "Name of the macro- and target browser buffer.")
-
-(defvar makefile-target-colon ":"
-  "String to append to all target names inserted by `makefile-insert-target'.
-\":\" or \"::\" are common values.")
-
-(defvar makefile-macro-assign " = "
-  "String to append to all macro names inserted by `makefile-insert-macro'.
+(defgroup makefile nil
+  "Makefile editing commands for Emacs."
+  :group 'tools
+  :prefix "makefile-")
+
+(defface makefile-space-face
+   '((((class color)) (:background  "hotpink"))
+     (t (:reverse-video t)))
+  "Face to use for highlighting leading spaces in Font-Lock mode."
+  :group 'faces
+  :group 'makefile)
+
+(defcustom makefile-browser-buffer-name "*Macros and Targets*"
+  "*Name of the macro- and target browser buffer."
+  :type 'string
+  :group 'makefile)
+
+(defcustom makefile-target-colon ":"
+  "*String to append to all target names inserted by `makefile-insert-target'.
+\":\" or \"::\" are common values."
+  :type 'string
+  :group 'makefile)
+
+(defcustom makefile-macro-assign " = "
+  "*String to append 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 \" := \" .")
-
-(defvar makefile-electric-keys nil
-  "If non-nil, install electric keybindings.
-Default is nil.")
-
-(defvar makefile-use-curly-braces-for-macros-p nil
-  "Controls the style of generated macro references.
-t (actually non-nil) means macro references should use curly braces,
-like `${this}'.
-nil means use parentheses, like `$(this)'.")
-
-(defvar makefile-tab-after-target-colon t
-  "If non-nil, insert a TAB after a target colon.
+might prefer to use \" += \" or \" := \" ."
+  :type 'string
+  :group 'makefile)
+
+(defcustom makefile-electric-keys nil
+  "*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
+  "*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
+  "*If non-nil, insert a TAB after a target colon.
 Otherwise, a space is inserted.
-The default is t.")
-
-(defvar makefile-browser-leftmost-column 10
-  "Number of blanks to the left of the browser selection mark.")
-
-(defvar makefile-browser-cursor-column 10
-  "Column in which the cursor is positioned when it moves
-up or down in the browser.")
-
-(defvar makefile-backslash-column 48
-  "*Column in which `makefile-backslash-region' inserts backslashes.")
-
-(defvar makefile-backslash-align t
-  "If non-nil, `makefile-backslash-region' will align backslashes.")
-
-(defvar makefile-browser-selected-mark "+  "
-  "String used to mark selected entries in the browser.")
-
-(defvar makefile-browser-unselected-mark "   "
-  "String used to mark unselected entries in the browser.")
-
-(defvar makefile-browser-auto-advance-after-selection-p t
-  "If non-nil, cursor will move after item is selected in browser.")
-
-(defvar makefile-pickup-everything-picks-up-filenames-p nil
-  "If non-nil, `makefile-pickup-everything' picks up filenames as targets.
-\(i.e. it calls `makefile-find-filenames-as-targets').
-Otherwise filenames are omitted.")
-
-(defvar makefile-cleanup-continuations-p t
-  "If non-nil, automatically clean up continuation lines when saving.
+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."
+  :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."
+  :type 'integer
+  :group 'makefile)
+
+(defcustom makefile-backslash-column 48
+  "*Column in which `makefile-backslash-region' inserts backslashes."
+  :type 'integer
+  :group 'makefile)
+
+(defcustom makefile-backslash-align t
+  "*If non-nil, `makefile-backslash-region' will align backslashes."
+  :type 'boolean
+  :group 'makefile)
+
+(defcustom makefile-browser-selected-mark "+  "
+  "*String used to mark selected entries in the Makefile browser."
+  :type 'string
+  :group 'makefile)
+
+(defcustom makefile-browser-unselected-mark "   "
+  "*String used to mark unselected entries in the Makefile browser."
+  :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."
+  :type 'boolean
+  :group 'makefile)
+
+(defcustom makefile-pickup-everything-picks-up-filenames-p nil
+  "*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)
+
+(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.
-IMPORTANT: Please note that enabling this option causes makefile-mode
-to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'.")
+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)
+
+(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-special-targets-list
+;;
+(defcustom makefile-special-targets-list
   '(("DEFAULT")      ("DONE")        ("ERROR")        ("EXPORT")
     ("FAILED")       ("GROUPEPILOG") ("GROUPPROLOG")  ("IGNORE")
     ("IMPORT")       ("INCLUDE")     ("INCLUDEDIRS")  ("INIT")
@@ -175,29 +220,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"))
-  "List of special targets.
+  "*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.")
+you enter a \".\" at the beginning of a line in `makefile-mode'."
+  :type '(repeat (list string))
+  :group 'makefile)
 
-(defvar makefile-runtime-macros-list
+(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
-not be enclosed in { } or ( ).")
+  "*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
-;; 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
-  "^ *\\([^ \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.")
 
-;; 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
-  "^ *\\([^ \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
@@ -211,15 +260,33 @@ not be enclosed in { } or ( ).")
 
 (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 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-reference-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.
@@ -233,6 +300,17 @@ not be enclosed in { } or ( ).")
    ;; They can make a tab fail to be effective.
    '("^\\( +\\)\t" 1 makefile-space-face)))
 
+(defconst makefile-font-lock-syntactic-keywords
+  (list
+   ;; 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 .
@@ -253,29 +331,42 @@ not be enclosed in { } or ( ).")
 ;;; of `makefile-query-by-make-minus-q' .
 ;;; ------------------------------------------------------------
 
-(defvar makefile-brave-make "make"
-  "A make that can handle the `-q' option.")
+(defcustom makefile-brave-make "make"
+  "*How to invoke make, for `makefile-query-targets'.
+This should identify a `make' command that can handle the `-q' option."
+  :type 'string
+  :group 'makefile)
 
-(defvar makefile-query-one-target-method 'makefile-query-by-make-minus-q
-  "Function to call to determine whether a make target is up to date.
+(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.
 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
   should be considered up-to-date in the context of the given
-  makefile, any nonzero integer value otherwise.")
+  makefile, any nonzero integer value otherwise."
+  :type 'function
+  :group 'makefile)
 
-(defvar makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*"
-  "Name of the Up-to-date overview buffer.")
+(defcustom makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*"
+  "*Name of the Up-to-date overview buffer."
+  :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.")
 
@@ -323,17 +414,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)
-  (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 "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-f" 'undefined))  
+  (define-key makefile-browser-map "\C-f" 'undefined))
 
 
 (defvar makefile-mode-syntax-table nil)
@@ -344,7 +435,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)
@@ -420,73 +511,76 @@ In the browser, use the following keys:
 
 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.
 
-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.
 
-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
-   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 \" := \" .
 
-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.
 
-makefile-browser-leftmost-column:
+`makefile-browser-leftmost-column':
    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.
 
-makefile-browser-selected-mark:
+`makefile-browser-selected-mark':
    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.
 
-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.
 
-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-find-filenames-as-targets'), otherwise
+   (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.
-   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\".
 
-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.
 
-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)
-  (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)
@@ -494,23 +588,32 @@ makefile-special-targets-list:
   (make-local-variable 'makefile-need-macro-pickup)
 
   ;; Font lock.
-  (if (fboundp 'make-face)
-      (makefile-define-space-face))
   (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.
-  (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 "\\$")
 
+  ;; Other abbrevs.
+  (setq local-abbrev-table makefile-mode-abbrev-table)
+
   ;; Filling.
   (make-local-variable 'fill-paragraph-function)
   (setq fill-paragraph-function 'makefile-fill-paragraph)
@@ -523,6 +626,9 @@ makefile-special-targets-list:
   (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")
@@ -626,7 +732,7 @@ Anywhere else just self-inserts."
        (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
@@ -660,7 +766,7 @@ Anywhere else just self-inserts."
     (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.")))
 
@@ -694,7 +800,7 @@ Anywhere else just self-inserts."
     (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.")))
@@ -703,15 +809,15 @@ Anywhere else just self-inserts."
   (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.
@@ -735,7 +841,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 "" ""))))
-    (mapcar '(lambda (name)
+    (mapcar (lambda (name)
               (if (and (not (file-directory-p name))
                        (not (string-match makefile-ignored-files-in-pickup-regex
                                           name)))
@@ -847,7 +953,7 @@ The context determines which are considered."
 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."
@@ -922,22 +1028,34 @@ definition and conveniently use this command."
     (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 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.
-     ((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)
@@ -967,10 +1085,7 @@ definition and conveniently use this command."
       ;; 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)))))
@@ -1051,7 +1166,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)
-    (kill-buffer (current-buffer))
+    (quit-window t)
     (pop-to-buffer my-client)))
 
 ;;;
@@ -1097,8 +1212,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)
-  (save-excursion
-    (set-buffer makefile-browser-client)
+  (with-current-buffer makefile-browser-client
     (end-of-line)
     (insert "\\\n\t")))
 
@@ -1143,11 +1257,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)
-       (make-variable-buffer-local 'makefile-browser-selection-vector)
        (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 ()
@@ -1240,7 +1353,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)))
-                      (needs-rebuild (or no-prereqs 
+                      (needs-rebuild (or no-prereqs
                                          (funcall
                                           makefile-query-one-target-method
                                           target-name
@@ -1268,11 +1381,11 @@ and generates the overview, one line per target name."
 
 (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))
-           (while (re-search-forward "\\\\[ \t]+$" (point-max) t)
+           (while (re-search-forward "\\\\[ \t]+$" nil t)
              (replace-match "\\" t t))))))
 
 
@@ -1281,21 +1394,23 @@ and generates the overview, one line per target name."
 ;;; ------------------------------------------------------------
 
 (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
 
 ;;; ------------------------------------------------------------
@@ -1370,20 +1485,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)
-    (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")
-    (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)
-    (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)))))
@@ -1407,25 +1522,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-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 ()
-  (= (makefile-end-of-line-point) (point-max)))
+  (= (line-end-position) (point-max)))
 
 (defun makefile-first-line-p ()
-  (= (makefile-beginning-of-line-point) (point-min)))
+  (= (line-beginning-position) (point-min)))
 
 \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.
@@ -1436,58 +1541,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.
-      (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)))
-
-(defun makefile-define-space-face ()
-  (make-face 'makefile-space-face)
-  (or (not (eq window-system 'x))
-      (face-differs-from-default-p 'makefile-space-face)
-      (let* ((params (frame-parameters))
-            (light-bg (cdr (assq 'background-mode params)))
-            (bg-color (cond ((eq (cdr (assq 'display-type params)) 'mono)
-                             (if light-bg "black" "white"))
-                            ((eq (cdr (assq 'display-type params)) 'grayscale)
-                             (if light-bg "black" "white"))
-                            (light-bg  ; Light color background.
-                             "hotpink")
-                            (t         ; Dark color background.
-                             "hotpink"))))
-       (set-face-background 'makefile-space-face bg-color))))
-
+      (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