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