Commit | Line | Data |
---|---|---|
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 | 14 | |
72c0ae01 ER |
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 | |
7c938215 | 19 | ;; the Free Software Foundation; either version 2, or (at your option) |
72c0ae01 ER |
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 | ||
e41b2db1 ER |
31 | ;;; Commentary: |
32 | ||
9e9bf716 ER |
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 | ;; | |
6783b1ce | 43 | ;; The command C-c C-f adds certain filenames in the current directory |
9e9bf716 ER |
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 | ;; | |
6783b1ce | 52 | ;; The command C-c C-b pops up a browser window listing all target and |
9e9bf716 ER |
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. | |
e41b2db1 | 60 | |
6783b1ce RS |
61 | ;; |
62 | ;; To Do: | |
63 | ;; | |
308a2860 RS |
64 | ;; * makefile-backslash-region should be given better behavior. |
65 | ;; * Consider binding C-c C-c to comment-region (like cc-mode). | |
6783b1ce RS |
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). | |
308a2860 | 75 | ;; * Make browser into a major mode. |
6783b1ce RS |
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 | ||
72c0ae01 ER |
89 | ;;; Code: |
90 | ||
91 | (provide 'makefile) | |
92 | ||
6783b1ce RS |
93 | ;; Sadly we need this for a macro. |
94 | (eval-when-compile | |
95 | (require 'imenu)) | |
96 | ||
72c0ae01 | 97 | ;;; ------------------------------------------------------------ |
eb8c3be9 | 98 | ;;; Configurable stuff |
72c0ae01 ER |
99 | ;;; ------------------------------------------------------------ |
100 | ||
72c0ae01 ER |
101 | (defvar makefile-browser-buffer-name "*Macros and Targets*" |
102 | "Name of the macro- and target browser buffer.") | |
103 | ||
104 | (defvar makefile-target-colon ":" | |
308a2860 RS |
105 | "String to append to all target names inserted by `makefile-insert-target'. |
106 | \":\" or \"::\" are common values.") | |
72c0ae01 ER |
107 | |
108 | (defvar makefile-macro-assign " = " | |
308a2860 | 109 | "String to append to all macro names inserted by `makefile-insert-macro'. |
72c0ae01 ER |
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 | ||
6783b1ce RS |
115 | (defvar makefile-electric-keys nil |
116 | "If non-nil, install electric keybindings. | |
117 | Default is nil.") | |
118 | ||
72c0ae01 | 119 | (defvar makefile-use-curly-braces-for-macros-p nil |
9e9bf716 | 120 | "Controls the style of generated macro references. |
308a2860 RS |
121 | t (actually non-nil) means macro references should use curly braces, |
122 | like `${this}'. | |
123 | nil means use parentheses, like `$(this)'.") | |
72c0ae01 ER |
124 | |
125 | (defvar makefile-tab-after-target-colon t | |
308a2860 RS |
126 | "If non-nil, insert a TAB after a target colon. |
127 | Otherwise, a space is inserted. | |
128 | The default is t.") | |
72c0ae01 ER |
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 | ||
308a2860 RS |
137 | (defvar makefile-backslash-column 48 |
138 | "*Column in which `makefile-backslash-region' inserts backslashes.") | |
139 | ||
72c0ae01 ER |
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 | |
308a2860 | 147 | "If non-nil, cursor will move after item is selected in browser.") |
72c0ae01 ER |
148 | |
149 | (defvar makefile-pickup-everything-picks-up-filenames-p nil | |
308a2860 RS |
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.") | |
72c0ae01 ER |
153 | |
154 | (defvar makefile-cleanup-continuations-p t | |
308a2860 RS |
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 | |
72c0ae01 ER |
159 | to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'.") |
160 | ||
308a2860 | 161 | (defvar makefile-browser-hook '()) |
72c0ae01 ER |
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")) | |
308a2860 RS |
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.") | |
72c0ae01 ER |
178 | |
179 | (defvar makefile-runtime-macros-list | |
6783b1ce | 180 | '(("@") ("&") (">") ("<") ("*") ("^") ("?") ("%") ("$")) |
72c0ae01 ER |
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 | ||
6783b1ce RS |
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. | |
72c0ae01 | 189 | (defconst makefile-dependency-regex |
6783b1ce | 190 | "^\\([^ \n\t#:]+\\([ \t]+[^ \t\n#:]+\\)*\\)[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)" |
72c0ae01 ER |
191 | "Regex used to find dependency lines in a makefile.") |
192 | ||
6783b1ce RS |
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. | |
72c0ae01 | 196 | (defconst makefile-macroassign-regex |
308a2860 | 197 | "^\\([^ \n\t][^:#= \t\n]*\\)[ \t]*[*:+]?:?=" |
72c0ae01 ER |
198 | "Regex used to find macro assignment lines in a makefile.") |
199 | ||
200 | (defconst makefile-ignored-files-in-pickup-regex | |
0c5b5a13 | 201 | "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)" |
72c0ae01 ER |
202 | "Regex for filenames that will NOT be included in the target list.") |
203 | ||
118a9857 RS |
204 | (defvar makefile-space-face 'makefile-space-face |
205 | "Face to use for highlighting leading spaces in Font-Lock mode.") | |
308a2860 | 206 | |
6783b1ce RS |
207 | (defconst makefile-font-lock-keywords |
208 | (list | |
af4b1991 | 209 | ;; Do macro assignments. These get the "variable-name" face rather |
6783b1ce | 210 | ;; arbitrarily. |
af4b1991 SM |
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. | |
308a2860 RS |
217 | (list makefile-dependency-regex 1 'font-lock-function-name-face) |
218 | ||
bd0e4eb1 RS |
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. | |
118a9857 RS |
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))) | |
6783b1ce | 228 | |
72c0ae01 ER |
229 | ;;; ------------------------------------------------------------ |
230 | ;;; The following configurable variables are used in the | |
231 | ;;; up-to-date overview . | |
eb8c3be9 | 232 | ;;; The standard configuration assumes that your `make' program |
72c0ae01 ER |
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 | |
9e9bf716 ER |
241 | ;;; it. Try it with your favourite one. GNU make, System V make, and |
242 | ;;; Dennis Vadura's DMake have no problems. | |
72c0ae01 ER |
243 | ;;; Set the variable `makefile-brave-make' to the name of the |
244 | ;;; make utility that does this on your system. | |
eb8c3be9 | 245 | ;;; To understand what this is all about see the function definition |
72c0ae01 ER |
246 | ;;; of `makefile-query-by-make-minus-q' . |
247 | ;;; ------------------------------------------------------------ | |
248 | ||
9e9bf716 | 249 | (defvar makefile-brave-make "make" |
bd0e4eb1 | 250 | "A make that can handle the `-q' option.") |
72c0ae01 ER |
251 | |
252 | (defvar makefile-query-one-target-method 'makefile-query-by-make-minus-q | |
bd0e4eb1 RS |
253 | "Function to call to determine whether a make target is up to date. |
254 | The function must satisfy this calling convention: | |
72c0ae01 ER |
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 | |
9e9bf716 | 260 | as a string. Depending on what you're going to do you may |
72c0ae01 ER |
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 | ||
72c0ae01 ER |
270 | ;;; --- end of up-to-date-overview configuration ------------------ |
271 | ||
72c0ae01 | 272 | (defvar makefile-mode-map nil |
bd0e4eb1 RS |
273 | "The keymap that is used in Makefile mode.") |
274 | ||
72c0ae01 ER |
275 | (if makefile-mode-map |
276 | () | |
277 | (setq makefile-mode-map (make-sparse-keymap)) | |
278 | ;; set up the keymap | |
6783b1ce RS |
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))) | |
72c0ae01 | 286 | (define-key makefile-mode-map "\C-c\C-f" 'makefile-pickup-filenames-as-targets) |
72c0ae01 ER |
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) | |
308a2860 | 291 | (define-key makefile-mode-map "\C-c\C-\\" 'makefile-backslash-region) |
72c0ae01 | 292 | (define-key makefile-mode-map "\M-p" 'makefile-previous-dependency) |
6783b1ce RS |
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] | |
0e520d74 | 301 | '("Pop up Makefile Browser" . makefile-switch-to-browser)) |
6783b1ce | 302 | (define-key makefile-mode-map [menu-bar makefile-mode complete] |
0e520d74 | 303 | '("Complete Target or Macro" . makefile-complete)) |
6783b1ce | 304 | (define-key makefile-mode-map [menu-bar makefile-mode pickup] |
0e520d74 | 305 | '("Find Targets and Macros" . makefile-pickup-everything)) |
6783b1ce RS |
306 | |
307 | (define-key makefile-mode-map [menu-bar makefile-mode prev] | |
0e520d74 | 308 | '("Move to Previous Dependency" . makefile-previous-dependency)) |
6783b1ce | 309 | (define-key makefile-mode-map [menu-bar makefile-mode next] |
0e520d74 | 310 | '("Move to Next Dependency" . makefile-next-dependency))) |
72c0ae01 ER |
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 | ||
308a2860 | 331 | (defvar makefile-mode-syntax-table nil) |
72c0ae01 ER |
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) | |
af4b1991 SM |
341 | (modify-syntax-entry ?\' "\" " makefile-mode-syntax-table) |
342 | (modify-syntax-entry ?\` "\" " makefile-mode-syntax-table) | |
72c0ae01 ER |
343 | (modify-syntax-entry ?# "< " makefile-mode-syntax-table) |
344 | (modify-syntax-entry ?\n "> " makefile-mode-syntax-table)) | |
6783b1ce RS |
345 | |
346 | ||
72c0ae01 ER |
347 | ;;; ------------------------------------------------------------ |
348 | ;;; Internal variables. | |
349 | ;;; You don't need to configure below this line. | |
350 | ;;; ------------------------------------------------------------ | |
351 | ||
352 | (defvar makefile-target-table nil | |
308a2860 | 353 | "Table of all target names known for this buffer.") |
72c0ae01 ER |
354 | |
355 | (defvar makefile-macro-table nil | |
308a2860 | 356 | "Table of all macro names known for this buffer.") |
72c0ae01 ER |
357 | |
358 | (defvar makefile-browser-client | |
bd0e4eb1 | 359 | "A buffer in Makefile mode that is currently using the browser.") |
72c0ae01 ER |
360 | |
361 | (defvar makefile-browser-selection-vector nil) | |
9e9bf716 ER |
362 | (defvar makefile-has-prereqs nil) |
363 | (defvar makefile-need-target-pickup t) | |
364 | (defvar makefile-need-macro-pickup t) | |
72c0ae01 ER |
365 | |
366 | (defvar makefile-mode-hook '()) | |
367 | ||
308a2860 RS |
368 | ;; Each element looks like '("GNU MAKE FUNCTION" "ARG" "ARG" ... ) |
369 | ;; Each "ARG" is used as a prompt for a required argument. | |
72c0ae01 | 370 | (defconst makefile-gnumake-functions-alist |
72c0ae01 ER |
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") | |
308a2860 | 394 | ("shell" "Command"))) |
72c0ae01 ER |
395 | |
396 | ||
397 | ;;; ------------------------------------------------------------ | |
398 | ;;; The mode function itself. | |
399 | ;;; ------------------------------------------------------------ | |
400 | ||
5c2946c7 | 401 | ;;;###autoload |
72c0ae01 ER |
402 | (defun makefile-mode () |
403 | "Major mode for editing Makefiles. | |
bd0e4eb1 | 404 | This function ends by invoking the function(s) `makefile-mode-hook'. |
72c0ae01 ER |
405 | |
406 | \\{makefile-mode-map} | |
407 | ||
408 | In the browser, use the following keys: | |
409 | ||
410 | \\{makefile-browser-map} | |
411 | ||
bd0e4eb1 | 412 | Makefile mode can be configured by modifying the following variables: |
72c0ae01 | 413 | |
72c0ae01 ER |
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 | |
bd0e4eb1 | 419 | inserted by `makefile-insert-target'. |
72c0ae01 ER |
420 | \":\" or \"::\" are quite common values. |
421 | ||
422 | makefile-macro-assign: | |
423 | The string that gets appended to all macro names | |
bd0e4eb1 | 424 | inserted by `makefile-insert-macro'. |
72c0ae01 ER |
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 | ||
72c0ae01 ER |
452 | makefile-pickup-everything-picks-up-filenames-p: |
453 | If this variable is set to a non-nil value then | |
bd0e4eb1 RS |
454 | `makefile-pickup-everything' also picks up filenames as targets |
455 | (i.e. it calls `makefile-find-filenames-as-targets'), otherwise | |
72c0ae01 ER |
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 | |
bd0e4eb1 | 465 | to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\". |
72c0ae01 ER |
466 | |
467 | makefile-browser-hook: | |
468 | A function or list of functions to be called just before the | |
9e9bf716 | 469 | browser is entered. This is executed in the makefile buffer. |
72c0ae01 ER |
470 | |
471 | makefile-special-targets-list: | |
472 | List of special targets. You will be offered to complete | |
bd0e4eb1 RS |
473 | on one of those in the minibuffer whenever you enter a `.'. |
474 | at the beginning of a line in Makefile mode." | |
6783b1ce | 475 | |
72c0ae01 ER |
476 | (interactive) |
477 | (kill-all-local-variables) | |
9854c615 | 478 | (make-local-variable 'local-write-file-hooks) |
b8ca7cc3 | 479 | (setq local-write-file-hooks |
cd99f76d | 480 | '(makefile-cleanup-continuations makefile-warn-suspicious-lines)) |
b8ca7cc3 RS |
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) | |
6783b1ce RS |
486 | |
487 | ;; Font lock. | |
118a9857 | 488 | (makefile-define-space-face) |
af4b1991 SM |
489 | (make-local-variable 'font-lock-defaults) |
490 | (setq font-lock-defaults '(makefile-font-lock-keywords)) | |
6783b1ce RS |
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 | ||
3b114205 RS |
500 | ;; Dabbrev. |
501 | (make-local-variable 'dabbrev-abbrev-skip-leading-regexp) | |
502 | (setq dabbrev-abbrev-skip-leading-regexp "\\$") | |
503 | ||
6783b1ce | 504 | ;; Comment stuff. |
531b2a28 | 505 | (make-local-variable 'comment-start) |
72c0ae01 | 506 | (setq comment-start "#") |
6783b1ce | 507 | (make-local-variable 'comment-end) |
72c0ae01 | 508 | (setq comment-end "") |
6783b1ce RS |
509 | (make-local-variable 'comment-start-skip) |
510 | (setq comment-start-skip "#+[ \t]*") | |
511 | ||
72c0ae01 ER |
512 | ;; become the current major mode |
513 | (setq major-mode 'makefile-mode) | |
6783b1ce RS |
514 | (setq mode-name "Makefile") |
515 | ||
516 | ;; Activate keymap and syntax table. | |
72c0ae01 ER |
517 | (use-local-map makefile-mode-map) |
518 | (set-syntax-table makefile-mode-syntax-table) | |
6783b1ce RS |
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. | |
72c0ae01 | 527 | |
72c0ae01 | 528 | (defun makefile-next-dependency () |
bd0e4eb1 | 529 | "Move point to the beginning of the next dependency line." |
72c0ae01 ER |
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))) | |
6783b1ce | 536 | |
72c0ae01 | 537 | (defun makefile-previous-dependency () |
bd0e4eb1 | 538 | "Move point to the beginning of the previous dependency line." |
72c0ae01 ER |
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 | ||
6783b1ce | 546 | \f |
72c0ae01 | 547 | |
6783b1ce | 548 | ;;; Electric keys. Blech. |
9e9bf716 | 549 | |
6783b1ce RS |
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") | |
72c0ae01 ER |
555 | (if (bolp) |
556 | (makefile-insert-special-target) | |
6783b1ce | 557 | (self-insert-command arg))) |
72c0ae01 | 558 | |
72c0ae01 | 559 | (defun makefile-insert-special-target () |
6783b1ce RS |
560 | "Propmt for and insert a special target name. |
561 | Uses `makefile-special-targets' list." | |
72c0ae01 | 562 | (interactive) |
9e9bf716 | 563 | (makefile-pickup-targets) |
6783b1ce RS |
564 | (let ((special-target |
565 | (completing-read "Special target: " | |
566 | makefile-special-targets-list nil nil nil))) | |
72c0ae01 ER |
567 | (if (zerop (length special-target)) |
568 | () | |
6783b1ce | 569 | (insert "." special-target ":") |
72c0ae01 ER |
570 | (makefile-forward-after-target-colon)))) |
571 | ||
6783b1ce RS |
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") | |
9e9bf716 | 577 | (makefile-pickup-macros) |
72c0ae01 ER |
578 | (if (bolp) |
579 | (call-interactively 'makefile-insert-macro) | |
6783b1ce | 580 | (self-insert-command arg))) |
72c0ae01 ER |
581 | |
582 | (defun makefile-insert-macro (macro-name) | |
583 | "Prepare definition of a new macro." | |
584 | (interactive "sMacro Name: ") | |
9e9bf716 | 585 | (makefile-pickup-macros) |
72c0ae01 ER |
586 | (if (not (zerop (length macro-name))) |
587 | (progn | |
588 | (beginning-of-line) | |
6783b1ce | 589 | (insert macro-name makefile-macro-assign) |
9e9bf716 | 590 | (setq makefile-need-macro-pickup t) |
72c0ae01 ER |
591 | (makefile-remember-macro macro-name)))) |
592 | ||
72c0ae01 | 593 | (defun makefile-insert-macro-ref (macro-name) |
bd0e4eb1 | 594 | "Complete on a list of known macros, then insert complete ref at point." |
72c0ae01 ER |
595 | (interactive |
596 | (list | |
9e9bf716 ER |
597 | (progn |
598 | (makefile-pickup-macros) | |
599 | (completing-read "Refer to macro: " makefile-macro-table nil nil nil)))) | |
6783b1ce | 600 | (makefile-do-macro-insertion macro-name)) |
72c0ae01 | 601 | |
72c0ae01 ER |
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) | |
6783b1ce | 608 | (insert target-name makefile-target-colon) |
72c0ae01 ER |
609 | (makefile-forward-after-target-colon) |
610 | (end-of-line) | |
9e9bf716 | 611 | (setq makefile-need-target-pickup t) |
72c0ae01 ER |
612 | (makefile-remember-target target-name)))) |
613 | ||
72c0ae01 | 614 | (defun makefile-insert-target-ref (target-name) |
bd0e4eb1 | 615 | "Complete on a list of known targets, then insert target-ref at point." |
72c0ae01 ER |
616 | (interactive |
617 | (list | |
0c5b5a13 | 618 | (progn |
9e9bf716 ER |
619 | (makefile-pickup-targets) |
620 | (completing-read "Refer to target: " makefile-target-table nil nil nil)))) | |
72c0ae01 | 621 | (if (not (zerop (length target-name))) |
6783b1ce | 622 | (insert target-name " "))) |
72c0ae01 | 623 | |
6783b1ce RS |
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") | |
72c0ae01 ER |
629 | (if (bolp) |
630 | (call-interactively 'makefile-insert-target) | |
6783b1ce RS |
631 | (self-insert-command arg))) |
632 | ||
633 | \f | |
72c0ae01 | 634 | |
72c0ae01 ER |
635 | ;;; ------------------------------------------------------------ |
636 | ;;; Extracting targets and macros from an existing makefile | |
637 | ;;; ------------------------------------------------------------ | |
638 | ||
639 | (defun makefile-pickup-targets () | |
308a2860 | 640 | "Notice names of all target definitions in Makefile." |
72c0ae01 | 641 | (interactive) |
9e9bf716 ER |
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."))) | |
72c0ae01 ER |
652 | |
653 | (defun makefile-add-this-line-targets () | |
654 | (save-excursion | |
655 | (beginning-of-line) | |
9e9bf716 ER |
656 | (let ((done-with-line nil) |
657 | (line-number (1+ (count-lines (point-min) (point))))) | |
72c0ae01 ER |
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:#") | |
9e9bf716 ER |
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))))))))) | |
72c0ae01 | 673 | |
72c0ae01 | 674 | (defun makefile-pickup-macros () |
308a2860 | 675 | "Notice names of all macro definitions in Makefile." |
72c0ae01 | 676 | (interactive) |
9e9bf716 ER |
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."))) | |
72c0ae01 ER |
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)) | |
9e9bf716 | 694 | (line-number (1+ (count-lines (point-min) (point)))) |
72c0ae01 ER |
695 | (macro-name (progn |
696 | (skip-chars-forward "^ \t:#=*") | |
697 | (buffer-substring start-of-macro-name (point))))) | |
698 | (if (makefile-remember-macro macro-name) | |
9e9bf716 ER |
699 | (message "Picked up macro \"%s\" from line %d" |
700 | macro-name line-number)))))) | |
72c0ae01 | 701 | |
6783b1ce | 702 | (defun makefile-pickup-everything (arg) |
308a2860 | 703 | "Notice names of all macros and targets in Makefile. |
6783b1ce RS |
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))) | |
72c0ae01 ER |
710 | (makefile-pickup-macros) |
711 | (makefile-pickup-targets) | |
712 | (if makefile-pickup-everything-picks-up-filenames-p | |
713 | (makefile-pickup-filenames-as-targets))) | |
714 | ||
72c0ae01 | 715 | (defun makefile-pickup-filenames-as-targets () |
308a2860 RS |
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." | |
72c0ae01 ER |
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 | ||
6783b1ce RS |
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 | ||
308a2860 RS |
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 | ||
72c0ae01 | 879 | ;;; ------------------------------------------------------------ |
6783b1ce | 880 | ;;; Browser mode. |
72c0ae01 ER |
881 | ;;; ------------------------------------------------------------ |
882 | ||
72c0ae01 ER |
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) | |
c72344c7 RS |
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))) | |
72c0ae01 ER |
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 () | |
308a2860 | 945 | "Leave the browser and return to the makefile buffer." |
72c0ae01 ER |
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) | |
c72344c7 RS |
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))) | |
72c0ae01 ER |
974 | (kill-line) |
975 | (insert | |
c72344c7 RS |
976 | (makefile-browser-format-target-line |
977 | target-name | |
978 | (makefile-browser-get-state-for-line this-line)))))) | |
72c0ae01 ER |
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 () | |
9e9bf716 | 989 | "Insert a makefile continuation. |
308a2860 | 990 | In the makefile buffer, go to (end-of-line), insert a \'\\\' |
72c0ae01 | 991 | character, insert a new blank line, go to that line and indent by one TAB. |
9e9bf716 ER |
992 | This is most useful in the process of creating continued lines when copying |
993 | large dependencies from the browser to the client buffer. | |
a4e104bf | 994 | \(point) advances accordingly in the client buffer." |
72c0ae01 ER |
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 () | |
308a2860 | 1002 | "Insert all selected targets and/or macros in the makefile buffer. |
bd0e4eb1 | 1003 | Insertion takes place at point." |
72c0ae01 ER |
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 | ||
72c0ae01 ER |
1030 | (defun makefile-browser-start-interaction () |
1031 | (use-local-map makefile-browser-map) | |
1032 | (setq buffer-read-only t)) | |
1033 | ||
72c0ae01 ER |
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) | |
9e9bf716 | 1044 | (shrink-window-if-larger-than-buffer) |
72c0ae01 ER |
1045 | (setq makefile-browser-selection-vector |
1046 | (make-vector (+ (length targets) (length macros)) nil)) | |
1047 | (makefile-browser-start-interaction)))) | |
72c0ae01 ER |
1048 | |
1049 | (defun makefile-switch-to-browser () | |
1050 | (interactive) | |
1051 | (run-hooks 'makefile-browser-hook) | |
1052 | (setq makefile-browser-client (current-buffer)) | |
9e9bf716 ER |
1053 | (makefile-pickup-targets) |
1054 | (makefile-pickup-macros) | |
72c0ae01 ER |
1055 | (makefile-browse makefile-target-table makefile-macro-table)) |
1056 | ||
6783b1ce | 1057 | \f |
72c0ae01 ER |
1058 | |
1059 | ;;; ------------------------------------------------------------ | |
1060 | ;;; Up-to-date overview buffer | |
1061 | ;;; ------------------------------------------------------------ | |
1062 | ||
1063 | (defun makefile-create-up-to-date-overview () | |
9e9bf716 | 1064 | "Create a buffer containing an overview of the state of all known targets. |
72c0ae01 ER |
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 | |
72c0ae01 | 1087 | (makefile-pickup-targets) |
9e9bf716 ER |
1088 | makefile-target-table)) |
1089 | (prereqs makefile-has-prereqs) | |
1090 | ) | |
72c0ae01 ER |
1091 | |
1092 | (set-buffer makefile-up-to-date-buffer) | |
1093 | (setq buffer-read-only nil) | |
1094 | (erase-buffer) | |
9e9bf716 | 1095 | (makefile-query-targets filename real-targets prereqs) |
72c0ae01 ER |
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)) | |
9e9bf716 | 1105 | (shrink-window-if-larger-than-buffer) |
72c0ae01 ER |
1106 | (sort-lines nil (point-min) (point-max)) |
1107 | (setq buffer-read-only t)))))) | |
72c0ae01 ER |
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 () | |
308a2860 | 1116 | "Create a filename suitable for use in `makefile-save-temporary'. |
72c0ae01 | 1117 | Be careful to allow brain-dead file systems (DOS, SYSV ...) to cope |
308a2860 | 1118 | with the generated name!" |
72c0ae01 ER |
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 | ||
9e9bf716 | 1130 | (defun makefile-query-targets (filename target-table prereq-list) |
bd0e4eb1 | 1131 | "Fill the up-to-date overview buffer. |
308a2860 | 1132 | Checks each target in TARGET-TABLE using `makefile-query-one-target-method' |
72c0ae01 ER |
1133 | and generates the overview, one line per target name." |
1134 | (insert | |
9e9bf716 ER |
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")) | |
72c0ae01 ER |
1151 | (goto-char (point-min)) |
1152 | (delete-file filename)) ; remove the tmpfile | |
1153 | ||
1154 | (defun makefile-query-by-make-minus-q (target &optional filename) | |
308a2860 RS |
1155 | (not (zerop |
1156 | (call-process makefile-brave-make nil nil nil | |
1157 | "-f" filename "-q" target)))) | |
72c0ae01 | 1158 | |
6783b1ce RS |
1159 | \f |
1160 | ||
72c0ae01 ER |
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 | ||
b8ca7cc3 RS |
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 | ||
6783b1ce | 1195 | \f |
b8ca7cc3 | 1196 | |
72c0ae01 ER |
1197 | ;;; ------------------------------------------------------------ |
1198 | ;;; GNU make function support | |
1199 | ;;; ------------------------------------------------------------ | |
1200 | ||
1201 | (defun makefile-insert-gmake-function () | |
308a2860 RS |
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." | |
72c0ae01 ER |
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) | |
308a2860 RS |
1222 | (read-string (format "[%s] %s: " function-name one-prompt) |
1223 | nil))) | |
72c0ae01 ER |
1224 | prompt-list |
1225 | ",")) | |
308a2860 | 1226 | |
6783b1ce | 1227 | \f |
72c0ae01 ER |
1228 | |
1229 | ;;; ------------------------------------------------------------ | |
1230 | ;;; Utility functions | |
1231 | ;;; ------------------------------------------------------------ | |
1232 | ||
6783b1ce RS |
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 | ||
9e9bf716 | 1240 | (defun makefile-remember-target (target-name &optional has-prereqs) |
72c0ae01 ER |
1241 | "Remember a given target if it is not already remembered for this buffer." |
1242 | (if (not (zerop (length target-name))) | |
9e9bf716 | 1243 | (progn |
72c0ae01 ER |
1244 | (if (not (assoc target-name makefile-target-table)) |
1245 | (setq makefile-target-table | |
9e9bf716 ER |
1246 | (cons (list target-name) makefile-target-table))) |
1247 | (if has-prereqs | |
1248 | (setq makefile-has-prereqs | |
1249 | (cons target-name makefile-has-prereqs)))))) | |
72c0ae01 ER |
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 () | |
308a2860 RS |
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'." | |
72c0ae01 ER |
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) | |
308a2860 RS |
1288 | "Format a macro reference. |
1289 | Uses `makefile-use-curly-braces-for-macros-p'." | |
b8ca7cc3 RS |
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)))) | |
72c0ae01 ER |
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 | ||
6783b1ce RS |
1322 | \f |
1323 | ||
1324 | ;;; Support for other packages, like add-log and imenu. | |
1325 | ||
1326 | (defun makefile-add-log-defun () | |
308a2860 | 1327 | ;; "Return name of target or macro point is in, or nil." |
6783b1ce RS |
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 | (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 () | |
308a2860 | 1343 | ;; "Generate alist of indices for imenu." |
6783b1ce RS |
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) | |
6783b1ce RS |
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 | ||
118a9857 RS |
1362 | (defun makefile-define-space-face () |
1363 | (make-face 'makefile-space-face) | |
1364 | (or (face-differs-from-default-p 'makefile-space-face) | |
3fc9add9 RS |
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")))) | |
118a9857 | 1376 | (set-face-background 'makefile-space-face bg-color)))) |
3fc9add9 | 1377 | |
6783b1ce | 1378 | ;;; makefile.el ends here |