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