Bug fix in menu code for XEmacs.
[bpt/emacs.git] / lisp / progmodes / make-mode.el
CommitLineData
72c0ae01
ER
1;;; makefile.el --- makefile editing commands for Emacs
2
b8ca7cc3 3;; Copyright (C) 1992, 1994 Free Software Foundation, Inc.
58142744 4
72c0ae01 5;; Author: Thomas Neumann <tom@smart.bo.open.de>
9e9bf716 6;; Eric S. Raymond <esr@snark.thyrsus.com>
72c0ae01 7;; Adapted-By: ESR
fd7fa35a 8;; Keywords: unix, tools
72c0ae01 9
74416836 10;; RMS:
6783b1ce 11;; This needs work.
74416836
RS
12;; Also, the doc strings need fixing: the first line doesn't stand alone,
13;; and other usage is not high quality. Symbol names don't have `...'.
74416836
RS
14
15;; So, for the meantime, this is not the default mode for makefiles.
16
3b114205 17;; $Id: makefile.el,v 1.19 1994/10/30 21:20:42 rms Exp rms $
72c0ae01 18
72c0ae01
ER
19;; This file is part of GNU Emacs.
20
21;; GNU Emacs is free software; you can redistribute it and/or modify
22;; it under the terms of the GNU General Public License as published by
23;; the Free Software Foundation; either version 1, or (at your option)
24;; any later version.
25
26;; GNU Emacs is distributed in the hope that it will be useful,
27;; but WITHOUT ANY WARRANTY; without even the implied warranty of
28;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29;; GNU General Public License for more details.
30
31;; You should have received a copy of the GNU General Public License
32;; along with GNU Emacs; see the file COPYING. If not, write to
33;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
34
e41b2db1
ER
35;;; Commentary:
36
9e9bf716
ER
37;; A major mode for editing makefiles. The mode knows about Makefile
38;; syntax and defines M-n and M-p to move to next and previous productions.
39;;
40;; The keys $, =, : and . are electric; they try to help you fill in a
41;; macro reference, macro definition, ordinary target name, or special
42;; target name, respectively. Such names are completed using a list of
43;; targets and macro names parsed out of the makefile. This list is
44;; automatically updated, if necessary, whenever you invoke one of
45;; these commands. You can force it to be updated with C-c C-p.
46;;
6783b1ce 47;; The command C-c C-f adds certain filenames in the current directory
9e9bf716
ER
48;; as targets. You can filter out filenames by setting the variable
49;; makefile-ignored-files-in-pickup-regex.
50;;
51;; The command C-c C-u grinds for a bit, then pops up a report buffer
52;; showing which target names are up-to-date with respect to their
53;; prerequisites, which targets are out-of-date, and which have no
54;; prerequisites.
55;;
6783b1ce 56;; The command C-c C-b pops up a browser window listing all target and
9e9bf716
ER
57;; macro names. You can mark or unmark items wit C-c SPC, and insert
58;; all marked items back in the Makefile with C-c TAB.
59;;
60;; The command C-c TAB in the makefile buffer inserts a GNU make builtin.
61;; You will be prompted for the builtin's args.
62;;
63;; There are numerous other customization variables.
e41b2db1 64
6783b1ce
RS
65;;
66;; To Do:
67;;
308a2860
RS
68;; * makefile-backslash-region should be given better behavior.
69;; * Consider binding C-c C-c to comment-region (like cc-mode).
6783b1ce
RS
70;; * Eliminate electric stuff entirely.
71;; * It might be nice to highlight targets differently depending on
72;; whether they are up-to-date or not. Not sure how this would
73;; interact with font-lock.
74;; * Would be nice to edit the commands in ksh-mode and have
75;; indentation and slashification done automatically. Hard.
76;; * Consider removing browser mode. It seems useless.
77;; * ":" should notice when a new target is made and add it to the
78;; list (or at least set makefile-need-target-pickup).
308a2860 79;; * Make browser into a major mode.
6783b1ce
RS
80;; * Clean up macro insertion stuff. It is a mess.
81;; * Browser entry and exit is weird. Normalize.
82;; * Browser needs to be rewritten. Right now it is kind of a crock.
83;; Should at least:
84;; * Act more like dired/buffer menu/whatever.
85;; * Highlight as mouse traverses.
86;; * B2 inserts.
87;; * Update documentation above.
88;; * Update texinfo manual.
89;; * Update files.el.
90
91\f
92
72c0ae01
ER
93;;; Code:
94
95(provide 'makefile)
96
6783b1ce
RS
97;; Sadly we need this for a macro.
98(eval-when-compile
99 (require 'imenu))
100
72c0ae01 101;;; ------------------------------------------------------------
eb8c3be9 102;;; Configurable stuff
72c0ae01
ER
103;;; ------------------------------------------------------------
104
72c0ae01
ER
105(defvar makefile-browser-buffer-name "*Macros and Targets*"
106 "Name of the macro- and target browser buffer.")
107
108(defvar makefile-target-colon ":"
308a2860
RS
109 "String to append to all target names inserted by `makefile-insert-target'.
110\":\" or \"::\" are common values.")
72c0ae01
ER
111
112(defvar makefile-macro-assign " = "
308a2860 113 "String to append to all macro names inserted by `makefile-insert-macro'.
72c0ae01
ER
114The normal value should be \" = \", since this is what
115standard make expects. However, newer makes such as dmake
116allow a larger variety of different macro assignments, so you
117might prefer to use \" += \" or \" := \" .")
118
6783b1ce
RS
119(defvar makefile-electric-keys nil
120 "If non-nil, install electric keybindings.
121Default is nil.")
122
72c0ae01 123(defvar makefile-use-curly-braces-for-macros-p nil
9e9bf716 124 "Controls the style of generated macro references.
308a2860
RS
125t (actually non-nil) means macro references should use curly braces,
126like `${this}'.
127nil means use parentheses, like `$(this)'.")
72c0ae01
ER
128
129(defvar makefile-tab-after-target-colon t
308a2860
RS
130 "If non-nil, insert a TAB after a target colon.
131Otherwise, a space is inserted.
132The default is t.")
72c0ae01
ER
133
134(defvar makefile-browser-leftmost-column 10
135 "Number of blanks to the left of the browser selection mark.")
136
137(defvar makefile-browser-cursor-column 10
138 "Column in which the cursor is positioned when it moves
139up or down in the browser.")
140
308a2860
RS
141(defvar makefile-backslash-column 48
142 "*Column in which `makefile-backslash-region' inserts backslashes.")
143
72c0ae01
ER
144(defvar makefile-browser-selected-mark "+ "
145 "String used to mark selected entries in the browser.")
146
147(defvar makefile-browser-unselected-mark " "
148 "String used to mark unselected entries in the browser.")
149
150(defvar makefile-browser-auto-advance-after-selection-p t
308a2860 151 "If non-nil, cursor will move after item is selected in browser.")
72c0ae01
ER
152
153(defvar makefile-pickup-everything-picks-up-filenames-p nil
308a2860
RS
154 "If non-nil, `makefile-pickup-everything' picks up filenames as targets.
155\(i.e. it calls `makefile-find-filenames-as-targets').
156Otherwise filenames are omitted.")
72c0ae01
ER
157
158(defvar makefile-cleanup-continuations-p t
308a2860
RS
159 "If non-nil, automatically clean up continuation lines when saving.
160A line is cleaned up by removing all whitespace following a trailing
161backslash. This is done silently.
162IMPORTANT: Please note that enabling this option causes makefile-mode
72c0ae01
ER
163to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'.")
164
308a2860 165(defvar makefile-browser-hook '())
72c0ae01
ER
166
167;;
168;; Special targets for DMake, Sun's make ...
169;;
170(defvar makefile-special-targets-list
171 '(("DEFAULT") ("DONE") ("ERROR") ("EXPORT")
172 ("FAILED") ("GROUPEPILOG") ("GROUPPROLOG") ("IGNORE")
173 ("IMPORT") ("INCLUDE") ("INCLUDEDIRS") ("INIT")
174 ("KEEP_STATE") ("MAKEFILES") ("MAKE_VERSION") ("NO_PARALLEL")
175 ("PARALLEL") ("PHONY") ("PRECIOUS") ("REMOVE")
176 ("SCCS_GET") ("SILENT") ("SOURCE") ("SUFFIXES")
177 ("WAIT") ("c.o") ("C.o") ("m.o")
178 ("el.elc") ("y.c") ("s.o"))
308a2860
RS
179 "List of special targets.
180You will be offered to complete on one of those in the minibuffer whenever
181you enter a \".\" at the beginning of a line in makefile-mode.")
72c0ae01
ER
182
183(defvar makefile-runtime-macros-list
6783b1ce 184 '(("@") ("&") (">") ("<") ("*") ("^") ("?") ("%") ("$"))
72c0ae01
ER
185 "List of macros that are resolved by make at runtime.
186If you insert a macro reference using makefile-insert-macro-ref, the name
187of the macro is checked against this list. If it can be found its name will
188not be enclosed in { } or ( ).")
189
6783b1ce
RS
190;; Note that the first big subexpression is used by font lock. Note
191;; that if you change this regexp you must fix the imenu index
192;; function defined at the end of the file.
72c0ae01 193(defconst makefile-dependency-regex
6783b1ce 194 "^\\([^ \n\t#:]+\\([ \t]+[^ \t\n#:]+\\)*\\)[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)"
72c0ae01
ER
195 "Regex used to find dependency lines in a makefile.")
196
6783b1ce
RS
197;; Note that the first subexpression is used by font lock. Note that
198;; if you change this regexp you must fix the imenu index function
199;; defined at the end of the file.
72c0ae01 200(defconst makefile-macroassign-regex
308a2860 201 "^\\([^ \n\t][^:#= \t\n]*\\)[ \t]*[*:+]?:?="
72c0ae01
ER
202 "Regex used to find macro assignment lines in a makefile.")
203
204(defconst makefile-ignored-files-in-pickup-regex
0c5b5a13 205 "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)"
72c0ae01
ER
206 "Regex for filenames that will NOT be included in the target list.")
207
308a2860
RS
208;; TABs are important in Makefiles. So highlight them in font-lock.
209;; Thanks to Job Ganzevoort <Job.Ganzevoort@cwi.nl> for this.
210(defvar makefile-tab-face
211 (if (fboundp 'make-face)
212 (progn
213 (make-face 'makefile-tab-face)
214 (or (face-differs-from-default-p 'makefile-tab-face)
215 (set-face-background 'makefile-tab-face "hotpink"))
216 'makefile-tab-face)
217 '())
218 "Face to use for highlighting leading tabs in font-lock-mode.")
219
6783b1ce
RS
220(defconst makefile-font-lock-keywords
221 (list
af4b1991 222 ;; Do macro assignments. These get the "variable-name" face rather
6783b1ce 223 ;; arbitrarily.
af4b1991
SM
224 (list makefile-macroassign-regex 1 'font-lock-variable-name-face)
225 ;;
226 ;; Variable references even in targets/strings/comments:
227 '("\\$[({]\\([a-zA-Z0-9_]+\\)[})]" 1 font-lock-reference-face t)
228 ;;
229 ;; Do dependencies. These get the function name face.
308a2860
RS
230 (list makefile-dependency-regex 1 'font-lock-function-name-face)
231
232 ;; Highlight leading tab. Maybe highlighting all leading TABs
233 ;; would be nice? I don't know.
234 '("^\t" . makefile-tab-face)))
6783b1ce 235
72c0ae01
ER
236;;; ------------------------------------------------------------
237;;; The following configurable variables are used in the
238;;; up-to-date overview .
eb8c3be9 239;;; The standard configuration assumes that your `make' program
72c0ae01
ER
240;;; can be run in question/query mode using the `-q' option, this
241;;; means that the command
242;;;
243;;; make -q foo
244;;;
245;;; should return an exit status of zero if the target `foo' is
246;;; up to date and a nonzero exit status otherwise.
247;;; Many makes can do this although the docs/manpages do not mention
9e9bf716
ER
248;;; it. Try it with your favourite one. GNU make, System V make, and
249;;; Dennis Vadura's DMake have no problems.
72c0ae01
ER
250;;; Set the variable `makefile-brave-make' to the name of the
251;;; make utility that does this on your system.
eb8c3be9 252;;; To understand what this is all about see the function definition
72c0ae01
ER
253;;; of `makefile-query-by-make-minus-q' .
254;;; ------------------------------------------------------------
255
9e9bf716 256(defvar makefile-brave-make "make"
72c0ae01
ER
257 "A make that can handle the \'-q\' option.")
258
259(defvar makefile-query-one-target-method 'makefile-query-by-make-minus-q
260 "A function symbol [one that can be used as the first argument to
261funcall] that provides a function that must conform to the following
262interface:
263
264* As its first argument, it must accept the name of the target to
265 be checked, as a string.
266
267* As its second argument, it may accept the name of a makefile
9e9bf716 268 as a string. Depending on what you're going to do you may
72c0ae01
ER
269 not need this.
270
271* It must return the integer value 0 (zero) if the given target
272 should be considered up-to-date in the context of the given
273 makefile, any nonzero integer value otherwise.")
274
275(defvar makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*"
276 "Name of the Up-to-date overview buffer.")
277
72c0ae01
ER
278;;; --- end of up-to-date-overview configuration ------------------
279
72c0ae01
ER
280(defvar makefile-mode-map nil
281 "The keymap that is used in makefile-mode.")
282(if makefile-mode-map
283 ()
284 (setq makefile-mode-map (make-sparse-keymap))
285 ;; set up the keymap
6783b1ce
RS
286 (define-key makefile-mode-map "\C-c:" 'makefile-insert-target-ref)
287 (if makefile-electric-keys
288 (progn
289 (define-key makefile-mode-map "$" 'makefile-insert-macro-ref)
290 (define-key makefile-mode-map ":" 'makefile-electric-colon)
291 (define-key makefile-mode-map "=" 'makefile-electric-equal)
292 (define-key makefile-mode-map "." 'makefile-electric-dot)))
72c0ae01 293 (define-key makefile-mode-map "\C-c\C-f" 'makefile-pickup-filenames-as-targets)
72c0ae01
ER
294 (define-key makefile-mode-map "\C-c\C-b" 'makefile-switch-to-browser)
295 (define-key makefile-mode-map "\C-c\C-p" 'makefile-pickup-everything)
296 (define-key makefile-mode-map "\C-c\C-u" 'makefile-create-up-to-date-overview)
297 (define-key makefile-mode-map "\C-c\C-i" 'makefile-insert-gmake-function)
308a2860 298 (define-key makefile-mode-map "\C-c\C-\\" 'makefile-backslash-region)
72c0ae01 299 (define-key makefile-mode-map "\M-p" 'makefile-previous-dependency)
6783b1ce
RS
300 (define-key makefile-mode-map "\M-n" 'makefile-next-dependency)
301 (define-key makefile-mode-map "\e\t" 'makefile-complete)
302
303 ;; Make menus.
304 (define-key makefile-mode-map [menu-bar makefile-mode]
305 (cons "Makefile" (make-sparse-keymap "Makefile")))
306
307 (define-key makefile-mode-map [menu-bar makefile-mode browse]
308 '("Pop up Makefile browser" . makefile-switch-to-browser))
309 (define-key makefile-mode-map [menu-bar makefile-mode complete]
310 '("Complete target or macro" . makefile-complete))
311 (define-key makefile-mode-map [menu-bar makefile-mode pickup]
312 '("Find targets and macros" . makefile-pickup-everything))
313
314 (define-key makefile-mode-map [menu-bar makefile-mode prev]
315 '("Move to previous dependency" . makefile-previous-dependency))
316 (define-key makefile-mode-map [menu-bar makefile-mode next]
317 '("Move to next dependency" . makefile-next-dependency)))
72c0ae01
ER
318
319(defvar makefile-browser-map nil
320 "The keymap that is used in the macro- and target browser.")
321(if makefile-browser-map
322 ()
323 (setq makefile-browser-map (make-sparse-keymap))
324 (define-key makefile-browser-map "n" 'makefile-browser-next-line)
325 (define-key makefile-browser-map "\C-n" 'makefile-browser-next-line)
326 (define-key makefile-browser-map "p" 'makefile-browser-previous-line)
327 (define-key makefile-browser-map "\C-p" 'makefile-browser-previous-line)
328 (define-key makefile-browser-map " " 'makefile-browser-toggle)
329 (define-key makefile-browser-map "i" 'makefile-browser-insert-selection)
330 (define-key makefile-browser-map "I" 'makefile-browser-insert-selection-and-quit)
331 (define-key makefile-browser-map "\C-c\C-m" 'makefile-browser-insert-continuation)
332 (define-key makefile-browser-map "q" 'makefile-browser-quit)
333 ;; disable horizontal movement
334 (define-key makefile-browser-map "\C-b" 'undefined)
335 (define-key makefile-browser-map "\C-f" 'undefined))
336
337
308a2860 338(defvar makefile-mode-syntax-table nil)
72c0ae01
ER
339(if makefile-mode-syntax-table
340 ()
341 (setq makefile-mode-syntax-table (make-syntax-table))
342 (modify-syntax-entry ?\( "() " makefile-mode-syntax-table)
343 (modify-syntax-entry ?\) ")( " makefile-mode-syntax-table)
344 (modify-syntax-entry ?\[ "(] " makefile-mode-syntax-table)
345 (modify-syntax-entry ?\] "([ " makefile-mode-syntax-table)
346 (modify-syntax-entry ?\{ "(} " makefile-mode-syntax-table)
347 (modify-syntax-entry ?\} "){ " makefile-mode-syntax-table)
af4b1991
SM
348 (modify-syntax-entry ?\' "\" " makefile-mode-syntax-table)
349 (modify-syntax-entry ?\` "\" " makefile-mode-syntax-table)
72c0ae01
ER
350 (modify-syntax-entry ?# "< " makefile-mode-syntax-table)
351 (modify-syntax-entry ?\n "> " makefile-mode-syntax-table))
6783b1ce
RS
352
353
72c0ae01
ER
354;;; ------------------------------------------------------------
355;;; Internal variables.
356;;; You don't need to configure below this line.
357;;; ------------------------------------------------------------
358
359(defvar makefile-target-table nil
308a2860 360 "Table of all target names known for this buffer.")
72c0ae01
ER
361
362(defvar makefile-macro-table nil
308a2860 363 "Table of all macro names known for this buffer.")
72c0ae01
ER
364
365(defvar makefile-browser-client
366 "A buffer in makefile-mode that is currently using the browser.")
367
368(defvar makefile-browser-selection-vector nil)
9e9bf716
ER
369(defvar makefile-has-prereqs nil)
370(defvar makefile-need-target-pickup t)
371(defvar makefile-need-macro-pickup t)
72c0ae01
ER
372
373(defvar makefile-mode-hook '())
374
308a2860
RS
375;; Each element looks like '("GNU MAKE FUNCTION" "ARG" "ARG" ... )
376;; Each "ARG" is used as a prompt for a required argument.
72c0ae01 377(defconst makefile-gnumake-functions-alist
72c0ae01
ER
378 '(
379 ;; Text functions
380 ("subst" "From" "To" "In")
381 ("patsubst" "Pattern" "Replacement" "In")
382 ("strip" "Text")
383 ("findstring" "Find what" "In")
384 ("filter" "Pattern" "Text")
385 ("filter-out" "Pattern" "Text")
386 ("sort" "List")
387 ;; Filename functions
388 ("dir" "Names")
389 ("notdir" "Names")
390 ("suffix" "Names")
391 ("basename" "Names")
392 ("addsuffix" "Suffix" "Names")
393 ("join" "List 1" "List 2")
394 ("word" "Index" "Text")
395 ("words" "Text")
396 ("firstword" "Text")
397 ("wildcard" "Pattern")
398 ;; Misc functions
399 ("foreach" "Variable" "List" "Text")
400 ("origin" "Variable")
308a2860 401 ("shell" "Command")))
72c0ae01
ER
402
403
404;;; ------------------------------------------------------------
405;;; The mode function itself.
406;;; ------------------------------------------------------------
407
5c2946c7 408;;;###autoload
72c0ae01
ER
409(defun makefile-mode ()
410 "Major mode for editing Makefiles.
411Calling this function invokes the function(s) \"makefile-mode-hook\" before
412doing anything else.
413
414\\{makefile-mode-map}
415
416In the browser, use the following keys:
417
418\\{makefile-browser-map}
419
420makefile-mode can be configured by modifying the following
421variables:
422
72c0ae01
ER
423makefile-browser-buffer-name:
424 Name of the macro- and target browser buffer.
425
426makefile-target-colon:
427 The string that gets appended to all target names
428 inserted by makefile-insert-target.
429 \":\" or \"::\" are quite common values.
430
431makefile-macro-assign:
432 The string that gets appended to all macro names
433 inserted by makefile-insert-macro.
434 The normal value should be \" = \", since this is what
435 standard make expects. However, newer makes such as dmake
436 allow a larger variety of different macro assignments, so you
437 might prefer to use \" += \" or \" := \" .
438
439makefile-tab-after-target-colon:
440 If you want a TAB (instead of a space) to be appended after the
441 target colon, then set this to a non-nil value.
442
443makefile-browser-leftmost-column:
444 Number of blanks to the left of the browser selection mark.
445
446makefile-browser-cursor-column:
447 Column in which the cursor is positioned when it moves
448 up or down in the browser.
449
450makefile-browser-selected-mark:
451 String used to mark selected entries in the browser.
452
453makefile-browser-unselected-mark:
454 String used to mark unselected entries in the browser.
455
456makefile-browser-auto-advance-after-selection-p:
457 If this variable is set to a non-nil value the cursor
458 will automagically advance to the next line after an item
459 has been selected in the browser.
460
72c0ae01
ER
461makefile-pickup-everything-picks-up-filenames-p:
462 If this variable is set to a non-nil value then
463 makefile-pickup-everything also picks up filenames as targets
464 (i.e. it calls makefile-find-filenames-as-targets), otherwise
465 filenames are omitted.
466
467makefile-cleanup-continuations-p:
468 If this variable is set to a non-nil value then makefile-mode
469 will assure that no line in the file ends with a backslash
470 (the continuation character) followed by any whitespace.
471 This is done by silently removing the trailing whitespace, leaving
472 the backslash itself intact.
473 IMPORTANT: Please note that enabling this option causes makefile-mode
474 to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'.
475
476makefile-browser-hook:
477 A function or list of functions to be called just before the
9e9bf716 478 browser is entered. This is executed in the makefile buffer.
72c0ae01
ER
479
480makefile-special-targets-list:
481 List of special targets. You will be offered to complete
482 on one of those in the minibuffer whenever you enter a \".\"
483 at the beginning of a line in makefile-mode."
6783b1ce 484
72c0ae01
ER
485 (interactive)
486 (kill-all-local-variables)
9854c615 487 (make-local-variable 'local-write-file-hooks)
b8ca7cc3 488 (setq local-write-file-hooks
cd99f76d 489 '(makefile-cleanup-continuations makefile-warn-suspicious-lines))
b8ca7cc3
RS
490 (make-local-variable 'makefile-target-table)
491 (make-local-variable 'makefile-macro-table)
492 (make-local-variable 'makefile-has-prereqs)
493 (make-local-variable 'makefile-need-target-pickup)
494 (make-local-variable 'makefile-need-macro-pickup)
6783b1ce
RS
495
496 ;; Font lock.
af4b1991
SM
497 (make-local-variable 'font-lock-defaults)
498 (setq font-lock-defaults '(makefile-font-lock-keywords))
6783b1ce
RS
499
500 ;; Add-log.
501 (make-local-variable 'add-log-current-defun-function)
502 (setq add-log-current-defun-function 'makefile-add-log-defun)
503
504 ;; Imenu.
505 (make-local-variable 'imenu-create-index-function)
506 (setq imenu-create-index-function 'makefile-menu-index-function)
507
3b114205
RS
508 ;; Dabbrev.
509 (make-local-variable 'dabbrev-abbrev-skip-leading-regexp)
510 (setq dabbrev-abbrev-skip-leading-regexp "\\$")
511
6783b1ce 512 ;; Comment stuff.
531b2a28 513 (make-local-variable 'comment-start)
72c0ae01 514 (setq comment-start "#")
6783b1ce 515 (make-local-variable 'comment-end)
72c0ae01 516 (setq comment-end "")
6783b1ce
RS
517 (make-local-variable 'comment-start-skip)
518 (setq comment-start-skip "#+[ \t]*")
519
72c0ae01
ER
520 ;; become the current major mode
521 (setq major-mode 'makefile-mode)
6783b1ce
RS
522 (setq mode-name "Makefile")
523
524 ;; Activate keymap and syntax table.
72c0ae01
ER
525 (use-local-map makefile-mode-map)
526 (set-syntax-table makefile-mode-syntax-table)
6783b1ce
RS
527
528 ;; Real TABs are important in makefiles
529 (setq indent-tabs-mode t)
530 (run-hooks 'makefile-mode-hook))
531
532\f
533
534;;; Motion code.
72c0ae01 535
72c0ae01 536(defun makefile-next-dependency ()
9e9bf716 537 "Move (point) to the beginning of the next dependency line below (point)."
72c0ae01
ER
538 (interactive)
539 (let ((here (point)))
540 (end-of-line)
541 (if (re-search-forward makefile-dependency-regex (point-max) t)
542 (progn (beginning-of-line) t) ; indicate success
543 (goto-char here) nil)))
6783b1ce 544
72c0ae01 545(defun makefile-previous-dependency ()
9e9bf716 546 "Move (point) to the beginning of the next dependency line above (point)."
72c0ae01
ER
547 (interactive)
548 (let ((here (point)))
549 (beginning-of-line)
550 (if (re-search-backward makefile-dependency-regex (point-min) t)
551 (progn (beginning-of-line) t) ; indicate success
552 (goto-char here) nil)))
553
6783b1ce 554\f
72c0ae01 555
6783b1ce 556;;; Electric keys. Blech.
9e9bf716 557
6783b1ce
RS
558(defun makefile-electric-dot (arg)
559 "Prompt for the name of a special target to insert.
560Only does electric insertion at beginning of line.
561Anywhere else just self-inserts."
562 (interactive "p")
72c0ae01
ER
563 (if (bolp)
564 (makefile-insert-special-target)
6783b1ce 565 (self-insert-command arg)))
72c0ae01 566
72c0ae01 567(defun makefile-insert-special-target ()
6783b1ce
RS
568 "Propmt for and insert a special target name.
569Uses `makefile-special-targets' list."
72c0ae01 570 (interactive)
9e9bf716 571 (makefile-pickup-targets)
6783b1ce
RS
572 (let ((special-target
573 (completing-read "Special target: "
574 makefile-special-targets-list nil nil nil)))
72c0ae01
ER
575 (if (zerop (length special-target))
576 ()
6783b1ce 577 (insert "." special-target ":")
72c0ae01
ER
578 (makefile-forward-after-target-colon))))
579
6783b1ce
RS
580(defun makefile-electric-equal (arg)
581 "Prompt for name of a macro to insert.
582Only does prompting if point is at beginning of line.
583Anywhere else just self-inserts."
584 (interactive "p")
9e9bf716 585 (makefile-pickup-macros)
72c0ae01
ER
586 (if (bolp)
587 (call-interactively 'makefile-insert-macro)
6783b1ce 588 (self-insert-command arg)))
72c0ae01
ER
589
590(defun makefile-insert-macro (macro-name)
591 "Prepare definition of a new macro."
592 (interactive "sMacro Name: ")
9e9bf716 593 (makefile-pickup-macros)
72c0ae01
ER
594 (if (not (zerop (length macro-name)))
595 (progn
596 (beginning-of-line)
6783b1ce 597 (insert macro-name makefile-macro-assign)
9e9bf716 598 (setq makefile-need-macro-pickup t)
72c0ae01
ER
599 (makefile-remember-macro macro-name))))
600
72c0ae01 601(defun makefile-insert-macro-ref (macro-name)
9e9bf716 602 "Complete on a list of known macros, then insert complete ref at (point)."
72c0ae01
ER
603 (interactive
604 (list
9e9bf716
ER
605 (progn
606 (makefile-pickup-macros)
607 (completing-read "Refer to macro: " makefile-macro-table nil nil nil))))
6783b1ce 608 (makefile-do-macro-insertion macro-name))
72c0ae01 609
72c0ae01
ER
610(defun makefile-insert-target (target-name)
611 "Prepare definition of a new target (dependency line)."
612 (interactive "sTarget: ")
613 (if (not (zerop (length target-name)))
614 (progn
615 (beginning-of-line)
6783b1ce 616 (insert target-name makefile-target-colon)
72c0ae01
ER
617 (makefile-forward-after-target-colon)
618 (end-of-line)
9e9bf716 619 (setq makefile-need-target-pickup t)
72c0ae01
ER
620 (makefile-remember-target target-name))))
621
72c0ae01 622(defun makefile-insert-target-ref (target-name)
9e9bf716 623 "Complete on a list of known targets, then insert target-ref at (point) ."
72c0ae01
ER
624 (interactive
625 (list
0c5b5a13 626 (progn
9e9bf716
ER
627 (makefile-pickup-targets)
628 (completing-read "Refer to target: " makefile-target-table nil nil nil))))
72c0ae01 629 (if (not (zerop (length target-name)))
6783b1ce 630 (insert target-name " ")))
72c0ae01 631
6783b1ce
RS
632(defun makefile-electric-colon (arg)
633 "Prompt for name of new target.
634Prompting only happens at beginning of line.
635Anywhere else just self-inserts."
636 (interactive "p")
72c0ae01
ER
637 (if (bolp)
638 (call-interactively 'makefile-insert-target)
6783b1ce
RS
639 (self-insert-command arg)))
640
641\f
72c0ae01 642
72c0ae01
ER
643;;; ------------------------------------------------------------
644;;; Extracting targets and macros from an existing makefile
645;;; ------------------------------------------------------------
646
647(defun makefile-pickup-targets ()
308a2860 648 "Notice names of all target definitions in Makefile."
72c0ae01 649 (interactive)
9e9bf716
ER
650 (if (not makefile-need-target-pickup)
651 nil
652 (setq makefile-need-target-pickup nil)
653 (setq makefile-target-table nil)
654 (setq makefile-has-prereqs nil)
655 (save-excursion
656 (goto-char (point-min))
657 (while (re-search-forward makefile-dependency-regex (point-max) t)
658 (makefile-add-this-line-targets)))
659 (message "Read targets OK.")))
72c0ae01
ER
660
661(defun makefile-add-this-line-targets ()
662 (save-excursion
663 (beginning-of-line)
9e9bf716
ER
664 (let ((done-with-line nil)
665 (line-number (1+ (count-lines (point-min) (point)))))
72c0ae01
ER
666 (while (not done-with-line)
667 (skip-chars-forward " \t")
668 (if (not (setq done-with-line (or (eolp)
669 (char-equal (char-after (point)) ?:))))
670 (progn
671 (let* ((start-of-target-name (point))
672 (target-name
673 (progn
674 (skip-chars-forward "^ \t:#")
9e9bf716
ER
675 (buffer-substring start-of-target-name (point))))
676 (has-prereqs
677 (not (looking-at ":[ \t]*$"))))
678 (if (makefile-remember-target target-name has-prereqs)
679 (message "Picked up target \"%s\" from line %d"
680 target-name line-number)))))))))
72c0ae01 681
72c0ae01 682(defun makefile-pickup-macros ()
308a2860 683 "Notice names of all macro definitions in Makefile."
72c0ae01 684 (interactive)
9e9bf716
ER
685 (if (not makefile-need-macro-pickup)
686 nil
687 (setq makefile-need-macro-pickup nil)
688 (setq makefile-macro-table nil)
689 (save-excursion
690 (goto-char (point-min))
691 (while (re-search-forward makefile-macroassign-regex (point-max) t)
692 (makefile-add-this-line-macro)
693 (forward-line 1)))
694 (message "Read macros OK.")))
72c0ae01
ER
695
696(defun makefile-add-this-line-macro ()
697 (save-excursion
698 (beginning-of-line)
699 (skip-chars-forward " \t")
700 (if (not (eolp))
701 (let* ((start-of-macro-name (point))
9e9bf716 702 (line-number (1+ (count-lines (point-min) (point))))
72c0ae01
ER
703 (macro-name (progn
704 (skip-chars-forward "^ \t:#=*")
705 (buffer-substring start-of-macro-name (point)))))
706 (if (makefile-remember-macro macro-name)
9e9bf716
ER
707 (message "Picked up macro \"%s\" from line %d"
708 macro-name line-number))))))
72c0ae01 709
6783b1ce 710(defun makefile-pickup-everything (arg)
308a2860 711 "Notice names of all macros and targets in Makefile.
6783b1ce
RS
712Prefix arg means force pickups to be redone."
713 (interactive "P")
714 (if arg
715 (progn
716 (setq makefile-need-target-pickup t)
717 (setq makefile-need-macro-pickup t)))
72c0ae01
ER
718 (makefile-pickup-macros)
719 (makefile-pickup-targets)
720 (if makefile-pickup-everything-picks-up-filenames-p
721 (makefile-pickup-filenames-as-targets)))
722
72c0ae01 723(defun makefile-pickup-filenames-as-targets ()
308a2860
RS
724 "Scan the current directory for filenames to use as targets.
725Checks each filename against `makefile-ignored-files-in-pickup-regex'
726and adds all qualifying names to the list of known targets."
72c0ae01
ER
727 (interactive)
728 (let* ((dir (file-name-directory (buffer-file-name)))
729 (raw-filename-list (if dir
730 (file-name-all-completions "" dir)
731 (file-name-all-completions "" ""))))
732 (mapcar '(lambda (name)
733 (if (and (not (file-directory-p name))
734 (not (string-match makefile-ignored-files-in-pickup-regex
735 name)))
736 (if (makefile-remember-target name)
737 (message "Picked up file \"%s\" as target" name))))
738 raw-filename-list)))
739
6783b1ce
RS
740\f
741
742;;; Completion.
743
744(defun makefile-complete ()
745 "Perform completion on Makefile construct preceding point.
746Can complete variable and target names.
747The context determines which are considered."
748 (interactive)
749 (let* ((beg (save-excursion
750 (skip-chars-backward "^$(){}:#= \t\n")
751 (point)))
752 (try (buffer-substring beg (point)))
753 (do-macros nil)
754 (paren nil))
755
756 (save-excursion
757 (goto-char beg)
758 (let ((pc (preceding-char)))
759 (cond
760 ;; Beginning of line means anything.
761 ((bolp)
762 ())
763
764 ;; Preceding "$" means macros only.
765 ((= pc ?$)
766 (setq do-macros t))
767
768 ;; Preceding "$(" or "${" means macros only.
769 ((and (or (= pc ?{)
770 (= pc ?\())
771 (progn
772 (setq paren pc)
773 (backward-char)
774 (and (not (bolp))
775 (= (preceding-char) ?$))))
776 (setq do-macros t)))))
777
778 ;; Try completion.
779 (let* ((table (append (if do-macros
780 '()
781 makefile-target-table)
782 makefile-macro-table))
783 (completion (try-completion try table)))
784 (cond
785 ;; Exact match, so insert closing paren or colon.
786 ((eq completion t)
787 (insert (if do-macros
788 (if (eq paren ?{)
789 ?}
790 ?\))
791 (if (save-excursion
792 (goto-char beg)
793 (bolp))
794 ":"
795 " "))))
796
797 ;; No match.
798 ((null completion)
799 (message "Can't find completion for \"%s\"" try)
800 (ding))
801
802 ;; Partial completion.
803 ((not (string= try completion))
804 ;; FIXME it would be nice to supply the closing paren if an
805 ;; exact, unambiguous match were found. That is not possible
806 ;; right now. Ditto closing ":" for targets.
807 (delete-region beg (point))
808
809 ;; DO-MACROS means doing macros only. If not that, then check
810 ;; to see if this completion is a macro. Special insertion
811 ;; must be done for macros.
812 (if (or do-macros
813 (assoc completion makefile-macro-table))
814 (let ((makefile-use-curly-braces-for-macros-p
815 (or (eq paren ?{)
816 makefile-use-curly-braces-for-macros-p)))
817 (delete-backward-char 2)
818 (makefile-do-macro-insertion completion)
819 (delete-backward-char 1))
820
821 ;; Just insert targets.
822 (insert completion)))
823
824 ;; Can't complete any more, so make completion list. FIXME
825 ;; this doesn't do the right thing when the completion is
826 ;; actually inserted. I don't think there is an easy way to do
827 ;; that.
828 (t
829 (message "Making completion list...")
830 (let ((list (all-completions try table)))
831 (with-output-to-temp-buffer "*Completions*"
832 (display-completion-list list)))
833 (message "Making completion list...done"))))))
834
835\f
836
308a2860
RS
837;; Backslashification. Stolen from cc-mode.el.
838
839(defun makefile-backslashify-current-line (doit)
840 (end-of-line)
841 (if doit
842 (if (not (save-excursion
843 (forward-char -1)
844 (eq (char-after (point)) ?\\ )))
845 (progn
846 (if (>= (current-column) makefile-backslash-column)
847 (insert " \\")
848 (while (<= (current-column) makefile-backslash-column)
849 (insert "\t")
850 (end-of-line))
851 (delete-char -1)
852 (while (< (current-column) makefile-backslash-column)
853 (insert " ")
854 (end-of-line))
855 (insert "\\"))))
856 (if (not (bolp))
857 (progn
858 (forward-char -1)
859 (if (eq (char-after (point)) ?\\ )
860 (let ((saved (save-excursion
861 (end-of-line)
862 (point))))
863 (skip-chars-backward " \t")
864 (delete-region (point) saved)))))))
865
866(defun makefile-backslash-region (beg end arg)
867 "Insert backslashes at end of every line in region.
868Useful for defining multi-line rules.
869If called with a prefix argument, trailing backslahes are removed."
870 (interactive "r\nP")
871 (save-excursion
872 (let ((do-lastline-p (progn (goto-char end) (not (bolp)))))
873 (save-restriction
874 (narrow-to-region beg end)
875 (goto-char (point-min))
876 (while (not (save-excursion
877 (forward-line 1)
878 (eobp)))
879 (makefile-backslashify-current-line (null arg))
880 (forward-line 1)))
881 (and do-lastline-p
882 (progn (goto-char end)
883 (makefile-backslashify-current-line (null arg)))))))
884
885\f
886
72c0ae01 887;;; ------------------------------------------------------------
6783b1ce 888;;; Browser mode.
72c0ae01
ER
889;;; ------------------------------------------------------------
890
72c0ae01
ER
891(defun makefile-browser-format-target-line (target selected)
892 (format
893 (concat (make-string makefile-browser-leftmost-column ?\ )
894 (if selected
895 makefile-browser-selected-mark
896 makefile-browser-unselected-mark)
897 "%s%s")
898 target makefile-target-colon))
899
900(defun makefile-browser-format-macro-line (macro selected)
901 (format
902 (concat (make-string makefile-browser-leftmost-column ?\ )
903 (if selected
904 makefile-browser-selected-mark
905 makefile-browser-unselected-mark)
906 (makefile-format-macro-ref macro))))
907
908(defun makefile-browser-fill (targets macros)
c72344c7
RS
909 (let ((inhibit-read-only t))
910 (goto-char (point-min))
911 (erase-buffer)
912 (mapconcat
913 (function
914 (lambda (item) (insert (makefile-browser-format-target-line (car item) nil) "\n")))
915 targets
916 "")
917 (mapconcat
918 (function
919 (lambda (item) (insert (makefile-browser-format-macro-line (car item) nil) "\n")))
920 macros
921 "")
922 (sort-lines nil (point-min) (point-max))
923 (goto-char (1- (point-max)))
924 (delete-char 1) ; remove unnecessary newline at eob
925 (goto-char (point-min))
926 (forward-char makefile-browser-cursor-column)))
72c0ae01
ER
927
928;;;
929;;; Moving up and down in the browser
930;;;
931
932(defun makefile-browser-next-line ()
933 "Move the browser selection cursor to the next line."
934 (interactive)
935 (if (not (makefile-last-line-p))
936 (progn
937 (forward-line 1)
938 (forward-char makefile-browser-cursor-column))))
939
940(defun makefile-browser-previous-line ()
941 "Move the browser selection cursor to the previous line."
942 (interactive)
943 (if (not (makefile-first-line-p))
944 (progn
945 (forward-line -1)
946 (forward-char makefile-browser-cursor-column))))
947
948;;;
949;;; Quitting the browser (returns to client buffer)
950;;;
951
952(defun makefile-browser-quit ()
308a2860 953 "Leave the browser and return to the makefile buffer."
72c0ae01
ER
954 (interactive)
955 (let ((my-client makefile-browser-client))
956 (setq makefile-browser-client nil) ; we quitted, so NO client!
957 (set-buffer-modified-p nil)
958 (kill-buffer (current-buffer))
959 (pop-to-buffer my-client)))
960
961;;;
962;;; Toggle state of a browser item
963;;;
964
965(defun makefile-browser-toggle ()
966 "Toggle the selection state of the browser item at the cursor position."
967 (interactive)
968 (let ((this-line (count-lines (point-min) (point))))
969 (setq this-line (max 1 this-line))
970 (makefile-browser-toggle-state-for-line this-line)
971 (goto-line this-line)
c72344c7
RS
972 (let ((inhibit-read-only t))
973 (beginning-of-line)
974 (if (makefile-browser-on-macro-line-p)
975 (let ((macro-name (makefile-browser-this-line-macro-name)))
976 (kill-line)
977 (insert
978 (makefile-browser-format-macro-line
979 macro-name
980 (makefile-browser-get-state-for-line this-line))))
981 (let ((target-name (makefile-browser-this-line-target-name)))
72c0ae01
ER
982 (kill-line)
983 (insert
c72344c7
RS
984 (makefile-browser-format-target-line
985 target-name
986 (makefile-browser-get-state-for-line this-line))))))
72c0ae01
ER
987 (beginning-of-line)
988 (forward-char makefile-browser-cursor-column)
989 (if makefile-browser-auto-advance-after-selection-p
990 (makefile-browser-next-line))))
991
992;;;
993;;; Making insertions into the client buffer
994;;;
995
996(defun makefile-browser-insert-continuation ()
9e9bf716 997 "Insert a makefile continuation.
308a2860 998In the makefile buffer, go to (end-of-line), insert a \'\\\'
72c0ae01 999character, insert a new blank line, go to that line and indent by one TAB.
9e9bf716
ER
1000This is most useful in the process of creating continued lines when copying
1001large dependencies from the browser to the client buffer.
a4e104bf 1002\(point) advances accordingly in the client buffer."
72c0ae01
ER
1003 (interactive)
1004 (save-excursion
1005 (set-buffer makefile-browser-client)
1006 (end-of-line)
1007 (insert "\\\n\t")))
1008
1009(defun makefile-browser-insert-selection ()
308a2860 1010 "Insert all selected targets and/or macros in the makefile buffer.
72c0ae01
ER
1011Insertion takes place at (point)."
1012 (interactive)
1013 (save-excursion
1014 (goto-line 1)
1015 (let ((current-line 1))
1016 (while (not (eobp))
1017 (if (makefile-browser-get-state-for-line current-line)
1018 (makefile-browser-send-this-line-item))
1019 (forward-line 1)
1020 (setq current-line (1+ current-line))))))
1021
1022(defun makefile-browser-insert-selection-and-quit ()
1023 (interactive)
1024 (makefile-browser-insert-selection)
1025 (makefile-browser-quit))
1026
1027(defun makefile-browser-send-this-line-item ()
1028 (if (makefile-browser-on-macro-line-p)
1029 (save-excursion
1030 (let ((macro-name (makefile-browser-this-line-macro-name)))
1031 (set-buffer makefile-browser-client)
1032 (insert (makefile-format-macro-ref macro-name) " ")))
1033 (save-excursion
1034 (let ((target-name (makefile-browser-this-line-target-name)))
1035 (set-buffer makefile-browser-client)
1036 (insert target-name " ")))))
1037
72c0ae01
ER
1038(defun makefile-browser-start-interaction ()
1039 (use-local-map makefile-browser-map)
1040 (setq buffer-read-only t))
1041
72c0ae01
ER
1042(defun makefile-browse (targets macros)
1043 (interactive)
1044 (if (zerop (+ (length targets) (length macros)))
1045 (progn
1046 (beep)
1047 (message "No macros or targets to browse! Consider running 'makefile-pickup-everything\'"))
1048 (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name)))
1049 (pop-to-buffer browser-buffer)
1050 (make-variable-buffer-local 'makefile-browser-selection-vector)
1051 (makefile-browser-fill targets macros)
9e9bf716 1052 (shrink-window-if-larger-than-buffer)
72c0ae01
ER
1053 (setq makefile-browser-selection-vector
1054 (make-vector (+ (length targets) (length macros)) nil))
1055 (makefile-browser-start-interaction))))
72c0ae01
ER
1056
1057(defun makefile-switch-to-browser ()
1058 (interactive)
1059 (run-hooks 'makefile-browser-hook)
1060 (setq makefile-browser-client (current-buffer))
9e9bf716
ER
1061 (makefile-pickup-targets)
1062 (makefile-pickup-macros)
72c0ae01
ER
1063 (makefile-browse makefile-target-table makefile-macro-table))
1064
6783b1ce 1065\f
72c0ae01
ER
1066
1067;;; ------------------------------------------------------------
1068;;; Up-to-date overview buffer
1069;;; ------------------------------------------------------------
1070
1071(defun makefile-create-up-to-date-overview ()
9e9bf716 1072 "Create a buffer containing an overview of the state of all known targets.
72c0ae01
ER
1073Known targets are targets that are explicitly defined in that makefile;
1074in other words, all targets that appear on the left hand side of a
1075dependency in the makefile."
1076 (interactive)
1077 (if (y-or-n-p "Are you sure that the makefile being edited is consistent? ")
1078 ;;
1079 ;; The rest of this function operates on a temporary makefile, created by
1080 ;; writing the current contents of the makefile buffer.
1081 ;;
1082 (let ((saved-target-table makefile-target-table)
1083 (this-buffer (current-buffer))
1084 (makefile-up-to-date-buffer
1085 (get-buffer-create makefile-up-to-date-buffer-name))
1086 (filename (makefile-save-temporary))
1087 ;;
1088 ;; Forget the target table because it may contain picked-up filenames
1089 ;; that are not really targets in the current makefile.
1090 ;; We don't want to query these, so get a new target-table with just the
1091 ;; targets that can be found in the makefile buffer.
1092 ;; The 'old' target table will be restored later.
1093 ;;
1094 (real-targets (progn
72c0ae01 1095 (makefile-pickup-targets)
9e9bf716
ER
1096 makefile-target-table))
1097 (prereqs makefile-has-prereqs)
1098 )
72c0ae01
ER
1099
1100 (set-buffer makefile-up-to-date-buffer)
1101 (setq buffer-read-only nil)
1102 (erase-buffer)
9e9bf716 1103 (makefile-query-targets filename real-targets prereqs)
72c0ae01
ER
1104 (if (zerop (buffer-size)) ; if it did not get us anything
1105 (progn
1106 (kill-buffer (current-buffer))
1107 (message "No overview created!")))
1108 (set-buffer this-buffer)
1109 (setq makefile-target-table saved-target-table)
1110 (if (get-buffer makefile-up-to-date-buffer-name)
1111 (progn
1112 (pop-to-buffer (get-buffer makefile-up-to-date-buffer-name))
9e9bf716 1113 (shrink-window-if-larger-than-buffer)
72c0ae01
ER
1114 (sort-lines nil (point-min) (point-max))
1115 (setq buffer-read-only t))))))
72c0ae01
ER
1116
1117(defun makefile-save-temporary ()
1118 "Create a temporary file from the current makefile buffer."
1119 (let ((filename (makefile-generate-temporary-filename)))
1120 (write-region (point-min) (point-max) filename nil 0)
1121 filename)) ; return the filename
1122
1123(defun makefile-generate-temporary-filename ()
308a2860 1124 "Create a filename suitable for use in `makefile-save-temporary'.
72c0ae01 1125Be careful to allow brain-dead file systems (DOS, SYSV ...) to cope
308a2860 1126with the generated name!"
72c0ae01
ER
1127 (let ((my-name (user-login-name))
1128 (my-uid (int-to-string (user-uid))))
1129 (concat "mktmp"
1130 (if (> (length my-name) 3)
1131 (substring my-name 0 3)
1132 my-name)
1133 "."
1134 (if (> (length my-uid) 3)
1135 (substring my-uid 0 3)
1136 my-uid))))
1137
9e9bf716 1138(defun makefile-query-targets (filename target-table prereq-list)
308a2860
RS
1139 "Fill the up-to-date-overview-buffer.
1140Checks each target in TARGET-TABLE using `makefile-query-one-target-method'
72c0ae01
ER
1141and generates the overview, one line per target name."
1142 (insert
9e9bf716
ER
1143 (mapconcat
1144 (function (lambda (item)
1145 (let* ((target-name (car item))
1146 (no-prereqs (not (member target-name prereq-list)))
1147 (needs-rebuild (or no-prereqs
1148 (funcall
1149 makefile-query-one-target-method
1150 target-name
1151 filename))))
1152 (format "\t%s%s"
1153 target-name
1154 (cond (no-prereqs " .. has no prerequisites")
1155 (needs-rebuild " .. NEEDS REBUILD")
1156 (t " .. is up to date"))))
1157 ))
1158 target-table "\n"))
72c0ae01
ER
1159 (goto-char (point-min))
1160 (delete-file filename)) ; remove the tmpfile
1161
1162(defun makefile-query-by-make-minus-q (target &optional filename)
308a2860
RS
1163 (not (zerop
1164 (call-process makefile-brave-make nil nil nil
1165 "-f" filename "-q" target))))
72c0ae01 1166
6783b1ce
RS
1167\f
1168
72c0ae01
ER
1169;;; ------------------------------------------------------------
1170;;; Continuation cleanup
1171;;; ------------------------------------------------------------
1172
1173(defun makefile-cleanup-continuations ()
1174 (if (eq major-mode 'makefile-mode)
1175 (if (and makefile-cleanup-continuations-p
1176 (not buffer-read-only))
1177 (save-excursion
1178 (goto-char (point-min))
1179 (while (re-search-forward "\\\\[ \t]+$" (point-max) t)
1180 (replace-match "\\" t t))))))
1181
b8ca7cc3
RS
1182
1183;;; ------------------------------------------------------------
1184;;; Warn of suspicious lines
1185;;; ------------------------------------------------------------
1186
1187(defun makefile-warn-suspicious-lines ()
1188 (let ((dont-save nil))
1189 (if (eq major-mode 'makefile-mode)
1190 (let ((suspicious
1191 (save-excursion
1192 (goto-char (point-min))
1193 (re-search-forward
1194 "\\(^[\t]+$\\)\\|\\(^[ ]+[\t]\\)" (point-max) t))))
1195 (if suspicious
1196 (let ((line-nr (count-lines (point-min) suspicious)))
1197 (setq dont-save
1198 (not (y-or-n-p
1199 (format "Suspicious line %d. Save anyway "
1200 line-nr))))))))
1201 dont-save))
1202
6783b1ce 1203\f
b8ca7cc3 1204
72c0ae01
ER
1205;;; ------------------------------------------------------------
1206;;; GNU make function support
1207;;; ------------------------------------------------------------
1208
1209(defun makefile-insert-gmake-function ()
308a2860
RS
1210 "Insert a GNU make function call.
1211Asks for the name of the function to use (with completion).
1212Then prompts for all required parameters."
72c0ae01
ER
1213 (interactive)
1214 (let* ((gm-function-name (completing-read
1215 "Function: "
1216 makefile-gnumake-functions-alist
1217 nil t nil))
1218 (gm-function-prompts
1219 (cdr (assoc gm-function-name makefile-gnumake-functions-alist))))
1220 (if (not (zerop (length gm-function-name)))
1221 (insert (makefile-format-macro-ref
1222 (concat gm-function-name " "
1223 (makefile-prompt-for-gmake-funargs
1224 gm-function-name gm-function-prompts)))
1225 " "))))
1226
1227(defun makefile-prompt-for-gmake-funargs (function-name prompt-list)
1228 (mapconcat
1229 (function (lambda (one-prompt)
308a2860
RS
1230 (read-string (format "[%s] %s: " function-name one-prompt)
1231 nil)))
72c0ae01
ER
1232 prompt-list
1233 ","))
308a2860 1234
6783b1ce 1235\f
72c0ae01
ER
1236
1237;;; ------------------------------------------------------------
1238;;; Utility functions
1239;;; ------------------------------------------------------------
1240
6783b1ce
RS
1241(defun makefile-do-macro-insertion (macro-name)
1242 "Insert a macro reference."
1243 (if (not (zerop (length macro-name)))
1244 (if (assoc macro-name makefile-runtime-macros-list)
1245 (insert "$" macro-name)
1246 (insert (makefile-format-macro-ref macro-name)))))
1247
9e9bf716 1248(defun makefile-remember-target (target-name &optional has-prereqs)
72c0ae01
ER
1249 "Remember a given target if it is not already remembered for this buffer."
1250 (if (not (zerop (length target-name)))
9e9bf716 1251 (progn
72c0ae01
ER
1252 (if (not (assoc target-name makefile-target-table))
1253 (setq makefile-target-table
9e9bf716
ER
1254 (cons (list target-name) makefile-target-table)))
1255 (if has-prereqs
1256 (setq makefile-has-prereqs
1257 (cons target-name makefile-has-prereqs))))))
72c0ae01
ER
1258
1259(defun makefile-remember-macro (macro-name)
1260 "Remember a given macro if it is not already remembered for this buffer."
1261 (if (not (zerop (length macro-name)))
1262 (if (not (assoc macro-name makefile-macro-table))
1263 (setq makefile-macro-table
1264 (cons (list macro-name) makefile-macro-table)))))
1265
1266(defun makefile-forward-after-target-colon ()
308a2860
RS
1267 "Move point forward after inserting the terminating colon of a target.
1268This acts according to the value of `makefile-tab-after-target-colon'."
72c0ae01
ER
1269 (if makefile-tab-after-target-colon
1270 (insert "\t")
1271 (insert " ")))
1272
1273(defun makefile-browser-on-macro-line-p ()
1274 "Determine if point is on a macro line in the browser."
1275 (save-excursion
1276 (beginning-of-line)
1277 (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t)))
1278
1279(defun makefile-browser-this-line-target-name ()
1280 "Extract the target name from a line in the browser."
1281 (save-excursion
1282 (end-of-line)
1283 (skip-chars-backward "^ \t")
1284 (buffer-substring (point) (1- (makefile-end-of-line-point)))))
1285
1286(defun makefile-browser-this-line-macro-name ()
1287 "Extract the macro name from a line in the browser."
1288 (save-excursion
1289 (beginning-of-line)
1290 (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t)
1291 (let ((macro-start (point)))
1292 (skip-chars-forward "^})")
1293 (buffer-substring macro-start (point)))))
1294
1295(defun makefile-format-macro-ref (macro-name)
308a2860
RS
1296 "Format a macro reference.
1297Uses `makefile-use-curly-braces-for-macros-p'."
b8ca7cc3
RS
1298 (if (or (char-equal ?\( (string-to-char macro-name))
1299 (char-equal ?\{ (string-to-char macro-name)))
1300 (format "$%s" macro-name)
1301 (if makefile-use-curly-braces-for-macros-p
1302 (format "${%s}" macro-name)
1303 (format "$(%s)" macro-name))))
72c0ae01
ER
1304
1305(defun makefile-browser-get-state-for-line (n)
1306 (aref makefile-browser-selection-vector (1- n)))
1307
1308(defun makefile-browser-set-state-for-line (n to-state)
1309 (aset makefile-browser-selection-vector (1- n) to-state))
1310
1311(defun makefile-browser-toggle-state-for-line (n)
1312 (makefile-browser-set-state-for-line n (not (makefile-browser-get-state-for-line n))))
1313
1314(defun makefile-beginning-of-line-point ()
1315 (save-excursion
1316 (beginning-of-line)
1317 (point)))
1318
1319(defun makefile-end-of-line-point ()
1320 (save-excursion
1321 (end-of-line)
1322 (point)))
1323
1324(defun makefile-last-line-p ()
1325 (= (makefile-end-of-line-point) (point-max)))
1326
1327(defun makefile-first-line-p ()
1328 (= (makefile-beginning-of-line-point) (point-min)))
1329
6783b1ce
RS
1330\f
1331
1332;;; Support for other packages, like add-log and imenu.
1333
1334(defun makefile-add-log-defun ()
308a2860 1335 ;; "Return name of target or macro point is in, or nil."
6783b1ce
RS
1336 (save-excursion
1337 (beginning-of-line)
1338 (cond
1339 ((looking-at makefile-macroassign-regex)
1340 (buffer-substring (match-beginning 1)
1341 (match-end 1)))
1342 ((progn
1343 (forward-char)
1344 (re-search-backward makefile-dependency-regex nil t))
1345 (buffer-substring (match-beginning 1)
1346 (match-end 1)))
1347 (t nil))))
1348
1349;; FIXME it might be nice to have them separated by macro vs target.
1350(defun makefile-menu-index-function ()
308a2860 1351 ;; "Generate alist of indices for imenu."
6783b1ce
RS
1352 (let (alist
1353 stupid
1354 (re (concat makefile-dependency-regex
1355 "\\|"
1356 makefile-macroassign-regex)))
1357 (imenu-progress-message stupid 0)
1358 (goto-char (point-min))
1359 (while (re-search-forward re nil t)
1360 (imenu-progress-message stupid)
6783b1ce
RS
1361 (let ((n (if (match-beginning 1) 1 5)))
1362 (setq alist (cons
1363 (cons (buffer-substring (match-beginning n)
1364 (match-end n))
1365 (match-beginning n))
1366 alist))))
1367 (imenu-progress-message stupid 100)
1368 (nreverse alist)))
1369
1370;;; makefile.el ends here