changeset 9454:40340d39257d

(makefile-mode-name): Removed. (makefile-mode): Skip any number of "#"s at beginning of comments. (makefile-electric-keys): New variable. (makefile-electric-dot): Self insert if not at bol. (makefile-electric-equal): Really self-insert if not at bol. (makefile-pickup-everything): Prefix arg means force pickups to be redone. (makefile-insert-macro-ref): Don't use format. (makefile-runtime-macros-list): Added "$" to list. (makefile-insert-special-target): Don't use format. (makefile-insert-macro): Don't use format. (makefile-insert-target): Don't use format. (makefile-insert-target-ref): Don't use format. (makefile-electric-colon): Really self-insert if not at bol. (makefile-complete): New function. Bound to M-TAB. (makefile-do-macro-insertion): New function. (makefile-mode-map): Add menu bar bindings. (makefile-font-lock-keywords): New constant. (makefile-mode): Deal with font-lock, add-log, imenu. (makefile-macroassign-regex): Changed for use with font-lock. (makefile-dependency-regex): Changed for use with font-lock. (makefile-add-log-defun): New function. (makefile-menu-index-function): New function.
author Richard M. Stallman <rms@gnu.org>
date Tue, 11 Oct 1994 20:42:23 +0000
parents 67b759a9096d
children 856edef96682
files lisp/progmodes/make-mode.el
diffstat 1 files changed, 310 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/make-mode.el	Tue Oct 11 20:17:52 1994 +0000
+++ b/lisp/progmodes/make-mode.el	Tue Oct 11 20:42:23 1994 +0000
@@ -8,16 +8,13 @@
 ;; Keywords: unix, tools
 
 ;; RMS:
-;; This needs work.  The electric characters are too obnoxious.
-;; It should not define C-c LETTER.
-;; It should support knowing the list of existing macros and targets
-;; via M-TAB completion, not by preempting insertion of references.
+;; 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 `...'.
 
 ;; So, for the meantime, this is not the default mode for makefiles.
 
-;; $Id: makefile.el,v 1.15 1994/04/22 20:20:49 rms Exp rms $
+;; $Id: makefile.el,v 1.16 1994/05/22 22:10:39 rms Exp $
 
 ;; This file is part of GNU Emacs.
 
@@ -47,7 +44,7 @@
 ;; automatically updated, if necessary, whenever you invoke one of
 ;; these commands.  You can force it to be updated with C-c C-p.
 ;;
-;; The command C-c f adds certain filenames in the current directory
+;; The command C-c C-f adds certain filenames in the current directory
 ;; as targets.  You can filter out filenames by setting the variable
 ;; makefile-ignored-files-in-pickup-regex.
 ;;
@@ -56,7 +53,7 @@
 ;; prerequisites, which targets are out-of-date, and which have no
 ;; prerequisites.
 ;;
-;; The command C-c b pops up a browser window listing all target and
+;; 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
 ;; all marked items back in the Makefile with C-c TAB.
 ;;
@@ -65,17 +62,44 @@
 ;;
 ;; There are numerous other customization variables.
 
+;;
+;; To Do:
+;;
+;; * 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
+;;   interact with font-lock.
+;; * Would be nice to edit the commands in ksh-mode and have
+;;   indentation and slashification done automatically.  Hard.
+;; * Consider removing browser mode.  It seems useless.
+;; * ":" should notice when a new target is made and add it to the
+;;   list (or at least set makefile-need-target-pickup).
+;; * Make browser into a mode.
+;; * Clean up macro insertion stuff.  It is a mess.
+;; * Browser entry and exit is weird.  Normalize.
+;; * Browser needs to be rewritten.  Right now it is kind of a crock.
+;;   Should at least:
+;;    * Act more like dired/buffer menu/whatever.
+;;    * Highlight as mouse traverses.
+;;    * B2 inserts.
+;; * Update documentation above.
+;; * Update texinfo manual.
+;; * Update files.el.
+
+
+
 ;;; Code:
 
 (provide 'makefile)
 
+;; Sadly we need this for a macro.
+(eval-when-compile
+  (require 'imenu))
+
 ;;; ------------------------------------------------------------
 ;;; Configurable stuff
 ;;; ------------------------------------------------------------
 
-(defconst makefile-mode-name "Makefile"
-  "The \"pretty name\" of makefile-mode, as it appears in the modeline.")
-
 (defvar makefile-browser-buffer-name "*Macros and Targets*"
   "Name of the macro- and target browser buffer.")
 
@@ -92,6 +116,10 @@
 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.
 Set this variable to a non-nil value if you prefer curly braces
@@ -153,24 +181,39 @@
 at the beginning of a line in makefile-mode.")
 
 (defvar 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 ( ).")
 
+;; 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.
 (defconst makefile-dependency-regex
-  "^[^ \t#:]+\\([ \t]+[^ \t#:]+\\)*[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)"
+  "^\\([^ \n\t#:]+\\([ \t]+[^ \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.
 (defconst makefile-macroassign-regex
-  "^[^ \t][^:#=]*[\\*:\\+]?:?=.*$"
+  "^\\([^ \n\t][^:#=\n]*\\)[ \t]*[*:+]?:?="
   "Regex used to find macro assignment lines in a makefile.")
 
 (defconst makefile-ignored-files-in-pickup-regex
   "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)"
   "Regex for filenames that will NOT be included in the target list.")
 
+(defconst makefile-font-lock-keywords
+  (list
+   ;; Do macro assignments.  These get the "type" face rather
+   ;; arbitrarily.
+   (list makefile-macroassign-regex 1 'font-lock-type-face)
+
+    ;; Do dependencies.  These get the function name face.
+   (list makefile-dependency-regex 1 'font-lock-function-name-face)))
+
 ;;; ------------------------------------------------------------
 ;;; The following configurable variables are used in the
 ;;; up-to-date overview .
@@ -221,18 +264,37 @@
     ()
   (setq makefile-mode-map (make-sparse-keymap))
   ;; set up the keymap
-  (define-key makefile-mode-map "$"        'makefile-insert-macro-ref)
-  (define-key makefile-mode-map "\C-c:"    'makefile-insert-target-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:" '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-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 "\M-p"     'makefile-previous-dependency)
-  (define-key makefile-mode-map "\M-n"     'makefile-next-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
   "The keymap that is used in the macro- and target browser.")
@@ -266,8 +328,8 @@
   (modify-syntax-entry ?\} "){    " makefile-mode-syntax-table)
   (modify-syntax-entry ?#  "<     " makefile-mode-syntax-table)
   (modify-syntax-entry ?\n ">     " makefile-mode-syntax-table))
-  
-  
+
+
 ;;; ------------------------------------------------------------
 ;;; Internal variables.
 ;;; You don't need to configure below this line.
@@ -342,10 +404,6 @@
 makefile-mode can be configured by modifying the following
 variables:
 
-makefile-mode-name:
-    The \"pretty name\" of makefile-mode, as it
-    appears in the modeline.
-
 makefile-browser-buffer-name:
     Name of the macro- and target browser buffer.
 
@@ -407,6 +465,7 @@
    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)
@@ -417,20 +476,44 @@
   (make-local-variable 'makefile-has-prereqs)
   (make-local-variable 'makefile-need-target-pickup)
   (make-local-variable 'makefile-need-macro-pickup)
+
+  ;; Font lock.
+  (make-local-variable 'font-lock-keywords)
+  (setq font-lock-keywords makefile-font-lock-keywords)
+  (make-local-variable 'font-lock-keywords-case-fold-search)
+  (setq font-lock-keywords-case-fold-search t)
+
+  ;; 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)
+
+  ;; Comment stuff.
   (make-local-variable 'comment-start)
+  (setq comment-start "#")
   (make-local-variable 'comment-end)
+  (setq comment-end "")
   (make-local-variable 'comment-start-skip)
-  (setq comment-start "#")
-  (setq comment-end "")
-  (setq comment-start-skip "#[ \t]*")
+  (setq comment-start-skip "#+[ \t]*")
+
   ;; become the current major mode
   (setq major-mode 'makefile-mode)
-  (setq mode-name makefile-mode-name)
-  ;; activate keymap
+  (setq mode-name "Makefile")
+
+  ;; Activate keymap and syntax table.
   (use-local-map makefile-mode-map)
   (set-syntax-table makefile-mode-syntax-table)
-  (setq indent-tabs-mode t)		;real TABs are important in makefiles
-  (run-hooks 'makefile-mode-hook))  
+
+  ;; Real TABs are important in makefiles
+  (setq indent-tabs-mode t)
+  (run-hooks 'makefile-mode-hook))
+
+
+
+;;; Motion code.
 
 (defun makefile-next-dependency ()
   "Move (point) to the beginning of the next dependency line below (point)."
@@ -440,7 +523,7 @@
     (if (re-search-forward makefile-dependency-regex (point-max) t)
 	(progn (beginning-of-line) t)	; indicate success
       (goto-char here) nil)))
-      
+
 (defun makefile-previous-dependency ()
   "Move (point) to the beginning of the next dependency line above (point)."
   (interactive)
@@ -450,37 +533,41 @@
 	(progn (beginning-of-line) t)	; indicate success
       (goto-char here) nil)))
 
+
 
-;;; Stuff below here depends on the pickup state
+;;; Electric keys.  Blech.
 
-(defun makefile-electric-dot ()
-  "At (bol), offer completion on makefile-special-targets-list.
-Anywhere else just insert a dot."
-  (interactive)
+(defun makefile-electric-dot (arg)
+  "Prompt for the name of a special target to insert.
+Only does electric insertion at beginning of line.
+Anywhere else just self-inserts."
+  (interactive "p")
   (if (bolp)
       (makefile-insert-special-target)
-    (insert ".")))
+    (self-insert-command arg)))
 
 (defun makefile-insert-special-target ()
-  "Complete on makefile-special-targets-list, insert result at (point)."
+  "Propmt for and insert a special target name.
+Uses `makefile-special-targets' list."
   (interactive)
   (makefile-pickup-targets)
-  (let
-      ((special-target
-       (completing-read "Special target: "
-			makefile-special-targets-list nil nil nil)))
+  (let ((special-target
+	 (completing-read "Special target: "
+			  makefile-special-targets-list nil nil nil)))
     (if (zerop (length special-target))
 	()
-      (insert (format ".%s:" special-target))
+      (insert "." special-target ":")
       (makefile-forward-after-target-colon))))
 
-(defun makefile-electric-equal ()
-  "At (bol) do makefile-insert-macro.  Anywhere else just self-insert."
-  (interactive)
+(defun makefile-electric-equal (arg)
+  "Prompt for name of a macro to insert.
+Only does prompting if point is at beginning of line.
+Anywhere else just self-inserts."
+  (interactive "p")
   (makefile-pickup-macros)
   (if (bolp)
       (call-interactively 'makefile-insert-macro)
-    (insert "=")))
+    (self-insert-command arg)))
 
 (defun makefile-insert-macro (macro-name)
   "Prepare definition of a new macro."
@@ -489,7 +576,7 @@
   (if (not (zerop (length macro-name)))
       (progn
 	(beginning-of-line)
-	(insert (format "%s%s" macro-name makefile-macro-assign))
+	(insert macro-name makefile-macro-assign)
 	(setq makefile-need-macro-pickup t)
 	(makefile-remember-macro macro-name))))
 
@@ -500,10 +587,7 @@
     (progn
       (makefile-pickup-macros)
       (completing-read "Refer to macro: " makefile-macro-table nil nil nil))))
-   (if (not (zerop (length macro-name)))
-       (if (assoc macro-name makefile-runtime-macros-list)
-	   (insert (format "$%s" macro-name))
-	 (insert (makefile-format-macro-ref macro-name)))))
+  (makefile-do-macro-insertion macro-name))
 
 (defun makefile-insert-target (target-name)
   "Prepare definition of a new target (dependency line)."
@@ -511,7 +595,7 @@
   (if (not (zerop (length target-name)))
       (progn
 	(beginning-of-line)
-	(insert (format "%s%s" target-name makefile-target-colon))
+	(insert target-name makefile-target-colon)
 	(makefile-forward-after-target-colon)
 	(end-of-line)
 	(setq makefile-need-target-pickup t)
@@ -525,15 +609,18 @@
      (makefile-pickup-targets)
      (completing-read "Refer to target: " makefile-target-table nil nil nil))))
    (if (not (zerop (length target-name)))
-       (progn
-	 (insert (format "%s " target-name)))))
+       (insert target-name " ")))
 
-(defun makefile-electric-colon ()
-  "At (bol) defines a new target, anywhere else just self-insert ."
-  (interactive)
+(defun makefile-electric-colon (arg)
+  "Prompt for name of new target.
+Prompting only happens at beginning of line.
+Anywhere else just self-inserts."
+  (interactive "p")
   (if (bolp)
       (call-interactively 'makefile-insert-target)
-    (insert ":")))
+    (self-insert-command arg)))
+
+
 
 ;;; ------------------------------------------------------------
 ;;; Extracting targets and macros from an existing makefile
@@ -605,16 +692,20 @@
 	      (message "Picked up macro \"%s\" from line %d"
 		       macro-name line-number))))))
 
-(defun makefile-pickup-everything ()
+(defun makefile-pickup-everything (arg)
   "Calls makefile-pickup-targets and makefile-pickup-macros.
-See their documentation for what they do."
-  (interactive)
+See their documentation for what they do.
+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)))
   (makefile-pickup-macros)
   (makefile-pickup-targets)
   (if makefile-pickup-everything-picks-up-filenames-p
       (makefile-pickup-filenames-as-targets)))
 
-
 (defun makefile-pickup-filenames-as-targets ()
   "Scan the current directory for filenames, check each filename
 against makefile-ignored-files-in-pickup-regex and add all qualifying
@@ -632,8 +723,105 @@
 		       (message "Picked up file \"%s\" as target" name))))
 	    raw-filename-list)))
 
+
+
+;;; Completion.
+
+(defun makefile-complete ()
+  "Perform completion on Makefile construct preceding point.
+Can complete variable and target names.
+The context determines which are considered."
+  (interactive)
+  (let* ((beg (save-excursion
+		(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"))))))
+
+
+
 ;;; ------------------------------------------------------------
-;;; The browser window
+;;; Browser mode.
 ;;; ------------------------------------------------------------
 
 (defun makefile-browser-format-target-line (target selected)
@@ -812,6 +1000,7 @@
   (makefile-pickup-macros)
   (makefile-browse makefile-target-table makefile-macro-table))
 
+
 
 ;;; ------------------------------------------------------------
 ;;; Up-to-date overview buffer
@@ -911,6 +1100,8 @@
 (defun makefile-query-by-make-minus-q (target &optional filename)
   (not (zerop (call-process makefile-brave-make nil nil nil "-f" filename "-q" target))))
 
+
+
 ;;; ------------------------------------------------------------
 ;;; Continuation cleanup
 ;;; ------------------------------------------------------------
@@ -945,6 +1136,7 @@
 				    line-nr))))))))
     dont-save))
 	  
+
 
 ;;; ------------------------------------------------------------
 ;;; GNU make function support
@@ -981,12 +1173,19 @@
    prompt-list
    ","))
     
-
+
 
 ;;; ------------------------------------------------------------
 ;;; Utility functions
 ;;; ------------------------------------------------------------
 
+(defun makefile-do-macro-insertion (macro-name)
+  "Insert a macro reference."
+  (if (not (zerop (length macro-name)))
+      (if (assoc macro-name makefile-runtime-macros-list)
+	  (insert "$" macro-name)
+	(insert (makefile-format-macro-ref macro-name)))))
+
 (defun makefile-remember-target (target-name &optional has-prereqs)
   "Remember a given target if it is not already remembered for this buffer."
   (if (not (zerop (length target-name)))
@@ -1070,4 +1269,47 @@
 (defun makefile-first-line-p ()
   (= (makefile-beginning-of-line-point) (point-min)))
 
-;; makefile.el ends here
+
+
+;;; Support for other packages, like add-log and imenu.
+
+(defun makefile-add-log-defun ()
+  "Return name of target or macro point is in, or nil."
+  (save-excursion
+    (beginning-of-line)
+    (cond
+     ((looking-at makefile-macroassign-regex)
+      (buffer-substring (match-beginning 1)
+			(match-end 1)))
+     ((progn
+	(forward-char)
+	(re-search-backward makefile-dependency-regex nil t))
+      (buffer-substring (match-beginning 1)
+			(match-end 1)))
+     (t nil))))
+
+;; 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)
+      (setq zardoz (list (match-beginning 0) (match-end 0)
+			 (match-beginning 1) (match-end 1)
+							  ))
+      (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)))
+
+;;; makefile.el ends here