Commit | Line | Data |
---|---|---|
80e01c19 | 1 | ;;; make-mode.el --- makefile editing commands for Emacs |
72c0ae01 | 2 | |
dc184009 | 3 | ;; Copyright (C) 1992, 1994, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
ae940284 | 4 | ;; 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
58142744 | 5 | |
72c0ae01 | 6 | ;; Author: Thomas Neumann <tom@smart.bo.open.de> |
9e9bf716 | 7 | ;; Eric S. Raymond <esr@snark.thyrsus.com> |
4228277d | 8 | ;; Maintainer: FSF |
72c0ae01 | 9 | ;; Adapted-By: ESR |
fd7fa35a | 10 | ;; Keywords: unix, tools |
72c0ae01 | 11 | |
72c0ae01 ER |
12 | ;; This file is part of GNU Emacs. |
13 | ||
b1fc2b50 | 14 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
72c0ae01 | 15 | ;; it under the terms of the GNU General Public License as published by |
b1fc2b50 GM |
16 | ;; the Free Software Foundation, either version 3 of the License, or |
17 | ;; (at your option) any later version. | |
72c0ae01 ER |
18 | |
19 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | ;; GNU General Public License for more details. | |
23 | ||
24 | ;; You should have received a copy of the GNU General Public License | |
b1fc2b50 | 25 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
72c0ae01 | 26 | |
e41b2db1 ER |
27 | ;;; Commentary: |
28 | ||
9e9bf716 ER |
29 | ;; A major mode for editing makefiles. The mode knows about Makefile |
30 | ;; syntax and defines M-n and M-p to move to next and previous productions. | |
31 | ;; | |
32 | ;; The keys $, =, : and . are electric; they try to help you fill in a | |
33 | ;; macro reference, macro definition, ordinary target name, or special | |
34 | ;; target name, respectively. Such names are completed using a list of | |
35 | ;; targets and macro names parsed out of the makefile. This list is | |
36 | ;; automatically updated, if necessary, whenever you invoke one of | |
37 | ;; these commands. You can force it to be updated with C-c C-p. | |
38 | ;; | |
6783b1ce | 39 | ;; The command C-c C-f adds certain filenames in the current directory |
9e9bf716 ER |
40 | ;; as targets. You can filter out filenames by setting the variable |
41 | ;; makefile-ignored-files-in-pickup-regex. | |
42 | ;; | |
43 | ;; The command C-c C-u grinds for a bit, then pops up a report buffer | |
44 | ;; showing which target names are up-to-date with respect to their | |
45 | ;; prerequisites, which targets are out-of-date, and which have no | |
46 | ;; prerequisites. | |
47 | ;; | |
6783b1ce | 48 | ;; The command C-c C-b pops up a browser window listing all target and |
10f518f7 | 49 | ;; macro names. You can mark or unmark items with C-c SPC, and insert |
9e9bf716 ER |
50 | ;; all marked items back in the Makefile with C-c TAB. |
51 | ;; | |
52 | ;; The command C-c TAB in the makefile buffer inserts a GNU make builtin. | |
53 | ;; You will be prompted for the builtin's args. | |
54 | ;; | |
55 | ;; There are numerous other customization variables. | |
e41b2db1 | 56 | |
6783b1ce RS |
57 | ;; |
58 | ;; To Do: | |
59 | ;; | |
e008a4e5 | 60 | ;; * Add missing doc strings, improve terse doc strings. |
6783b1ce RS |
61 | ;; * Eliminate electric stuff entirely. |
62 | ;; * It might be nice to highlight targets differently depending on | |
63 | ;; whether they are up-to-date or not. Not sure how this would | |
64 | ;; interact with font-lock. | |
65 | ;; * Would be nice to edit the commands in ksh-mode and have | |
66 | ;; indentation and slashification done automatically. Hard. | |
67 | ;; * Consider removing browser mode. It seems useless. | |
68 | ;; * ":" should notice when a new target is made and add it to the | |
69 | ;; list (or at least set makefile-need-target-pickup). | |
308a2860 | 70 | ;; * Make browser into a major mode. |
6783b1ce RS |
71 | ;; * Clean up macro insertion stuff. It is a mess. |
72 | ;; * Browser entry and exit is weird. Normalize. | |
73 | ;; * Browser needs to be rewritten. Right now it is kind of a crock. | |
74 | ;; Should at least: | |
75 | ;; * Act more like dired/buffer menu/whatever. | |
76 | ;; * Highlight as mouse traverses. | |
77 | ;; * B2 inserts. | |
78 | ;; * Update documentation above. | |
79 | ;; * Update texinfo manual. | |
80 | ;; * Update files.el. | |
81 | ||
82 | \f | |
83 | ||
72c0ae01 ER |
84 | ;;; Code: |
85 | ||
6783b1ce RS |
86 | ;; Sadly we need this for a macro. |
87 | (eval-when-compile | |
9ffb4859 GM |
88 | (require 'imenu) |
89 | (require 'dabbrev) | |
90 | (require 'add-log)) | |
6783b1ce | 91 | |
72c0ae01 | 92 | ;;; ------------------------------------------------------------ |
eb8c3be9 | 93 | ;;; Configurable stuff |
72c0ae01 ER |
94 | ;;; ------------------------------------------------------------ |
95 | ||
c098c7f1 RS |
96 | (defgroup makefile nil |
97 | "Makefile editing commands for Emacs." | |
8ec3bce0 | 98 | :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) |
c098c7f1 RS |
99 | :group 'tools |
100 | :prefix "makefile-") | |
72c0ae01 | 101 | |
602dc0da | 102 | (defface makefile-space |
9c859203 DP |
103 | '((((class color)) (:background "hotpink")) |
104 | (t (:reverse-video t))) | |
dc3fc797 | 105 | "Face to use for highlighting leading spaces in Font-Lock mode." |
a27b41ab | 106 | :group 'makefile) |
c4f6e489 | 107 | (define-obsolete-face-alias 'makefile-space-face 'makefile-space "22.1") |
dc3fc797 | 108 | |
602dc0da | 109 | (defface makefile-targets |
9c859203 | 110 | ;; This needs to go along both with foreground and background colors (i.e. shell) |
602dc0da | 111 | '((t (:inherit font-lock-function-name-face))) |
9c859203 | 112 | "Face to use for additionally highlighting rule targets in Font-Lock mode." |
30edba6e DP |
113 | :group 'makefile |
114 | :version "22.1") | |
9c859203 | 115 | |
602dc0da DP |
116 | (defface makefile-shell |
117 | () | |
118 | ;;'((((class color) (min-colors 88) (background light)) (:background "seashell1")) | |
119 | ;; (((class color) (min-colors 88) (background dark)) (:background "seashell4"))) | |
9c859203 | 120 | "Face to use for additionally highlighting Shell commands in Font-Lock mode." |
30edba6e DP |
121 | :group 'makefile |
122 | :version "22.1") | |
9c859203 | 123 | |
602dc0da | 124 | (defface makefile-makepp-perl |
9c859203 DP |
125 | '((((class color) (background light)) (:background "LightBlue1")) ; Camel Book |
126 | (((class color) (background dark)) (:background "DarkBlue")) | |
127 | (t (:reverse-video t))) | |
128 | "Face to use for additionally highlighting Perl code in Font-Lock mode." | |
30edba6e DP |
129 | :group 'makefile |
130 | :version "22.1") | |
9c859203 | 131 | |
c098c7f1 | 132 | (defcustom makefile-browser-buffer-name "*Macros and Targets*" |
9ffb4859 | 133 | "*Name of the macro- and target browser buffer." |
c098c7f1 RS |
134 | :type 'string |
135 | :group 'makefile) | |
136 | ||
137 | (defcustom makefile-target-colon ":" | |
9ffb4859 | 138 | "*String to append to all target names inserted by `makefile-insert-target'. |
c098c7f1 RS |
139 | \":\" or \"::\" are common values." |
140 | :type 'string | |
141 | :group 'makefile) | |
72c0ae01 | 142 | |
c098c7f1 | 143 | (defcustom makefile-macro-assign " = " |
9ffb4859 | 144 | "*String to append to all macro names inserted by `makefile-insert-macro'. |
72c0ae01 | 145 | The normal value should be \" = \", since this is what |
a564ebfc | 146 | standard make expects. However, newer makes such as dmake |
72c0ae01 | 147 | allow a larger variety of different macro assignments, so you |
c098c7f1 RS |
148 | might prefer to use \" += \" or \" := \" ." |
149 | :type 'string | |
150 | :group 'makefile) | |
72c0ae01 | 151 | |
c098c7f1 | 152 | (defcustom makefile-electric-keys nil |
9ffb4859 | 153 | "*If non-nil, Makefile mode should install electric keybindings. |
c098c7f1 RS |
154 | Default is nil." |
155 | :type 'boolean | |
156 | :group 'makefile) | |
6783b1ce | 157 | |
c098c7f1 | 158 | (defcustom makefile-use-curly-braces-for-macros-p nil |
9ffb4859 | 159 | "*Controls the style of generated macro references. |
c098c7f1 RS |
160 | Non-nil means macro references should use curly braces, like `${this}'. |
161 | nil means use parentheses, like `$(this)'." | |
162 | :type 'boolean | |
163 | :group 'makefile) | |
72c0ae01 | 164 | |
c098c7f1 | 165 | (defcustom makefile-tab-after-target-colon t |
9ffb4859 | 166 | "*If non-nil, insert a TAB after a target colon. |
308a2860 | 167 | Otherwise, a space is inserted. |
c098c7f1 RS |
168 | The default is t." |
169 | :type 'boolean | |
170 | :group 'makefile) | |
171 | ||
172 | (defcustom makefile-browser-leftmost-column 10 | |
9ffb4859 | 173 | "*Number of blanks to the left of the browser selection mark." |
c098c7f1 RS |
174 | :type 'integer |
175 | :group 'makefile) | |
176 | ||
177 | (defcustom makefile-browser-cursor-column 10 | |
9ffb4859 | 178 | "*Column the cursor goes to when it moves up or down in the Makefile browser." |
c098c7f1 RS |
179 | :type 'integer |
180 | :group 'makefile) | |
181 | ||
182 | (defcustom makefile-backslash-column 48 | |
183 | "*Column in which `makefile-backslash-region' inserts backslashes." | |
184 | :type 'integer | |
185 | :group 'makefile) | |
186 | ||
187 | (defcustom makefile-backslash-align t | |
9ffb4859 | 188 | "*If non-nil, `makefile-backslash-region' will align backslashes." |
c098c7f1 RS |
189 | :type 'boolean |
190 | :group 'makefile) | |
191 | ||
192 | (defcustom makefile-browser-selected-mark "+ " | |
9ffb4859 | 193 | "*String used to mark selected entries in the Makefile browser." |
c098c7f1 RS |
194 | :type 'string |
195 | :group 'makefile) | |
196 | ||
197 | (defcustom makefile-browser-unselected-mark " " | |
9ffb4859 | 198 | "*String used to mark unselected entries in the Makefile browser." |
c098c7f1 RS |
199 | :type 'string |
200 | :group 'makefile) | |
201 | ||
202 | (defcustom makefile-browser-auto-advance-after-selection-p t | |
9ffb4859 | 203 | "*If non-nil, cursor will move after item is selected in Makefile browser." |
c098c7f1 RS |
204 | :type 'boolean |
205 | :group 'makefile) | |
206 | ||
207 | (defcustom makefile-pickup-everything-picks-up-filenames-p nil | |
9ffb4859 | 208 | "*If non-nil, `makefile-pickup-everything' picks up filenames as targets. |
b20a44dc | 209 | This means it calls `makefile-pickup-filenames-as-targets'. |
c098c7f1 RS |
210 | Otherwise filenames are omitted." |
211 | :type 'boolean | |
212 | :group 'makefile) | |
72c0ae01 | 213 | |
a11e2800 | 214 | (defcustom makefile-cleanup-continuations nil |
9ffb4859 | 215 | "*If non-nil, automatically clean up continuation lines when saving. |
308a2860 RS |
216 | A line is cleaned up by removing all whitespace following a trailing |
217 | backslash. This is done silently. | |
a564ebfc | 218 | IMPORTANT: Please note that enabling this option causes Makefile mode |
c098c7f1 RS |
219 | to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\"." |
220 | :type 'boolean | |
221 | :group 'makefile) | |
72c0ae01 | 222 | |
66c8215f | 223 | (defcustom makefile-mode-hook nil |
9ffb4859 | 224 | "*Normal hook run by `makefile-mode'." |
66c8215f DL |
225 | :type 'hook |
226 | :group 'makefile) | |
227 | ||
308a2860 | 228 | (defvar makefile-browser-hook '()) |
72c0ae01 ER |
229 | |
230 | ;; | |
231 | ;; Special targets for DMake, Sun's make ... | |
a1506d29 | 232 | ;; |
c098c7f1 | 233 | (defcustom makefile-special-targets-list |
72c0ae01 ER |
234 | '(("DEFAULT") ("DONE") ("ERROR") ("EXPORT") |
235 | ("FAILED") ("GROUPEPILOG") ("GROUPPROLOG") ("IGNORE") | |
236 | ("IMPORT") ("INCLUDE") ("INCLUDEDIRS") ("INIT") | |
237 | ("KEEP_STATE") ("MAKEFILES") ("MAKE_VERSION") ("NO_PARALLEL") | |
238 | ("PARALLEL") ("PHONY") ("PRECIOUS") ("REMOVE") | |
239 | ("SCCS_GET") ("SILENT") ("SOURCE") ("SUFFIXES") | |
240 | ("WAIT") ("c.o") ("C.o") ("m.o") | |
241 | ("el.elc") ("y.c") ("s.o")) | |
9ffb4859 | 242 | "*List of special targets. |
308a2860 | 243 | You will be offered to complete on one of those in the minibuffer whenever |
9ffb4859 | 244 | you enter a \".\" at the beginning of a line in `makefile-mode'." |
c098c7f1 RS |
245 | :type '(repeat (list string)) |
246 | :group 'makefile) | |
9e2d84cc | 247 | (put 'makefile-special-targets-list 'risky-local-variable t) |
72c0ae01 | 248 | |
c098c7f1 | 249 | (defcustom makefile-runtime-macros-list |
1f35e359 | 250 | '(("@") ("&") (">") ("<") ("*") ("^") ("+") ("?") ("%") ("$")) |
9ffb4859 | 251 | "*List of macros that are resolved by make at runtime. |
a564ebfc DL |
252 | If you insert a macro reference using `makefile-insert-macro-ref', the name |
253 | of the macro is checked against this list. If it can be found its name will | |
c098c7f1 RS |
254 | not be enclosed in { } or ( )." |
255 | :type '(repeat (list string)) | |
256 | :group 'makefile) | |
72c0ae01 | 257 | |
6783b1ce | 258 | ;; Note that the first big subexpression is used by font lock. Note |
3b7f63b1 RS |
259 | ;; that if you change this regexp you might have to fix the imenu |
260 | ;; index in makefile-imenu-generic-expression. | |
92984345 DP |
261 | (defvar makefile-dependency-regex |
262 | ;; Allow for two nested levels $(v1:$(v2:$(v3:a=b)=c)=d) | |
9391790a | 263 | "^\\(\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[({]\\(?:\\$\\(?:[^({]\\|.[^\n$#})]+?[})]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#)}]\\)+?[})]\\|[^({]\\)\\|[^\n$#:=]\\)+?\\)\\(:\\)\\(?:[ \t]*$\\|[^=\n]\\(?:[^#\n]*?;[ \t]*\\(.+\\)\\)?\\)" |
72c0ae01 ER |
264 | "Regex used to find dependency lines in a makefile.") |
265 | ||
30edba6e DP |
266 | (defconst makefile-bsdmake-dependency-regex |
267 | (progn (string-match (regexp-quote "\\(:\\)") makefile-dependency-regex) | |
268 | (replace-match "\\([:!]\\)" t t makefile-dependency-regex)) | |
269 | "Regex used to find dependency lines in a BSD makefile.") | |
270 | ||
0b11ce59 DP |
271 | (defvar makefile-dependency-skip "^:" |
272 | "Characters to skip to find a line that might be a dependency.") | |
273 | ||
92984345 | 274 | (defvar makefile-rule-action-regex |
adde7693 | 275 | "^\t[ \t]*\\([-@]*\\)[ \t]*\\(\\(?:.*\\\\\n\\)*.*\\)" |
9c859203 DP |
276 | "Regex used to highlight rule action lines in font lock mode.") |
277 | ||
30edba6e DP |
278 | (defconst makefile-makepp-rule-action-regex |
279 | ;; Don't care about initial tab, but I don't know how to font-lock correctly without. | |
280 | "^\t[ \t]*\\(\\(?:\\(?:noecho\\|ignore[-_]error\\|[-@]+\\)[ \t]*\\)*\\)\\(\\(&\\S +\\)?\\(?:.*\\\\\n\\)*.*\\)" | |
281 | "Regex used to highlight makepp rule action lines in font lock mode.") | |
282 | ||
283 | (defconst makefile-bsdmake-rule-action-regex | |
284 | (progn (string-match "-@" makefile-rule-action-regex) | |
285 | (replace-match "-+@" t t makefile-rule-action-regex)) | |
286 | "Regex used to highlight BSD rule action lines in font lock mode.") | |
287 | ||
9c859203 DP |
288 | ;; Note that the first and second subexpression is used by font lock. Note |
289 | ;; that if you change this regexp you might have to fix the imenu index in | |
290 | ;; makefile-imenu-generic-expression. | |
72c0ae01 | 291 | (defconst makefile-macroassign-regex |
c5301b5c SM |
292 | ;; We used to match not just the varname but also the whole value |
293 | ;; (spanning potentially several lines). | |
294 | ;; "^ *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*\\(?:!=[ \t]*\\(\\(?:.+\\\\\n\\)*.+\\)\\|[*:+]?[:?]?=[ \t]*\\(\\(?:.*\\\\\n\\)*.*\\)\\)" | |
88983f8c DP |
295 | ;; What about the define statement? What about differentiating this for makepp? |
296 | "\\(?:^\\|^export\\|^override\\|:\\|: *override\\) *\\([^ \n\t][^:#= \t\n]*\\)[ \t]*\\(?:!=\\|[*:+]?[:?]?=\\)" | |
72c0ae01 ER |
297 | "Regex used to find macro assignment lines in a makefile.") |
298 | ||
9c859203 | 299 | (defconst makefile-var-use-regex |
92984345 | 300 | "[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\|[@%<?^+*][FD]?\\)" |
9c859203 DP |
301 | "Regex used to find $(macro) uses in a makefile.") |
302 | ||
72c0ae01 | 303 | (defconst makefile-ignored-files-in-pickup-regex |
0c5b5a13 | 304 | "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)" |
72c0ae01 ER |
305 | "Regex for filenames that will NOT be included in the target list.") |
306 | ||
602dc0da | 307 | (defvar makefile-space 'makefile-space |
118a9857 | 308 | "Face to use for highlighting leading spaces in Font-Lock mode.") |
308a2860 | 309 | |
9c859203 DP |
310 | ;; These lists were inspired by the old solution. But they are silly, because |
311 | ;; you can't differentiate what follows. They need to be split up. | |
312 | (defconst makefile-statements '("include") | |
313 | "List of keywords understood by standard make.") | |
314 | ||
315 | (defconst makefile-automake-statements | |
316 | `("if" "else" "endif" ,@makefile-statements) | |
317 | "List of keywords understood by automake.") | |
318 | ||
319 | (defconst makefile-gmake-statements | |
88983f8c | 320 | `("-sinclude" "sinclude" "vpath" ; makefile-makepp-statements takes rest |
9c859203 | 321 | "ifdef" "ifndef" "ifeq" "ifneq" "-include" "define" "endef" "export" |
88983f8c | 322 | "override define" "override" "unexport" |
9c859203 DP |
323 | ,@(cdr makefile-automake-statements)) |
324 | "List of keywords understood by gmake.") | |
325 | ||
326 | ;; These are even more silly, because you can have more spaces in between. | |
327 | (defconst makefile-makepp-statements | |
328 | `("and ifdef" "and ifndef" "and ifeq" "and ifneq" "and ifperl" | |
329 | "and ifmakeperl" "and ifsys" "and ifnsys" "build_cache" "build_check" | |
330 | "else ifdef" "else ifndef" "else ifeq" "else ifneq" "else ifperl" | |
88983f8c DP |
331 | "else ifmakeperl" "else ifsys" "else ifnsys" "enddef" "global" |
332 | "load_makefile" "ifperl" "ifmakeperl" "ifsys" "ifnsys" "_include" | |
333 | "makeperl" "makesub" "no_implicit_load" "perl" "perl-begin" "perl_begin" | |
334 | "perl-end" "perl_end" "prebuild" "or ifdef" "or ifndef" "or ifeq" | |
335 | "or ifneq" "or ifperl" "or ifmakeperl" "or ifsys" "or ifnsys" | |
336 | "override export" "override global" "register_command_parser" | |
9c859203 | 337 | "register_scanner" "repository" "runtime" "signature" "sub" |
88983f8c | 338 | ,@(nthcdr 3 makefile-gmake-statements)) |
9c859203 DP |
339 | "List of keywords understood by gmake.") |
340 | ||
341 | (defconst makefile-bsdmake-statements | |
342 | `(".elif" ".elifdef" ".elifmake" ".elifndef" ".elifnmake" ".else" ".endfor" | |
343 | ".endif" ".for" ".if" ".ifdef" ".ifmake" ".ifndef" ".ifnmake" ".undef") | |
344 | "List of keywords understood by BSD make.") | |
345 | ||
92984345 DP |
346 | (defun makefile-make-font-lock-keywords (var keywords space |
347 | &optional negation | |
348 | &rest font-lock-keywords) | |
9c859203 DP |
349 | `(;; Do macro assignments. These get the "variable-name" face. |
350 | (,makefile-macroassign-regex | |
351 | (1 font-lock-variable-name-face) | |
352 | ;; This is for after != | |
602dc0da | 353 | (2 'makefile-shell prepend t) |
8ade3c25 DP |
354 | ;; This is for after normal assignment |
355 | (3 'font-lock-string-face prepend t)) | |
9c859203 | 356 | |
9c859203 | 357 | ;; Rule actions. |
92984345 | 358 | (makefile-match-action |
9c859203 | 359 | (1 font-lock-type-face) |
602dc0da | 360 | (2 'makefile-shell prepend) |
9c859203 DP |
361 | ;; Only makepp has builtin commands. |
362 | (3 font-lock-builtin-face prepend t)) | |
363 | ||
364 | ;; Variable references even in targets/strings/comments. | |
365 | (,var 1 font-lock-variable-name-face prepend) | |
366 | ||
367 | ;; Automatic variable references and single character variable references, | |
368 | ;; but not shell variables references. | |
369 | ("[^$]\\$\\([@%<?^+*_]\\|[a-zA-Z0-9]\\>\\)" | |
370 | 1 font-lock-constant-face prepend) | |
371 | ("[^$]\\(\\$[@%*]\\)" | |
602dc0da | 372 | 1 'makefile-targets append) |
9ffb4859 | 373 | |
9c859203 | 374 | ;; Fontify conditionals and includes. |
9c859203 DP |
375 | (,(concat "^\\(?: [ \t]*\\)?" |
376 | (regexp-opt keywords t) | |
377 | "\\>[ \t]*\\([^: \t\n#]*\\)") | |
378 | (1 font-lock-keyword-face) (2 font-lock-variable-name-face)) | |
9ffb4859 | 379 | |
92984345 | 380 | ,@(if negation |
5c8b5442 DP |
381 | `((,negation (1 font-lock-negation-char-face prepend) |
382 | (2 font-lock-negation-char-face prepend t)))) | |
9ffb4859 | 383 | |
9c859203 DP |
384 | ,@(if space |
385 | '(;; Highlight lines that contain just whitespace. | |
386 | ;; They can cause trouble, especially if they start with a tab. | |
602dc0da | 387 | ("^[ \t]+$" . makefile-space) |
61bc75ab | 388 | |
9c859203 DP |
389 | ;; Highlight shell comments that Make treats as commands, |
390 | ;; since these can fool people. | |
602dc0da | 391 | ("^\t+#" 0 makefile-space t) |
ba080a3c | 392 | |
9c859203 DP |
393 | ;; Highlight spaces that precede tabs. |
394 | ;; They can make a tab fail to be effective. | |
602dc0da | 395 | ("^\\( +\\)\t" 1 makefile-space))) |
10f518f7 | 396 | |
92984345 DP |
397 | ,@font-lock-keywords |
398 | ||
399 | ;; Do dependencies. | |
400 | (makefile-match-dependency | |
602dc0da DP |
401 | (1 'makefile-targets prepend) |
402 | (3 'makefile-shell prepend t)))) | |
bd0e4eb1 | 403 | |
9c859203 DP |
404 | (defconst makefile-font-lock-keywords |
405 | (makefile-make-font-lock-keywords | |
9c859203 DP |
406 | makefile-var-use-regex |
407 | makefile-statements | |
408 | t)) | |
409 | ||
410 | (defconst makefile-automake-font-lock-keywords | |
411 | (makefile-make-font-lock-keywords | |
9c859203 DP |
412 | makefile-var-use-regex |
413 | makefile-automake-statements | |
414 | t)) | |
415 | ||
416 | (defconst makefile-gmake-font-lock-keywords | |
417 | (makefile-make-font-lock-keywords | |
9c859203 DP |
418 | makefile-var-use-regex |
419 | makefile-gmake-statements | |
420 | t | |
421 | "^\\(?: [ \t]*\\)?if\\(n\\)\\(?:def\\|eq\\)\\>" | |
422 | ||
423 | '("[^$]\\(\\$[({][@%*][DF][})]\\)" | |
602dc0da | 424 | 1 'makefile-targets append) |
9c859203 DP |
425 | |
426 | ;; $(function ...) ${function ...} | |
92984345 DP |
427 | '("[^$]\\$[({]\\([-a-zA-Z0-9_.]+\\s \\)" |
428 | 1 font-lock-function-name-face prepend) | |
9c859203 DP |
429 | |
430 | ;; $(shell ...) ${shell ...} | |
431 | '("[^$]\\$\\([({]\\)shell[ \t]+" | |
432 | makefile-match-function-end nil nil | |
602dc0da | 433 | (1 'makefile-shell prepend t)))) |
9c859203 DP |
434 | |
435 | (defconst makefile-makepp-font-lock-keywords | |
436 | (makefile-make-font-lock-keywords | |
9c859203 DP |
437 | makefile-var-use-regex |
438 | makefile-makepp-statements | |
439 | nil | |
440 | "^\\(?: [ \t]*\\)?\\(?:and[ \t]+\\|else[ \t]+\\|or[ \t]+\\)?if\\(n\\)\\(?:def\\|eq\\|sys\\)\\>" | |
441 | ||
adde7693 | 442 | '("[^$]\\(\\$[({]\\(?:output\\|stem\\|target\\)s?\\_>.*?[})]\\)" |
602dc0da | 443 | 1 'makefile-targets append) |
9c859203 DP |
444 | |
445 | ;; Colon modifier keywords. | |
92984345 DP |
446 | '("\\(:\\s *\\)\\(build_c\\(?:ache\\|heck\\)\\|env\\(?:ironment\\)?\\|foreach\\|signature\\|scanner\\|quickscan\\|smartscan\\)\\>\\([^:\n]*\\)" |
447 | (1 font-lock-type-face t) | |
448 | (2 font-lock-keyword-face t) | |
449 | (3 font-lock-variable-name-face t)) | |
9c859203 DP |
450 | |
451 | ;; $(function ...) $((function ...)) ${function ...} ${{function ...}} | |
92984345 DP |
452 | '("[^$]\\$\\(?:((?\\|{{?\\)\\([-a-zA-Z0-9_.]+\\s \\)" |
453 | 1 font-lock-function-name-face prepend) | |
9c859203 DP |
454 | |
455 | ;; $(shell ...) $((shell ...)) ${shell ...} ${{shell ...}} | |
456 | '("[^$]\\$\\(((?\\|{{?\\)shell\\(?:[-_]\\(?:global[-_]\\)?once\\)?[ \t]+" | |
457 | makefile-match-function-end nil nil | |
602dc0da | 458 | (1 'makefile-shell prepend t)) |
9c859203 DP |
459 | |
460 | ;; $(perl ...) $((perl ...)) ${perl ...} ${{perl ...}} | |
461 | '("[^$]\\$\\(((?\\|{{?\\)makeperl[ \t]+" | |
462 | makefile-match-function-end nil nil | |
602dc0da | 463 | (1 'makefile-makepp-perl prepend t)) |
9c859203 DP |
464 | '("[^$]\\$\\(((?\\|{{?\\)perl[ \t]+" |
465 | makefile-match-function-end nil nil | |
602dc0da | 466 | (1 'makefile-makepp-perl t t)) |
9c859203 DP |
467 | |
468 | ;; Can we unify these with (if (match-end 1) 'prepend t)? | |
602dc0da DP |
469 | '("ifmakeperl\\s +\\(.*\\)" 1 'makefile-makepp-perl prepend) |
470 | '("ifperl\\s +\\(.*\\)" 1 'makefile-makepp-perl t) | |
9c859203 DP |
471 | |
472 | ;; Perl block single- or multiline, as statement or rule action. | |
473 | ;; Don't know why the initial newline in 2nd variant of group 2 doesn't get skipped. | |
474 | '("\\<make\\(?:perl\\|sub\\s +\\S +\\)\\s *\n?\\s *{\\(?:{\\s *\n?\\(\\(?:.*\n\\)+?\\)\\s *}\\|\\s *\\(\\(?:.*?\\|\n?\\(?:.*\n\\)+?\\)\\)\\)}" | |
602dc0da DP |
475 | (1 'makefile-makepp-perl prepend t) |
476 | (2 'makefile-makepp-perl prepend t)) | |
9c859203 | 477 | '("\\<\\(?:perl\\|sub\\s +\\S +\\)\\s *\n?\\s *{\\(?:{\\s *\n?\\(\\(?:.*\n\\)+?\\)\\s *}\\|\\s *\\(\\(?:.*?\\|\n?\\(?:.*\n\\)+?\\)\\)\\)}" |
602dc0da DP |
478 | (1 'makefile-makepp-perl t t) |
479 | (2 'makefile-makepp-perl t t)) | |
9c859203 DP |
480 | |
481 | ;; Statement style perl block. | |
482 | '("perl[-_]begin\\s *\\(?:\\s #.*\\)?\n\\(\\(?:.*\n\\)+?\\)\\s *perl[-_]end\\>" | |
602dc0da | 483 | 1 'makefile-makepp-perl t))) |
9c859203 | 484 | |
9c859203 DP |
485 | (defconst makefile-bsdmake-font-lock-keywords |
486 | (makefile-make-font-lock-keywords | |
92984345 | 487 | ;; A lot more could be done for variables here: |
9c859203 DP |
488 | makefile-var-use-regex |
489 | makefile-bsdmake-statements | |
490 | t | |
491 | "^\\(?: [ \t]*\\)?\\.\\(?:el\\)?if\\(n?\\)\\(?:def\\|make\\)?\\>[ \t]*\\(!?\\)" | |
492 | '("^[ \t]*\\.for[ \t].+[ \t]\\(in\\)\\>" 1 font-lock-keyword-face))) | |
f067044f | 493 | |
3968c89f MY |
494 | (defconst makefile-imake-font-lock-keywords |
495 | (append | |
496 | (makefile-make-font-lock-keywords | |
497 | makefile-var-use-regex | |
498 | makefile-statements | |
499 | t | |
500 | nil | |
501 | '("^XCOMM.*$" . font-lock-comment-face) | |
502 | '("XVAR\\(?:use\\|def\\)[0-9]" 0 font-lock-keyword-face prepend) | |
503 | '("@@" . font-lock-preprocessor-face) | |
504 | ) | |
505 | cpp-font-lock-keywords)) | |
506 | ||
6783b1ce | 507 | |
0b51ba8a | 508 | (defconst makefile-font-lock-syntactic-keywords |
310ee6ad SM |
509 | ;; From sh-script.el. |
510 | ;; A `#' begins a comment in sh when it is unquoted and at the beginning | |
511 | ;; of a word. In the shell, words are separated by metacharacters. | |
512 | ;; The list of special chars is taken from the single-unix spec of the | |
513 | ;; shell command language (under `quoting') but with `$' removed. | |
514 | '(("[^|&;<>()`\\\"' \t\n]\\(#+\\)" 1 "_") | |
515 | ;; Change the syntax of a quoted newline so that it does not end a comment. | |
516 | ("\\\\\n" 0 "."))) | |
0b51ba8a | 517 | |
db85e69c | 518 | (defvar makefile-imenu-generic-expression |
774cd454 | 519 | `(("Dependencies" makefile-previous-dependency 1) |
92984345 | 520 | ("Macro Assignment" ,makefile-macroassign-regex 1)) |
a564ebfc | 521 | "Imenu generic expression for Makefile mode. See `imenu-generic-expression'.") |
db85e69c | 522 | |
72c0ae01 ER |
523 | ;;; ------------------------------------------------------------ |
524 | ;;; The following configurable variables are used in the | |
525 | ;;; up-to-date overview . | |
eb8c3be9 | 526 | ;;; The standard configuration assumes that your `make' program |
72c0ae01 ER |
527 | ;;; can be run in question/query mode using the `-q' option, this |
528 | ;;; means that the command | |
529 | ;;; | |
530 | ;;; make -q foo | |
531 | ;;; | |
532 | ;;; should return an exit status of zero if the target `foo' is | |
533 | ;;; up to date and a nonzero exit status otherwise. | |
534 | ;;; Many makes can do this although the docs/manpages do not mention | |
9e9bf716 ER |
535 | ;;; it. Try it with your favourite one. GNU make, System V make, and |
536 | ;;; Dennis Vadura's DMake have no problems. | |
72c0ae01 ER |
537 | ;;; Set the variable `makefile-brave-make' to the name of the |
538 | ;;; make utility that does this on your system. | |
eb8c3be9 | 539 | ;;; To understand what this is all about see the function definition |
72c0ae01 ER |
540 | ;;; of `makefile-query-by-make-minus-q' . |
541 | ;;; ------------------------------------------------------------ | |
542 | ||
c098c7f1 | 543 | (defcustom makefile-brave-make "make" |
9ffb4859 | 544 | "*How to invoke make, for `makefile-query-targets'. |
c098c7f1 RS |
545 | This should identify a `make' command that can handle the `-q' option." |
546 | :type 'string | |
547 | :group 'makefile) | |
72c0ae01 | 548 | |
b308197b RW |
549 | (defcustom makefile-query-one-target-method-function |
550 | 'makefile-query-by-make-minus-q | |
9ffb4859 | 551 | "*Function to call to determine whether a make target is up to date. |
bd0e4eb1 | 552 | The function must satisfy this calling convention: |
72c0ae01 ER |
553 | |
554 | * As its first argument, it must accept the name of the target to | |
555 | be checked, as a string. | |
556 | ||
557 | * As its second argument, it may accept the name of a makefile | |
a564ebfc | 558 | as a string. Depending on what you're going to do you may |
72c0ae01 ER |
559 | not need this. |
560 | ||
561 | * It must return the integer value 0 (zero) if the given target | |
562 | should be considered up-to-date in the context of the given | |
c098c7f1 RS |
563 | makefile, any nonzero integer value otherwise." |
564 | :type 'function | |
565 | :group 'makefile) | |
b308197b RW |
566 | (defvaralias 'makefile-query-one-target-method |
567 | 'makefile-query-one-target-method-function) | |
c098c7f1 RS |
568 | |
569 | (defcustom makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*" | |
9ffb4859 | 570 | "*Name of the Up-to-date overview buffer." |
c098c7f1 RS |
571 | :type 'string |
572 | :group 'makefile) | |
72c0ae01 | 573 | |
72c0ae01 ER |
574 | ;;; --- end of up-to-date-overview configuration ------------------ |
575 | ||
9ffb4859 GM |
576 | (defvar makefile-mode-abbrev-table nil |
577 | "Abbrev table in use in Makefile buffers.") | |
578 | (if makefile-mode-abbrev-table | |
579 | () | |
580 | (define-abbrev-table 'makefile-mode-abbrev-table ())) | |
581 | ||
9c859203 | 582 | (defvar makefile-mode-map |
2f9a87f5 DN |
583 | (let ((map (make-sparse-keymap)) |
584 | (opt-map (make-sparse-keymap))) | |
9c859203 DP |
585 | ;; set up the keymap |
586 | (define-key map "\C-c:" 'makefile-insert-target-ref) | |
587 | (if makefile-electric-keys | |
588 | (progn | |
589 | (define-key map "$" 'makefile-insert-macro-ref) | |
590 | (define-key map ":" 'makefile-electric-colon) | |
591 | (define-key map "=" 'makefile-electric-equal) | |
592 | (define-key map "." 'makefile-electric-dot))) | |
593 | (define-key map "\C-c\C-f" 'makefile-pickup-filenames-as-targets) | |
594 | (define-key map "\C-c\C-b" 'makefile-switch-to-browser) | |
595 | (define-key map "\C-c\C-c" 'comment-region) | |
596 | (define-key map "\C-c\C-p" 'makefile-pickup-everything) | |
597 | (define-key map "\C-c\C-u" 'makefile-create-up-to-date-overview) | |
598 | (define-key map "\C-c\C-i" 'makefile-insert-gmake-function) | |
599 | (define-key map "\C-c\C-\\" 'makefile-backslash-region) | |
600 | (define-key map "\C-c\C-m\C-a" 'makefile-automake-mode) | |
601 | (define-key map "\C-c\C-m\C-b" 'makefile-bsdmake-mode) | |
602 | (define-key map "\C-c\C-m\C-g" 'makefile-gmake-mode) | |
3968c89f | 603 | (define-key map "\C-c\C-m\C-i" 'makefile-imake-mode) |
9c859203 DP |
604 | (define-key map "\C-c\C-m\C-m" 'makefile-mode) |
605 | (define-key map "\C-c\C-m\C-p" 'makefile-makepp-mode) | |
606 | (define-key map "\M-p" 'makefile-previous-dependency) | |
607 | (define-key map "\M-n" 'makefile-next-dependency) | |
608 | (define-key map "\e\t" 'makefile-complete) | |
609 | ||
610 | ;; Make menus. | |
611 | (define-key map [menu-bar makefile-mode] | |
612 | (cons "Makefile" (make-sparse-keymap "Makefile"))) | |
613 | ||
2f9a87f5 DN |
614 | (define-key map [menu-bar makefile-mode makefile-type] |
615 | (cons "Switch Makefile Type" opt-map)) | |
616 | (define-key opt-map [makefile-makepp-mode] | |
617 | '(menu-item "Makepp" makefile-makepp-mode | |
618 | :help "An adapted `makefile-mode' that knows about makepp" | |
619 | :button (:radio . (eq major-mode 'makefile-makepp-mode)))) | |
620 | (define-key opt-map [makefile-imake-mode] | |
621 | '(menu-item "Imake" makefile-imake-mode | |
622 | :help "An adapted `makefile-mode' that knows about imake" | |
623 | :button (:radio . (eq major-mode 'makefile-imake-mode)))) | |
624 | (define-key opt-map [makefile-mode] | |
625 | '(menu-item "Classic" makefile-mode | |
626 | :help "`makefile-mode' with no special functionality" | |
627 | :button (:radio . (eq major-mode 'makefile-mode)))) | |
628 | (define-key opt-map [makefile-bsdmake-mode] | |
629 | '(menu-item "BSD" makefile-bsdmake-mode | |
630 | :help "An adapted `makefile-mode' that knows about BSD make" | |
631 | :button (:radio . (eq major-mode 'makefile-bsdmake-mode)))) | |
632 | (define-key opt-map [makefile-automake-mode] | |
633 | '(menu-item "Automake" makefile-automake-mode | |
634 | :help "An adapted `makefile-mode' that knows about automake" | |
635 | :button (:radio . (eq major-mode 'makefile-automake-mode)))) | |
636 | (define-key opt-map [makefile-gmake-mode] | |
637 | '(menu-item "GNU make" makefile-gmake-mode | |
638 | :help "An adapted `makefile-mode' that knows about GNU make" | |
639 | :button (:radio . (eq major-mode 'makefile-gmake-mode)))) | |
9c859203 | 640 | (define-key map [menu-bar makefile-mode browse] |
2f9a87f5 DN |
641 | '(menu-item "Pop up Makefile Browser" makefile-switch-to-browser |
642 | ;; XXX: this needs a better string, the function is not documented... | |
643 | :help "Pop up Makefile Browser")) | |
644 | (define-key map [menu-bar makefile-mode overview] | |
645 | '(menu-item "Up To Date Overview" makefile-create-up-to-date-overview | |
646 | :help "Create a buffer containing an overview of the state of all known targets")) | |
647 | ;; Target related | |
648 | (define-key map [menu-bar makefile-mode separator1] '("----")) | |
649 | (define-key map [menu-bar makefile-mode pickup-file] | |
650 | '(menu-item "Pick File Name as Target" makefile-pickup-filenames-as-targets | |
651 | :help "Scan the current directory for filenames to use as targets")) | |
652 | (define-key map [menu-bar makefile-mode function] | |
653 | '(menu-item "Insert GNU make function" makefile-insert-gmake-function | |
654 | :help "Insert a GNU make function call")) | |
9c859203 | 655 | (define-key map [menu-bar makefile-mode pickup] |
2f9a87f5 DN |
656 | '(menu-item "Find Targets and Macros" makefile-pickup-everything |
657 | :help "Notice names of all macros and targets in Makefile")) | |
658 | (define-key map [menu-bar makefile-mode complete] | |
659 | '(menu-item "Complete Target or Macro" makefile-complete | |
660 | :help "Perform completion on Makefile construct preceding point")) | |
661 | (define-key map [menu-bar makefile-mode backslash] | |
662 | '(menu-item "Backslash Region" makefile-backslash-region | |
663 | :help "Insert, align, or delete end-of-line backslashes on the lines in the region")) | |
664 | ;; Motion | |
665 | (define-key map [menu-bar makefile-mode separator] '("----")) | |
9c859203 | 666 | (define-key map [menu-bar makefile-mode prev] |
2f9a87f5 DN |
667 | '(menu-item "Move to Previous Dependency" makefile-previous-dependency |
668 | :help "Move point to the beginning of the previous dependency line")) | |
9c859203 | 669 | (define-key map [menu-bar makefile-mode next] |
2f9a87f5 DN |
670 | '(menu-item "Move to Next Dependency" makefile-next-dependency |
671 | :help "Move point to the beginning of the next dependency line")) | |
9c859203 | 672 | map) |
bd0e4eb1 RS |
673 | "The keymap that is used in Makefile mode.") |
674 | ||
c5301b5c SM |
675 | |
676 | (defvar makefile-browser-map | |
677 | (let ((map (make-sparse-keymap))) | |
678 | (define-key map "n" 'makefile-browser-next-line) | |
679 | (define-key map "\C-n" 'makefile-browser-next-line) | |
680 | (define-key map "p" 'makefile-browser-previous-line) | |
681 | (define-key map "\C-p" 'makefile-browser-previous-line) | |
682 | (define-key map " " 'makefile-browser-toggle) | |
683 | (define-key map "i" 'makefile-browser-insert-selection) | |
684 | (define-key map "I" 'makefile-browser-insert-selection-and-quit) | |
685 | (define-key map "\C-c\C-m" 'makefile-browser-insert-continuation) | |
686 | (define-key map "q" 'makefile-browser-quit) | |
687 | ;; disable horizontal movement | |
688 | (define-key map "\C-b" 'undefined) | |
689 | (define-key map "\C-f" 'undefined) | |
690 | map) | |
72c0ae01 | 691 | "The keymap that is used in the macro- and target browser.") |
c5301b5c SM |
692 | |
693 | ||
694 | (defvar makefile-mode-syntax-table | |
695 | (let ((st (make-syntax-table))) | |
696 | (modify-syntax-entry ?\( "() " st) | |
697 | (modify-syntax-entry ?\) ")( " st) | |
698 | (modify-syntax-entry ?\[ "(] " st) | |
699 | (modify-syntax-entry ?\] ")[ " st) | |
700 | (modify-syntax-entry ?\{ "(} " st) | |
701 | (modify-syntax-entry ?\} "){ " st) | |
702 | (modify-syntax-entry ?\' "\" " st) | |
703 | (modify-syntax-entry ?\` "\" " st) | |
704 | (modify-syntax-entry ?# "< " st) | |
705 | (modify-syntax-entry ?\n "> " st) | |
706 | st)) | |
6783b1ce | 707 | |
3968c89f MY |
708 | (defvar makefile-imake-mode-syntax-table (copy-syntax-table |
709 | makefile-mode-syntax-table)) | |
710 | (if makefile-imake-mode-syntax-table | |
711 | () | |
712 | (modify-syntax-entry ?/ ". 14" makefile-imake-mode-syntax-table) | |
713 | (modify-syntax-entry ?* ". 23" makefile-imake-mode-syntax-table) | |
714 | (modify-syntax-entry ?# "'" makefile-imake-mode-syntax-table) | |
715 | (modify-syntax-entry ?\n ". b" makefile-imake-mode-syntax-table)) | |
716 | ||
6783b1ce | 717 | |
72c0ae01 ER |
718 | ;;; ------------------------------------------------------------ |
719 | ;;; Internal variables. | |
720 | ;;; You don't need to configure below this line. | |
721 | ;;; ------------------------------------------------------------ | |
722 | ||
723 | (defvar makefile-target-table nil | |
308a2860 | 724 | "Table of all target names known for this buffer.") |
9e2d84cc | 725 | (put 'makefile-target-table 'risky-local-variable t) |
72c0ae01 ER |
726 | |
727 | (defvar makefile-macro-table nil | |
308a2860 | 728 | "Table of all macro names known for this buffer.") |
9e2d84cc | 729 | (put 'makefile-macro-table 'risky-local-variable t) |
72c0ae01 ER |
730 | |
731 | (defvar makefile-browser-client | |
bd0e4eb1 | 732 | "A buffer in Makefile mode that is currently using the browser.") |
72c0ae01 ER |
733 | |
734 | (defvar makefile-browser-selection-vector nil) | |
9e9bf716 ER |
735 | (defvar makefile-has-prereqs nil) |
736 | (defvar makefile-need-target-pickup t) | |
737 | (defvar makefile-need-macro-pickup t) | |
72c0ae01 ER |
738 | |
739 | (defvar makefile-mode-hook '()) | |
740 | ||
308a2860 RS |
741 | ;; Each element looks like '("GNU MAKE FUNCTION" "ARG" "ARG" ... ) |
742 | ;; Each "ARG" is used as a prompt for a required argument. | |
72c0ae01 | 743 | (defconst makefile-gnumake-functions-alist |
72c0ae01 ER |
744 | '( |
745 | ;; Text functions | |
746 | ("subst" "From" "To" "In") | |
747 | ("patsubst" "Pattern" "Replacement" "In") | |
748 | ("strip" "Text") | |
749 | ("findstring" "Find what" "In") | |
750 | ("filter" "Pattern" "Text") | |
751 | ("filter-out" "Pattern" "Text") | |
752 | ("sort" "List") | |
753 | ;; Filename functions | |
754 | ("dir" "Names") | |
755 | ("notdir" "Names") | |
756 | ("suffix" "Names") | |
757 | ("basename" "Names") | |
e1775344 | 758 | ("addprefix" "Prefix" "Names") |
72c0ae01 ER |
759 | ("addsuffix" "Suffix" "Names") |
760 | ("join" "List 1" "List 2") | |
761 | ("word" "Index" "Text") | |
762 | ("words" "Text") | |
763 | ("firstword" "Text") | |
764 | ("wildcard" "Pattern") | |
765 | ;; Misc functions | |
766 | ("foreach" "Variable" "List" "Text") | |
767 | ("origin" "Variable") | |
308a2860 | 768 | ("shell" "Command"))) |
72c0ae01 ER |
769 | |
770 | ||
771 | ;;; ------------------------------------------------------------ | |
772 | ;;; The mode function itself. | |
773 | ;;; ------------------------------------------------------------ | |
774 | ||
5c2946c7 | 775 | ;;;###autoload |
72c0ae01 | 776 | (defun makefile-mode () |
9c859203 DP |
777 | "Major mode for editing standard Makefiles. |
778 | ||
779 | If you are editing a file for a different make, try one of the | |
780 | variants `makefile-automake-mode', `makefile-gmake-mode', | |
73290fbd EZ |
781 | `makefile-makepp-mode', `makefile-bsdmake-mode' or, |
782 | `makefile-imake-mode'. All but the last should be correctly | |
783 | chosen based on the file name, except if it is *.mk. This | |
784 | function ends by invoking the function(s) `makefile-mode-hook'. | |
72c0ae01 | 785 | |
92984345 DP |
786 | It is strongly recommended to use `font-lock-mode', because that |
787 | provides additional parsing information. This is used for | |
788 | example to see that a rule action `echo foo: bar' is a not rule | |
789 | dependency, despite the colon. | |
790 | ||
72c0ae01 ER |
791 | \\{makefile-mode-map} |
792 | ||
793 | In the browser, use the following keys: | |
794 | ||
795 | \\{makefile-browser-map} | |
796 | ||
bd0e4eb1 | 797 | Makefile mode can be configured by modifying the following variables: |
72c0ae01 | 798 | |
debe2de2 | 799 | `makefile-browser-buffer-name': |
72c0ae01 ER |
800 | Name of the macro- and target browser buffer. |
801 | ||
debe2de2 | 802 | `makefile-target-colon': |
72c0ae01 | 803 | The string that gets appended to all target names |
bd0e4eb1 | 804 | inserted by `makefile-insert-target'. |
72c0ae01 ER |
805 | \":\" or \"::\" are quite common values. |
806 | ||
debe2de2 | 807 | `makefile-macro-assign': |
72c0ae01 | 808 | The string that gets appended to all macro names |
bd0e4eb1 | 809 | inserted by `makefile-insert-macro'. |
72c0ae01 | 810 | The normal value should be \" = \", since this is what |
a564ebfc | 811 | standard make expects. However, newer makes such as dmake |
72c0ae01 ER |
812 | allow a larger variety of different macro assignments, so you |
813 | might prefer to use \" += \" or \" := \" . | |
814 | ||
debe2de2 | 815 | `makefile-tab-after-target-colon': |
72c0ae01 ER |
816 | If you want a TAB (instead of a space) to be appended after the |
817 | target colon, then set this to a non-nil value. | |
818 | ||
debe2de2 | 819 | `makefile-browser-leftmost-column': |
72c0ae01 ER |
820 | Number of blanks to the left of the browser selection mark. |
821 | ||
debe2de2 | 822 | `makefile-browser-cursor-column': |
72c0ae01 ER |
823 | Column in which the cursor is positioned when it moves |
824 | up or down in the browser. | |
825 | ||
debe2de2 | 826 | `makefile-browser-selected-mark': |
72c0ae01 ER |
827 | String used to mark selected entries in the browser. |
828 | ||
debe2de2 | 829 | `makefile-browser-unselected-mark': |
72c0ae01 ER |
830 | String used to mark unselected entries in the browser. |
831 | ||
debe2de2 | 832 | `makefile-browser-auto-advance-after-selection-p': |
72c0ae01 ER |
833 | If this variable is set to a non-nil value the cursor |
834 | will automagically advance to the next line after an item | |
835 | has been selected in the browser. | |
836 | ||
debe2de2 | 837 | `makefile-pickup-everything-picks-up-filenames-p': |
72c0ae01 | 838 | If this variable is set to a non-nil value then |
bd0e4eb1 | 839 | `makefile-pickup-everything' also picks up filenames as targets |
b20a44dc | 840 | (i.e. it calls `makefile-pickup-filenames-as-targets'), otherwise |
72c0ae01 ER |
841 | filenames are omitted. |
842 | ||
e006b3cd | 843 | `makefile-cleanup-continuations': |
a564ebfc | 844 | If this variable is set to a non-nil value then Makefile mode |
72c0ae01 ER |
845 | will assure that no line in the file ends with a backslash |
846 | (the continuation character) followed by any whitespace. | |
847 | This is done by silently removing the trailing whitespace, leaving | |
848 | the backslash itself intact. | |
a564ebfc | 849 | IMPORTANT: Please note that enabling this option causes Makefile mode |
bd0e4eb1 | 850 | to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\". |
72c0ae01 | 851 | |
debe2de2 | 852 | `makefile-browser-hook': |
72c0ae01 | 853 | A function or list of functions to be called just before the |
9e9bf716 | 854 | browser is entered. This is executed in the makefile buffer. |
72c0ae01 | 855 | |
debe2de2 | 856 | `makefile-special-targets-list': |
72c0ae01 | 857 | List of special targets. You will be offered to complete |
bd0e4eb1 RS |
858 | on one of those in the minibuffer whenever you enter a `.'. |
859 | at the beginning of a line in Makefile mode." | |
6783b1ce | 860 | |
72c0ae01 ER |
861 | (interactive) |
862 | (kill-all-local-variables) | |
e006b3cd SM |
863 | (add-hook 'write-file-functions |
864 | 'makefile-warn-suspicious-lines nil t) | |
a11e2800 RS |
865 | (add-hook 'write-file-functions |
866 | 'makefile-warn-continuations nil t) | |
e006b3cd SM |
867 | (add-hook 'write-file-functions |
868 | 'makefile-cleanup-continuations nil t) | |
b8ca7cc3 RS |
869 | (make-local-variable 'makefile-target-table) |
870 | (make-local-variable 'makefile-macro-table) | |
871 | (make-local-variable 'makefile-has-prereqs) | |
872 | (make-local-variable 'makefile-need-target-pickup) | |
873 | (make-local-variable 'makefile-need-macro-pickup) | |
6783b1ce RS |
874 | |
875 | ;; Font lock. | |
af4b1991 | 876 | (make-local-variable 'font-lock-defaults) |
c7ca58df EZ |
877 | (setq font-lock-defaults |
878 | ;; SYNTAX-BEGIN set to backward-paragraph to avoid slow-down | |
879 | ;; near the end of a large buffer, due to parse-partial-sexp's | |
880 | ;; trying to parse all the way till the beginning of buffer. | |
0b51ba8a JB |
881 | '(makefile-font-lock-keywords |
882 | nil nil | |
883 | ((?$ . ".")) | |
884 | backward-paragraph | |
472e1031 SM |
885 | (font-lock-syntactic-keywords |
886 | . makefile-font-lock-syntactic-keywords))) | |
6783b1ce RS |
887 | |
888 | ;; Add-log. | |
889 | (make-local-variable 'add-log-current-defun-function) | |
890 | (setq add-log-current-defun-function 'makefile-add-log-defun) | |
891 | ||
892 | ;; Imenu. | |
db85e69c RS |
893 | (make-local-variable 'imenu-generic-expression) |
894 | (setq imenu-generic-expression makefile-imenu-generic-expression) | |
6783b1ce | 895 | |
3b114205 RS |
896 | ;; Dabbrev. |
897 | (make-local-variable 'dabbrev-abbrev-skip-leading-regexp) | |
898 | (setq dabbrev-abbrev-skip-leading-regexp "\\$") | |
899 | ||
9ffb4859 GM |
900 | ;; Other abbrevs. |
901 | (setq local-abbrev-table makefile-mode-abbrev-table) | |
902 | ||
dfa9e6fc RS |
903 | ;; Filling. |
904 | (make-local-variable 'fill-paragraph-function) | |
905 | (setq fill-paragraph-function 'makefile-fill-paragraph) | |
906 | ||
6783b1ce | 907 | ;; Comment stuff. |
531b2a28 | 908 | (make-local-variable 'comment-start) |
72c0ae01 | 909 | (setq comment-start "#") |
6783b1ce | 910 | (make-local-variable 'comment-end) |
72c0ae01 | 911 | (setq comment-end "") |
6783b1ce RS |
912 | (make-local-variable 'comment-start-skip) |
913 | (setq comment-start-skip "#+[ \t]*") | |
914 | ||
debe2de2 SM |
915 | ;; Make sure TAB really inserts \t. |
916 | (set (make-local-variable 'indent-line-function) 'indent-to-left-margin) | |
917 | ||
72c0ae01 ER |
918 | ;; become the current major mode |
919 | (setq major-mode 'makefile-mode) | |
6783b1ce RS |
920 | (setq mode-name "Makefile") |
921 | ||
922 | ;; Activate keymap and syntax table. | |
72c0ae01 ER |
923 | (use-local-map makefile-mode-map) |
924 | (set-syntax-table makefile-mode-syntax-table) | |
6783b1ce RS |
925 | |
926 | ;; Real TABs are important in makefiles | |
927 | (setq indent-tabs-mode t) | |
e1c45277 | 928 | (run-mode-hooks 'makefile-mode-hook)) |
6783b1ce | 929 | |
9c859203 DP |
930 | ;; These should do more than just differentiate font-lock. |
931 | ;;;###autoload | |
932 | (define-derived-mode makefile-automake-mode makefile-mode "Makefile.am" | |
933 | "An adapted `makefile-mode' that knows about automake." | |
934 | (setq font-lock-defaults | |
935 | `(makefile-automake-font-lock-keywords ,@(cdr font-lock-defaults)))) | |
936 | ||
937 | ;;;###autoload | |
938 | (define-derived-mode makefile-gmake-mode makefile-mode "GNUmakefile" | |
939 | "An adapted `makefile-mode' that knows about gmake." | |
940 | (setq font-lock-defaults | |
941 | `(makefile-gmake-font-lock-keywords ,@(cdr font-lock-defaults)))) | |
942 | ||
943 | ;;;###autoload | |
944 | (define-derived-mode makefile-makepp-mode makefile-mode "Makeppfile" | |
945 | "An adapted `makefile-mode' that knows about makepp." | |
30edba6e DP |
946 | (set (make-local-variable 'makefile-rule-action-regex) |
947 | makefile-makepp-rule-action-regex) | |
9c859203 | 948 | (setq font-lock-defaults |
774cd454 DP |
949 | `(makefile-makepp-font-lock-keywords ,@(cdr font-lock-defaults)) |
950 | imenu-generic-expression | |
951 | `(("Functions" "^[ \t]*\\(?:make\\)?sub[ \t]+\\([A-Za-z0-9_]+\\)" 1) | |
952 | ,@imenu-generic-expression))) | |
9c859203 DP |
953 | |
954 | ;;;###autoload | |
955 | (define-derived-mode makefile-bsdmake-mode makefile-mode "BSDmakefile" | |
956 | "An adapted `makefile-mode' that knows about BSD make." | |
92984345 | 957 | (set (make-local-variable 'makefile-dependency-regex) |
30edba6e | 958 | makefile-bsdmake-dependency-regex) |
0b11ce59 | 959 | (set (make-local-variable 'makefile-dependency-skip) "^:!") |
92984345 | 960 | (set (make-local-variable 'makefile-rule-action-regex) |
30edba6e | 961 | makefile-bsdmake-rule-action-regex) |
9c859203 | 962 | (setq font-lock-defaults |
774cd454 | 963 | `(makefile-bsdmake-font-lock-keywords ,@(cdr font-lock-defaults)))) |
9c859203 | 964 | |
3968c89f MY |
965 | ;;;###autoload |
966 | (define-derived-mode makefile-imake-mode makefile-mode "Imakefile" | |
967 | "An adapted `makefile-mode' that knows about imake." | |
968 | :syntax-table makefile-imake-mode-syntax-table | |
969 | (let ((base `(makefile-imake-font-lock-keywords ,@(cdr font-lock-defaults))) | |
970 | new) | |
971 | ;; Remove `font-lock-syntactic-keywords' entry from font-lock-defaults. | |
972 | (mapc (lambda (elt) | |
973 | (unless (and (consp elt) | |
974 | (eq (car elt) 'font-lock-syntactic-keywords)) | |
975 | (setq new (cons elt new)))) | |
976 | base) | |
977 | (setq font-lock-defaults (nreverse new)))) | |
978 | ||
6783b1ce RS |
979 | \f |
980 | ||
981 | ;;; Motion code. | |
72c0ae01 | 982 | |
72c0ae01 | 983 | (defun makefile-next-dependency () |
bd0e4eb1 | 984 | "Move point to the beginning of the next dependency line." |
72c0ae01 ER |
985 | (interactive) |
986 | (let ((here (point))) | |
987 | (end-of-line) | |
0b11ce59 | 988 | (if (makefile-match-dependency nil) |
72c0ae01 ER |
989 | (progn (beginning-of-line) t) ; indicate success |
990 | (goto-char here) nil))) | |
6783b1ce | 991 | |
72c0ae01 | 992 | (defun makefile-previous-dependency () |
bd0e4eb1 | 993 | "Move point to the beginning of the previous dependency line." |
72c0ae01 | 994 | (interactive) |
0b11ce59 | 995 | (let ((pt (point))) |
72c0ae01 | 996 | (beginning-of-line) |
0b11ce59 DP |
997 | ;; makefile-match-dependency done backwards: |
998 | (catch 'found | |
dfa89b5d DP |
999 | (while (progn (skip-chars-backward makefile-dependency-skip) |
1000 | (not (bobp))) | |
5c8b5442 DP |
1001 | (or (prog1 (eq (char-after) ?=) |
1002 | (backward-char)) | |
1003 | (get-text-property (point) 'face) | |
0b11ce59 | 1004 | (beginning-of-line) |
602dc0da DP |
1005 | (if (> (point) (+ (point-min) 2)) |
1006 | (eq (char-before (1- (point))) ?\\)) | |
0b11ce59 DP |
1007 | (if (looking-at makefile-dependency-regex) |
1008 | (throw 'found t)))) | |
1009 | (goto-char pt) | |
1010 | nil))) | |
72c0ae01 | 1011 | |
6783b1ce | 1012 | \f |
72c0ae01 | 1013 | |
6783b1ce | 1014 | ;;; Electric keys. Blech. |
9e9bf716 | 1015 | |
6783b1ce RS |
1016 | (defun makefile-electric-dot (arg) |
1017 | "Prompt for the name of a special target to insert. | |
1018 | Only does electric insertion at beginning of line. | |
1019 | Anywhere else just self-inserts." | |
1020 | (interactive "p") | |
72c0ae01 ER |
1021 | (if (bolp) |
1022 | (makefile-insert-special-target) | |
6783b1ce | 1023 | (self-insert-command arg))) |
72c0ae01 | 1024 | |
72c0ae01 | 1025 | (defun makefile-insert-special-target () |
ac282af8 | 1026 | "Prompt for and insert a special target name. |
6783b1ce | 1027 | Uses `makefile-special-targets' list." |
72c0ae01 | 1028 | (interactive) |
9e9bf716 | 1029 | (makefile-pickup-targets) |
6783b1ce RS |
1030 | (let ((special-target |
1031 | (completing-read "Special target: " | |
1032 | makefile-special-targets-list nil nil nil))) | |
72c0ae01 ER |
1033 | (if (zerop (length special-target)) |
1034 | () | |
6783b1ce | 1035 | (insert "." special-target ":") |
72c0ae01 ER |
1036 | (makefile-forward-after-target-colon)))) |
1037 | ||
6783b1ce RS |
1038 | (defun makefile-electric-equal (arg) |
1039 | "Prompt for name of a macro to insert. | |
1040 | Only does prompting if point is at beginning of line. | |
1041 | Anywhere else just self-inserts." | |
1042 | (interactive "p") | |
9e9bf716 | 1043 | (makefile-pickup-macros) |
72c0ae01 ER |
1044 | (if (bolp) |
1045 | (call-interactively 'makefile-insert-macro) | |
6783b1ce | 1046 | (self-insert-command arg))) |
72c0ae01 ER |
1047 | |
1048 | (defun makefile-insert-macro (macro-name) | |
1049 | "Prepare definition of a new macro." | |
1050 | (interactive "sMacro Name: ") | |
9e9bf716 | 1051 | (makefile-pickup-macros) |
72c0ae01 ER |
1052 | (if (not (zerop (length macro-name))) |
1053 | (progn | |
1054 | (beginning-of-line) | |
6783b1ce | 1055 | (insert macro-name makefile-macro-assign) |
9e9bf716 | 1056 | (setq makefile-need-macro-pickup t) |
72c0ae01 ER |
1057 | (makefile-remember-macro macro-name)))) |
1058 | ||
72c0ae01 | 1059 | (defun makefile-insert-macro-ref (macro-name) |
bd0e4eb1 | 1060 | "Complete on a list of known macros, then insert complete ref at point." |
72c0ae01 ER |
1061 | (interactive |
1062 | (list | |
9e9bf716 ER |
1063 | (progn |
1064 | (makefile-pickup-macros) | |
1065 | (completing-read "Refer to macro: " makefile-macro-table nil nil nil)))) | |
6783b1ce | 1066 | (makefile-do-macro-insertion macro-name)) |
72c0ae01 | 1067 | |
72c0ae01 ER |
1068 | (defun makefile-insert-target (target-name) |
1069 | "Prepare definition of a new target (dependency line)." | |
1070 | (interactive "sTarget: ") | |
1071 | (if (not (zerop (length target-name))) | |
1072 | (progn | |
1073 | (beginning-of-line) | |
6783b1ce | 1074 | (insert target-name makefile-target-colon) |
72c0ae01 ER |
1075 | (makefile-forward-after-target-colon) |
1076 | (end-of-line) | |
9e9bf716 | 1077 | (setq makefile-need-target-pickup t) |
72c0ae01 ER |
1078 | (makefile-remember-target target-name)))) |
1079 | ||
72c0ae01 | 1080 | (defun makefile-insert-target-ref (target-name) |
a564ebfc | 1081 | "Complete on a list of known targets, then insert TARGET-NAME at point." |
72c0ae01 ER |
1082 | (interactive |
1083 | (list | |
0c5b5a13 | 1084 | (progn |
9e9bf716 ER |
1085 | (makefile-pickup-targets) |
1086 | (completing-read "Refer to target: " makefile-target-table nil nil nil)))) | |
72c0ae01 | 1087 | (if (not (zerop (length target-name))) |
6783b1ce | 1088 | (insert target-name " "))) |
72c0ae01 | 1089 | |
6783b1ce RS |
1090 | (defun makefile-electric-colon (arg) |
1091 | "Prompt for name of new target. | |
1092 | Prompting only happens at beginning of line. | |
1093 | Anywhere else just self-inserts." | |
1094 | (interactive "p") | |
72c0ae01 ER |
1095 | (if (bolp) |
1096 | (call-interactively 'makefile-insert-target) | |
6783b1ce RS |
1097 | (self-insert-command arg))) |
1098 | ||
1099 | \f | |
72c0ae01 | 1100 | |
72c0ae01 ER |
1101 | ;;; ------------------------------------------------------------ |
1102 | ;;; Extracting targets and macros from an existing makefile | |
1103 | ;;; ------------------------------------------------------------ | |
1104 | ||
1105 | (defun makefile-pickup-targets () | |
308a2860 | 1106 | "Notice names of all target definitions in Makefile." |
72c0ae01 | 1107 | (interactive) |
dfa89b5d DP |
1108 | (when makefile-need-target-pickup |
1109 | (setq makefile-need-target-pickup nil | |
1110 | makefile-target-table nil | |
1111 | makefile-has-prereqs nil) | |
9e9bf716 ER |
1112 | (save-excursion |
1113 | (goto-char (point-min)) | |
92984345 | 1114 | (while (makefile-match-dependency nil) |
dfa89b5d DP |
1115 | (goto-char (match-beginning 1)) |
1116 | (while (let ((target-name | |
1117 | (buffer-substring-no-properties (point) | |
1118 | (progn | |
1119 | (skip-chars-forward "^ \t:#") | |
1120 | (point)))) | |
9e9bf716 ER |
1121 | (has-prereqs |
1122 | (not (looking-at ":[ \t]*$")))) | |
dfa89b5d DP |
1123 | (if (makefile-remember-target target-name has-prereqs) |
1124 | (message "Picked up target \"%s\" from line %d" | |
1125 | target-name (line-number-at-pos))) | |
1126 | (skip-chars-forward " \t") | |
1127 | (not (or (eolp) (eq (char-after) ?:))))) | |
1128 | (forward-line))) | |
1129 | (message "Read targets OK."))) | |
72c0ae01 | 1130 | |
72c0ae01 | 1131 | (defun makefile-pickup-macros () |
308a2860 | 1132 | "Notice names of all macro definitions in Makefile." |
72c0ae01 | 1133 | (interactive) |
dfa89b5d DP |
1134 | (when makefile-need-macro-pickup |
1135 | (setq makefile-need-macro-pickup nil | |
1136 | makefile-macro-table nil) | |
9e9bf716 ER |
1137 | (save-excursion |
1138 | (goto-char (point-min)) | |
e006b3cd | 1139 | (while (re-search-forward makefile-macroassign-regex nil t) |
dfa89b5d DP |
1140 | (goto-char (match-beginning 1)) |
1141 | (let ((macro-name (buffer-substring-no-properties (point) | |
1142 | (progn | |
1143 | (skip-chars-forward "^ \t:#=*") | |
1144 | (point))))) | |
1145 | (if (makefile-remember-macro macro-name) | |
1146 | (message "Picked up macro \"%s\" from line %d" | |
1147 | macro-name (line-number-at-pos)))) | |
1148 | (forward-line))) | |
9e9bf716 | 1149 | (message "Read macros OK."))) |
72c0ae01 | 1150 | |
6783b1ce | 1151 | (defun makefile-pickup-everything (arg) |
308a2860 | 1152 | "Notice names of all macros and targets in Makefile. |
6783b1ce RS |
1153 | Prefix arg means force pickups to be redone." |
1154 | (interactive "P") | |
1155 | (if arg | |
dfa89b5d DP |
1156 | (setq makefile-need-target-pickup t |
1157 | makefile-need-macro-pickup t)) | |
72c0ae01 ER |
1158 | (makefile-pickup-macros) |
1159 | (makefile-pickup-targets) | |
1160 | (if makefile-pickup-everything-picks-up-filenames-p | |
1161 | (makefile-pickup-filenames-as-targets))) | |
1162 | ||
72c0ae01 | 1163 | (defun makefile-pickup-filenames-as-targets () |
308a2860 RS |
1164 | "Scan the current directory for filenames to use as targets. |
1165 | Checks each filename against `makefile-ignored-files-in-pickup-regex' | |
1166 | and adds all qualifying names to the list of known targets." | |
72c0ae01 | 1167 | (interactive) |
dfa89b5d DP |
1168 | (mapc (lambda (name) |
1169 | (or (file-directory-p name) | |
1170 | (string-match makefile-ignored-files-in-pickup-regex name) | |
1171 | (if (makefile-remember-target name) | |
1172 | (message "Picked up file \"%s\" as target" name)))) | |
1173 | (file-name-all-completions "" (or (file-name-directory (buffer-file-name)) "")))) | |
72c0ae01 | 1174 | |
6783b1ce RS |
1175 | \f |
1176 | ||
1177 | ;;; Completion. | |
1178 | ||
1179 | (defun makefile-complete () | |
1180 | "Perform completion on Makefile construct preceding point. | |
1181 | Can complete variable and target names. | |
1182 | The context determines which are considered." | |
1183 | (interactive) | |
1184 | (let* ((beg (save-excursion | |
1185 | (skip-chars-backward "^$(){}:#= \t\n") | |
1186 | (point))) | |
1187 | (try (buffer-substring beg (point))) | |
1188 | (do-macros nil) | |
1189 | (paren nil)) | |
1190 | ||
1191 | (save-excursion | |
1192 | (goto-char beg) | |
1193 | (let ((pc (preceding-char))) | |
1194 | (cond | |
1195 | ;; Beginning of line means anything. | |
1196 | ((bolp) | |
1197 | ()) | |
1198 | ||
1199 | ;; Preceding "$" means macros only. | |
1200 | ((= pc ?$) | |
1201 | (setq do-macros t)) | |
1202 | ||
1203 | ;; Preceding "$(" or "${" means macros only. | |
1204 | ((and (or (= pc ?{) | |
1205 | (= pc ?\()) | |
1206 | (progn | |
1207 | (setq paren pc) | |
1208 | (backward-char) | |
1209 | (and (not (bolp)) | |
1210 | (= (preceding-char) ?$)))) | |
1211 | (setq do-macros t))))) | |
1212 | ||
1213 | ;; Try completion. | |
1214 | (let* ((table (append (if do-macros | |
1215 | '() | |
1216 | makefile-target-table) | |
1217 | makefile-macro-table)) | |
1218 | (completion (try-completion try table))) | |
1219 | (cond | |
1220 | ;; Exact match, so insert closing paren or colon. | |
1221 | ((eq completion t) | |
1222 | (insert (if do-macros | |
1223 | (if (eq paren ?{) | |
1224 | ?} | |
1225 | ?\)) | |
1226 | (if (save-excursion | |
1227 | (goto-char beg) | |
1228 | (bolp)) | |
1229 | ":" | |
1230 | " ")))) | |
1231 | ||
1232 | ;; No match. | |
1233 | ((null completion) | |
1234 | (message "Can't find completion for \"%s\"" try) | |
1235 | (ding)) | |
1236 | ||
1237 | ;; Partial completion. | |
1238 | ((not (string= try completion)) | |
1239 | ;; FIXME it would be nice to supply the closing paren if an | |
1240 | ;; exact, unambiguous match were found. That is not possible | |
1241 | ;; right now. Ditto closing ":" for targets. | |
1242 | (delete-region beg (point)) | |
1243 | ||
1244 | ;; DO-MACROS means doing macros only. If not that, then check | |
1245 | ;; to see if this completion is a macro. Special insertion | |
1246 | ;; must be done for macros. | |
1247 | (if (or do-macros | |
1248 | (assoc completion makefile-macro-table)) | |
1249 | (let ((makefile-use-curly-braces-for-macros-p | |
1250 | (or (eq paren ?{) | |
1251 | makefile-use-curly-braces-for-macros-p))) | |
1252 | (delete-backward-char 2) | |
1253 | (makefile-do-macro-insertion completion) | |
1254 | (delete-backward-char 1)) | |
1255 | ||
1256 | ;; Just insert targets. | |
1257 | (insert completion))) | |
1258 | ||
1259 | ;; Can't complete any more, so make completion list. FIXME | |
1260 | ;; this doesn't do the right thing when the completion is | |
1261 | ;; actually inserted. I don't think there is an easy way to do | |
1262 | ;; that. | |
1263 | (t | |
1264 | (message "Making completion list...") | |
1265 | (let ((list (all-completions try table))) | |
1266 | (with-output-to-temp-buffer "*Completions*" | |
f5fab556 | 1267 | (display-completion-list list try))) |
6783b1ce RS |
1268 | (message "Making completion list...done")))))) |
1269 | ||
1270 | \f | |
1271 | ||
308a2860 RS |
1272 | ;; Backslashification. Stolen from cc-mode.el. |
1273 | ||
dfa9e6fc RS |
1274 | (defun makefile-backslash-region (from to delete-flag) |
1275 | "Insert, align, or delete end-of-line backslashes on the lines in the region. | |
1276 | With no argument, inserts backslashes and aligns existing backslashes. | |
1277 | With an argument, deletes the backslashes. | |
1278 | ||
a564ebfc | 1279 | This function does not modify the last line of the region if the region ends |
dfa9e6fc RS |
1280 | right at the start of the following line; it does not modify blank lines |
1281 | at the start of the region. So you can put the region around an entire macro | |
1282 | definition and conveniently use this command." | |
308a2860 RS |
1283 | (interactive "r\nP") |
1284 | (save-excursion | |
dfa9e6fc RS |
1285 | (goto-char from) |
1286 | (let ((column makefile-backslash-column) | |
1287 | (endmark (make-marker))) | |
1288 | (move-marker endmark to) | |
1289 | ;; Compute the smallest column number past the ends of all the lines. | |
1290 | (if makefile-backslash-align | |
1291 | (progn | |
1292 | (if (not delete-flag) | |
1293 | (while (< (point) to) | |
1294 | (end-of-line) | |
1295 | (if (= (preceding-char) ?\\) | |
1296 | (progn (forward-char -1) | |
1297 | (skip-chars-backward " \t"))) | |
1298 | (setq column (max column (1+ (current-column)))) | |
1299 | (forward-line 1))) | |
1300 | ;; Adjust upward to a tab column, if that doesn't push | |
1301 | ;; past the margin. | |
1302 | (if (> (% column tab-width) 0) | |
1303 | (let ((adjusted (* (/ (+ column tab-width -1) tab-width) | |
1304 | tab-width))) | |
1305 | (if (< adjusted (window-width)) | |
1306 | (setq column adjusted)))))) | |
1307 | ;; Don't modify blank lines at start of region. | |
1308 | (goto-char from) | |
1309 | (while (and (< (point) endmark) (eolp)) | |
1310 | (forward-line 1)) | |
1311 | ;; Add or remove backslashes on all the lines. | |
1312 | (while (and (< (point) endmark) | |
1313 | ;; Don't backslashify the last line | |
1314 | ;; if the region ends right at the start of the next line. | |
1315 | (save-excursion | |
1316 | (forward-line 1) | |
1317 | (< (point) endmark))) | |
1318 | (if (not delete-flag) | |
1319 | (makefile-append-backslash column) | |
1320 | (makefile-delete-backslash)) | |
1321 | (forward-line 1)) | |
1322 | (move-marker endmark nil)))) | |
1323 | ||
1324 | (defun makefile-append-backslash (column) | |
1325 | (end-of-line) | |
1326 | ;; Note that "\\\\" is needed to get one backslash. | |
1327 | (if (= (preceding-char) ?\\) | |
1328 | (progn (forward-char -1) | |
1329 | (delete-horizontal-space) | |
1330 | (indent-to column (if makefile-backslash-align nil 1))) | |
1331 | (indent-to column (if makefile-backslash-align nil 1)) | |
1332 | (insert "\\"))) | |
1333 | ||
1334 | (defun makefile-delete-backslash () | |
1335 | (end-of-line) | |
1336 | (or (bolp) | |
1337 | (progn | |
1338 | (forward-char -1) | |
1339 | (if (looking-at "\\\\") | |
1340 | (delete-region (1+ (point)) | |
1341 | (progn (skip-chars-backward " \t") (point))))))) | |
1342 | ||
1343 | \f | |
1344 | ||
1345 | ;; Filling | |
1346 | ||
1347 | (defun makefile-fill-paragraph (arg) | |
1348 | ;; Fill comments, backslashed lines, and variable definitions | |
1349 | ;; specially. | |
1350 | (save-excursion | |
1351 | (beginning-of-line) | |
1352 | (cond | |
5e01f1ca | 1353 | ((looking-at "^[ \t]*#+\\s-*") |
c5301b5c SM |
1354 | ;; Found a comment. Return nil to let normal filling take place. |
1355 | nil) | |
dfa9e6fc RS |
1356 | |
1357 | ;; Must look for backslashed-region before looking for variable | |
1358 | ;; assignment. | |
e006b3cd SM |
1359 | ((or (eq (char-before (line-end-position 1)) ?\\) |
1360 | (eq (char-before (line-end-position 0)) ?\\)) | |
dfa9e6fc RS |
1361 | ;; A backslash region. Find beginning and end, remove |
1362 | ;; backslashes, fill, and then reapply backslahes. | |
1363 | (end-of-line) | |
1364 | (let ((beginning | |
1365 | (save-excursion | |
1366 | (end-of-line 0) | |
1367 | (while (= (preceding-char) ?\\) | |
1368 | (end-of-line 0)) | |
1369 | (forward-char) | |
1370 | (point))) | |
1371 | (end | |
1372 | (save-excursion | |
1373 | (while (= (preceding-char) ?\\) | |
1374 | (end-of-line 2)) | |
1375 | (point)))) | |
1376 | (save-restriction | |
1377 | (narrow-to-region beginning end) | |
1378 | (makefile-backslash-region (point-min) (point-max) t) | |
1379 | (let ((fill-paragraph-function nil)) | |
1380 | (fill-paragraph nil)) | |
1381 | (makefile-backslash-region (point-min) (point-max) nil) | |
1382 | (goto-char (point-max)) | |
1383 | (if (< (skip-chars-backward "\n") 0) | |
c5301b5c SM |
1384 | (delete-region (point) (point-max))))) |
1385 | ;; Return non-nil to indicate it's been filled. | |
1386 | t) | |
dfa9e6fc RS |
1387 | |
1388 | ((looking-at makefile-macroassign-regex) | |
1389 | ;; Have a macro assign. Fill just this line, and then backslash | |
1390 | ;; resulting region. | |
308a2860 | 1391 | (save-restriction |
debe2de2 | 1392 | (narrow-to-region (point) (line-beginning-position 2)) |
dfa9e6fc RS |
1393 | (let ((fill-paragraph-function nil)) |
1394 | (fill-paragraph nil)) | |
c5301b5c SM |
1395 | (makefile-backslash-region (point-min) (point-max) nil)) |
1396 | ;; Return non-nil to indicate it's been filled. | |
1397 | t) | |
dfa9e6fc | 1398 | |
c5301b5c SM |
1399 | (t |
1400 | ;; Return non-nil so we don't fill anything else. | |
1401 | t)))) | |
308a2860 RS |
1402 | |
1403 | \f | |
1404 | ||
72c0ae01 | 1405 | ;;; ------------------------------------------------------------ |
6783b1ce | 1406 | ;;; Browser mode. |
72c0ae01 ER |
1407 | ;;; ------------------------------------------------------------ |
1408 | ||
72c0ae01 ER |
1409 | (defun makefile-browser-format-target-line (target selected) |
1410 | (format | |
1411 | (concat (make-string makefile-browser-leftmost-column ?\ ) | |
1412 | (if selected | |
1413 | makefile-browser-selected-mark | |
1414 | makefile-browser-unselected-mark) | |
1415 | "%s%s") | |
1416 | target makefile-target-colon)) | |
1417 | ||
1418 | (defun makefile-browser-format-macro-line (macro selected) | |
1419 | (format | |
1420 | (concat (make-string makefile-browser-leftmost-column ?\ ) | |
1421 | (if selected | |
1422 | makefile-browser-selected-mark | |
1423 | makefile-browser-unselected-mark) | |
1424 | (makefile-format-macro-ref macro)))) | |
1425 | ||
1426 | (defun makefile-browser-fill (targets macros) | |
c72344c7 RS |
1427 | (let ((inhibit-read-only t)) |
1428 | (goto-char (point-min)) | |
1429 | (erase-buffer) | |
1430 | (mapconcat | |
1431 | (function | |
1432 | (lambda (item) (insert (makefile-browser-format-target-line (car item) nil) "\n"))) | |
1433 | targets | |
1434 | "") | |
1435 | (mapconcat | |
1436 | (function | |
1437 | (lambda (item) (insert (makefile-browser-format-macro-line (car item) nil) "\n"))) | |
1438 | macros | |
1439 | "") | |
1440 | (sort-lines nil (point-min) (point-max)) | |
1441 | (goto-char (1- (point-max))) | |
1442 | (delete-char 1) ; remove unnecessary newline at eob | |
1443 | (goto-char (point-min)) | |
1444 | (forward-char makefile-browser-cursor-column))) | |
72c0ae01 ER |
1445 | |
1446 | ;;; | |
1447 | ;;; Moving up and down in the browser | |
1448 | ;;; | |
1449 | ||
1450 | (defun makefile-browser-next-line () | |
1451 | "Move the browser selection cursor to the next line." | |
1452 | (interactive) | |
1453 | (if (not (makefile-last-line-p)) | |
1454 | (progn | |
1455 | (forward-line 1) | |
1456 | (forward-char makefile-browser-cursor-column)))) | |
1457 | ||
1458 | (defun makefile-browser-previous-line () | |
1459 | "Move the browser selection cursor to the previous line." | |
1460 | (interactive) | |
1461 | (if (not (makefile-first-line-p)) | |
1462 | (progn | |
1463 | (forward-line -1) | |
1464 | (forward-char makefile-browser-cursor-column)))) | |
1465 | ||
1466 | ;;; | |
1467 | ;;; Quitting the browser (returns to client buffer) | |
1468 | ;;; | |
1469 | ||
1470 | (defun makefile-browser-quit () | |
308a2860 | 1471 | "Leave the browser and return to the makefile buffer." |
72c0ae01 ER |
1472 | (interactive) |
1473 | (let ((my-client makefile-browser-client)) | |
1474 | (setq makefile-browser-client nil) ; we quitted, so NO client! | |
1475 | (set-buffer-modified-p nil) | |
59047653 | 1476 | (quit-window t) |
72c0ae01 ER |
1477 | (pop-to-buffer my-client))) |
1478 | ||
1479 | ;;; | |
1480 | ;;; Toggle state of a browser item | |
1481 | ;;; | |
1482 | ||
1483 | (defun makefile-browser-toggle () | |
1484 | "Toggle the selection state of the browser item at the cursor position." | |
1485 | (interactive) | |
1486 | (let ((this-line (count-lines (point-min) (point)))) | |
1487 | (setq this-line (max 1 this-line)) | |
1488 | (makefile-browser-toggle-state-for-line this-line) | |
df1c29a0 GM |
1489 | (goto-char (point-min)) |
1490 | (forward-line (1- this-line)) | |
c72344c7 | 1491 | (let ((inhibit-read-only t)) |
df1c29a0 | 1492 | (beginning-of-line) ; redundant? |
c72344c7 RS |
1493 | (if (makefile-browser-on-macro-line-p) |
1494 | (let ((macro-name (makefile-browser-this-line-macro-name))) | |
8d3a7934 | 1495 | (delete-region (point) (progn (end-of-line) (point))) |
c72344c7 RS |
1496 | (insert |
1497 | (makefile-browser-format-macro-line | |
1498 | macro-name | |
1499 | (makefile-browser-get-state-for-line this-line)))) | |
1500 | (let ((target-name (makefile-browser-this-line-target-name))) | |
8d3a7934 | 1501 | (delete-region (point) (progn (end-of-line) (point))) |
72c0ae01 | 1502 | (insert |
c72344c7 RS |
1503 | (makefile-browser-format-target-line |
1504 | target-name | |
1505 | (makefile-browser-get-state-for-line this-line)))))) | |
72c0ae01 ER |
1506 | (beginning-of-line) |
1507 | (forward-char makefile-browser-cursor-column) | |
1508 | (if makefile-browser-auto-advance-after-selection-p | |
1509 | (makefile-browser-next-line)))) | |
1510 | ||
1511 | ;;; | |
1512 | ;;; Making insertions into the client buffer | |
1513 | ;;; | |
1514 | ||
1515 | (defun makefile-browser-insert-continuation () | |
9e9bf716 | 1516 | "Insert a makefile continuation. |
308a2860 | 1517 | In the makefile buffer, go to (end-of-line), insert a \'\\\' |
72c0ae01 | 1518 | character, insert a new blank line, go to that line and indent by one TAB. |
9e9bf716 ER |
1519 | This is most useful in the process of creating continued lines when copying |
1520 | large dependencies from the browser to the client buffer. | |
a4e104bf | 1521 | \(point) advances accordingly in the client buffer." |
72c0ae01 | 1522 | (interactive) |
debe2de2 | 1523 | (with-current-buffer makefile-browser-client |
72c0ae01 ER |
1524 | (end-of-line) |
1525 | (insert "\\\n\t"))) | |
1526 | ||
1527 | (defun makefile-browser-insert-selection () | |
308a2860 | 1528 | "Insert all selected targets and/or macros in the makefile buffer. |
bd0e4eb1 | 1529 | Insertion takes place at point." |
72c0ae01 ER |
1530 | (interactive) |
1531 | (save-excursion | |
df1c29a0 | 1532 | (goto-char (point-min)) |
72c0ae01 ER |
1533 | (let ((current-line 1)) |
1534 | (while (not (eobp)) | |
1535 | (if (makefile-browser-get-state-for-line current-line) | |
1536 | (makefile-browser-send-this-line-item)) | |
1537 | (forward-line 1) | |
1538 | (setq current-line (1+ current-line)))))) | |
1539 | ||
1540 | (defun makefile-browser-insert-selection-and-quit () | |
1541 | (interactive) | |
1542 | (makefile-browser-insert-selection) | |
1543 | (makefile-browser-quit)) | |
1544 | ||
1545 | (defun makefile-browser-send-this-line-item () | |
1546 | (if (makefile-browser-on-macro-line-p) | |
1547 | (save-excursion | |
1548 | (let ((macro-name (makefile-browser-this-line-macro-name))) | |
1549 | (set-buffer makefile-browser-client) | |
1550 | (insert (makefile-format-macro-ref macro-name) " "))) | |
1551 | (save-excursion | |
1552 | (let ((target-name (makefile-browser-this-line-target-name))) | |
1553 | (set-buffer makefile-browser-client) | |
1554 | (insert target-name " "))))) | |
1555 | ||
72c0ae01 ER |
1556 | (defun makefile-browser-start-interaction () |
1557 | (use-local-map makefile-browser-map) | |
1558 | (setq buffer-read-only t)) | |
1559 | ||
72c0ae01 ER |
1560 | (defun makefile-browse (targets macros) |
1561 | (interactive) | |
1562 | (if (zerop (+ (length targets) (length macros))) | |
1563 | (progn | |
1564 | (beep) | |
1565 | (message "No macros or targets to browse! Consider running 'makefile-pickup-everything\'")) | |
1566 | (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name))) | |
1567 | (pop-to-buffer browser-buffer) | |
72c0ae01 | 1568 | (makefile-browser-fill targets macros) |
9e9bf716 | 1569 | (shrink-window-if-larger-than-buffer) |
a7e34f79 SM |
1570 | (set (make-local-variable 'makefile-browser-selection-vector) |
1571 | (make-vector (+ (length targets) (length macros)) nil)) | |
72c0ae01 | 1572 | (makefile-browser-start-interaction)))) |
72c0ae01 ER |
1573 | |
1574 | (defun makefile-switch-to-browser () | |
1575 | (interactive) | |
1576 | (run-hooks 'makefile-browser-hook) | |
1577 | (setq makefile-browser-client (current-buffer)) | |
9e9bf716 ER |
1578 | (makefile-pickup-targets) |
1579 | (makefile-pickup-macros) | |
72c0ae01 ER |
1580 | (makefile-browse makefile-target-table makefile-macro-table)) |
1581 | ||
6783b1ce | 1582 | \f |
72c0ae01 ER |
1583 | |
1584 | ;;; ------------------------------------------------------------ | |
1585 | ;;; Up-to-date overview buffer | |
1586 | ;;; ------------------------------------------------------------ | |
1587 | ||
1588 | (defun makefile-create-up-to-date-overview () | |
9e9bf716 | 1589 | "Create a buffer containing an overview of the state of all known targets. |
72c0ae01 ER |
1590 | Known targets are targets that are explicitly defined in that makefile; |
1591 | in other words, all targets that appear on the left hand side of a | |
1592 | dependency in the makefile." | |
1593 | (interactive) | |
1594 | (if (y-or-n-p "Are you sure that the makefile being edited is consistent? ") | |
1595 | ;; | |
1596 | ;; The rest of this function operates on a temporary makefile, created by | |
1597 | ;; writing the current contents of the makefile buffer. | |
1598 | ;; | |
1599 | (let ((saved-target-table makefile-target-table) | |
1600 | (this-buffer (current-buffer)) | |
1601 | (makefile-up-to-date-buffer | |
1602 | (get-buffer-create makefile-up-to-date-buffer-name)) | |
1603 | (filename (makefile-save-temporary)) | |
1604 | ;; | |
1605 | ;; Forget the target table because it may contain picked-up filenames | |
1606 | ;; that are not really targets in the current makefile. | |
1607 | ;; We don't want to query these, so get a new target-table with just the | |
1608 | ;; targets that can be found in the makefile buffer. | |
1609 | ;; The 'old' target table will be restored later. | |
1610 | ;; | |
1611 | (real-targets (progn | |
72c0ae01 | 1612 | (makefile-pickup-targets) |
9e9bf716 ER |
1613 | makefile-target-table)) |
1614 | (prereqs makefile-has-prereqs) | |
1615 | ) | |
72c0ae01 ER |
1616 | |
1617 | (set-buffer makefile-up-to-date-buffer) | |
1618 | (setq buffer-read-only nil) | |
1619 | (erase-buffer) | |
9e9bf716 | 1620 | (makefile-query-targets filename real-targets prereqs) |
72c0ae01 ER |
1621 | (if (zerop (buffer-size)) ; if it did not get us anything |
1622 | (progn | |
1623 | (kill-buffer (current-buffer)) | |
1624 | (message "No overview created!"))) | |
1625 | (set-buffer this-buffer) | |
1626 | (setq makefile-target-table saved-target-table) | |
1627 | (if (get-buffer makefile-up-to-date-buffer-name) | |
1628 | (progn | |
1629 | (pop-to-buffer (get-buffer makefile-up-to-date-buffer-name)) | |
9e9bf716 | 1630 | (shrink-window-if-larger-than-buffer) |
72c0ae01 ER |
1631 | (sort-lines nil (point-min) (point-max)) |
1632 | (setq buffer-read-only t)))))) | |
72c0ae01 ER |
1633 | |
1634 | (defun makefile-save-temporary () | |
1635 | "Create a temporary file from the current makefile buffer." | |
1636 | (let ((filename (makefile-generate-temporary-filename))) | |
1637 | (write-region (point-min) (point-max) filename nil 0) | |
1638 | filename)) ; return the filename | |
1639 | ||
1640 | (defun makefile-generate-temporary-filename () | |
308a2860 | 1641 | "Create a filename suitable for use in `makefile-save-temporary'. |
72c0ae01 | 1642 | Be careful to allow brain-dead file systems (DOS, SYSV ...) to cope |
308a2860 | 1643 | with the generated name!" |
72c0ae01 ER |
1644 | (let ((my-name (user-login-name)) |
1645 | (my-uid (int-to-string (user-uid)))) | |
1646 | (concat "mktmp" | |
1647 | (if (> (length my-name) 3) | |
1648 | (substring my-name 0 3) | |
1649 | my-name) | |
1650 | "." | |
1651 | (if (> (length my-uid) 3) | |
1652 | (substring my-uid 0 3) | |
1653 | my-uid)))) | |
1654 | ||
9e9bf716 | 1655 | (defun makefile-query-targets (filename target-table prereq-list) |
bd0e4eb1 | 1656 | "Fill the up-to-date overview buffer. |
b308197b RW |
1657 | Checks each target in TARGET-TABLE using |
1658 | `makefile-query-one-target-method-function' | |
72c0ae01 ER |
1659 | and generates the overview, one line per target name." |
1660 | (insert | |
9e9bf716 ER |
1661 | (mapconcat |
1662 | (function (lambda (item) | |
1663 | (let* ((target-name (car item)) | |
1664 | (no-prereqs (not (member target-name prereq-list))) | |
a564ebfc | 1665 | (needs-rebuild (or no-prereqs |
9e9bf716 | 1666 | (funcall |
b308197b | 1667 | makefile-query-one-target-method-function |
9e9bf716 ER |
1668 | target-name |
1669 | filename)))) | |
1670 | (format "\t%s%s" | |
1671 | target-name | |
1672 | (cond (no-prereqs " .. has no prerequisites") | |
1673 | (needs-rebuild " .. NEEDS REBUILD") | |
1674 | (t " .. is up to date")))) | |
1675 | )) | |
1676 | target-table "\n")) | |
72c0ae01 ER |
1677 | (goto-char (point-min)) |
1678 | (delete-file filename)) ; remove the tmpfile | |
1679 | ||
1680 | (defun makefile-query-by-make-minus-q (target &optional filename) | |
15502042 | 1681 | (not (eq 0 |
308a2860 RS |
1682 | (call-process makefile-brave-make nil nil nil |
1683 | "-f" filename "-q" target)))) | |
72c0ae01 | 1684 | |
6783b1ce RS |
1685 | \f |
1686 | ||
72c0ae01 ER |
1687 | ;;; ------------------------------------------------------------ |
1688 | ;;; Continuation cleanup | |
1689 | ;;; ------------------------------------------------------------ | |
1690 | ||
1691 | (defun makefile-cleanup-continuations () | |
e956634f | 1692 | (if (derived-mode-p 'makefile-mode) |
e006b3cd | 1693 | (if (and makefile-cleanup-continuations |
72c0ae01 ER |
1694 | (not buffer-read-only)) |
1695 | (save-excursion | |
1696 | (goto-char (point-min)) | |
e006b3cd | 1697 | (while (re-search-forward "\\\\[ \t]+$" nil t) |
72c0ae01 ER |
1698 | (replace-match "\\" t t)))))) |
1699 | ||
b8ca7cc3 RS |
1700 | |
1701 | ;;; ------------------------------------------------------------ | |
1702 | ;;; Warn of suspicious lines | |
1703 | ;;; ------------------------------------------------------------ | |
1704 | ||
1705 | (defun makefile-warn-suspicious-lines () | |
68049bfa | 1706 | ;; Returning non-nil cancels the save operation |
e956634f | 1707 | (if (derived-mode-p 'makefile-mode) |
68049bfa SM |
1708 | (save-excursion |
1709 | (goto-char (point-min)) | |
1710 | (if (re-search-forward "^\\(\t+$\\| +\t\\)" nil t) | |
1711 | (not (y-or-n-p | |
a11e2800 RS |
1712 | (format "Suspicious line %d. Save anyway? " |
1713 | (count-lines (point-min) (point))))))))) | |
1714 | ||
1715 | (defun makefile-warn-continuations () | |
e956634f | 1716 | (if (derived-mode-p 'makefile-mode) |
a11e2800 RS |
1717 | (save-excursion |
1718 | (goto-char (point-min)) | |
5cc2d137 | 1719 | (if (re-search-forward "\\\\[ \t]+$" nil t) |
a11e2800 RS |
1720 | (not (y-or-n-p |
1721 | (format "Suspicious continuation in line %d. Save anyway? " | |
68049bfa | 1722 | (count-lines (point-min) (point))))))))) |
6783b1ce | 1723 | \f |
b8ca7cc3 | 1724 | |
72c0ae01 ER |
1725 | ;;; ------------------------------------------------------------ |
1726 | ;;; GNU make function support | |
1727 | ;;; ------------------------------------------------------------ | |
1728 | ||
1729 | (defun makefile-insert-gmake-function () | |
308a2860 RS |
1730 | "Insert a GNU make function call. |
1731 | Asks for the name of the function to use (with completion). | |
1732 | Then prompts for all required parameters." | |
72c0ae01 ER |
1733 | (interactive) |
1734 | (let* ((gm-function-name (completing-read | |
1735 | "Function: " | |
1736 | makefile-gnumake-functions-alist | |
1737 | nil t nil)) | |
1738 | (gm-function-prompts | |
1739 | (cdr (assoc gm-function-name makefile-gnumake-functions-alist)))) | |
1740 | (if (not (zerop (length gm-function-name))) | |
1741 | (insert (makefile-format-macro-ref | |
1742 | (concat gm-function-name " " | |
1743 | (makefile-prompt-for-gmake-funargs | |
1744 | gm-function-name gm-function-prompts))) | |
1745 | " ")))) | |
1746 | ||
1747 | (defun makefile-prompt-for-gmake-funargs (function-name prompt-list) | |
1748 | (mapconcat | |
1749 | (function (lambda (one-prompt) | |
308a2860 RS |
1750 | (read-string (format "[%s] %s: " function-name one-prompt) |
1751 | nil))) | |
72c0ae01 ER |
1752 | prompt-list |
1753 | ",")) | |
308a2860 | 1754 | |
6783b1ce | 1755 | \f |
72c0ae01 ER |
1756 | |
1757 | ;;; ------------------------------------------------------------ | |
1758 | ;;; Utility functions | |
1759 | ;;; ------------------------------------------------------------ | |
1760 | ||
9c859203 DP |
1761 | (defun makefile-match-function-end (end) |
1762 | "To be called as an anchored matcher by font-lock. | |
1763 | The anchor must have matched the opening parens in the first group." | |
1764 | (let ((s (match-string-no-properties 1))) | |
dc184009 GM |
1765 | ;; FIXME forward-sexp or somesuch would be better? |
1766 | (if (setq s (cond ((string= s "(") ")") | |
1767 | ((string= s "{") "}") | |
1768 | ((string= s "((") "))") | |
1769 | ((string= s "{{") "}}"))) | |
1770 | (re-search-forward (concat "\\(.*\\)[ \t]*" s) (line-end-position) t)))) | |
9c859203 | 1771 | |
0b11ce59 | 1772 | (defun makefile-match-dependency (bound) |
92984345 | 1773 | "Search for `makefile-dependency-regex' up to BOUND. |
92984345 DP |
1774 | Checks that the colon has not already been fontified, else we |
1775 | matched in a rule action." | |
1776 | (catch 'found | |
0b11ce59 | 1777 | (let ((pt (point))) |
dfa89b5d | 1778 | (while (progn (skip-chars-forward makefile-dependency-skip bound) |
774cd454 | 1779 | (< (point) (or bound (point-max)))) |
0b11ce59 | 1780 | (forward-char) |
5c8b5442 DP |
1781 | (or (eq (char-after) ?=) |
1782 | (get-text-property (1- (point)) 'face) | |
602dc0da DP |
1783 | (if (> (line-beginning-position) (+ (point-min) 2)) |
1784 | (eq (char-before (line-end-position 0)) ?\\)) | |
0b11ce59 DP |
1785 | (when (save-excursion |
1786 | (beginning-of-line) | |
1787 | (looking-at makefile-dependency-regex)) | |
dce16363 RS |
1788 | (save-excursion |
1789 | (let ((deps-end (match-end 1)) | |
1790 | (match-data (match-data))) | |
1791 | (goto-char deps-end) | |
1792 | (skip-chars-backward " \t") | |
1793 | (setq deps-end (point)) | |
1794 | (beginning-of-line) | |
1795 | (skip-chars-forward " \t") | |
1796 | ;; Alter the bounds recorded for subexp 1, | |
1797 | ;; which is what is supposed to match the targets. | |
1798 | (setcar (nthcdr 2 match-data) (point)) | |
1799 | (setcar (nthcdr 3 match-data) deps-end) | |
1800 | (store-match-data match-data))) | |
0b11ce59 DP |
1801 | (end-of-line) |
1802 | (throw 'found (point))))) | |
1803 | (goto-char pt)) | |
1804 | nil)) | |
92984345 DP |
1805 | |
1806 | (defun makefile-match-action (bound) | |
1807 | (catch 'found | |
1808 | (while (re-search-forward makefile-rule-action-regex bound t) | |
1809 | (or (eq ?\\ (char-after (- (match-beginning 0) 2))) | |
1810 | (throw 'found t))))) | |
1811 | ||
6783b1ce RS |
1812 | (defun makefile-do-macro-insertion (macro-name) |
1813 | "Insert a macro reference." | |
1814 | (if (not (zerop (length macro-name))) | |
1815 | (if (assoc macro-name makefile-runtime-macros-list) | |
1816 | (insert "$" macro-name) | |
1817 | (insert (makefile-format-macro-ref macro-name))))) | |
1818 | ||
9e9bf716 | 1819 | (defun makefile-remember-target (target-name &optional has-prereqs) |
72c0ae01 ER |
1820 | "Remember a given target if it is not already remembered for this buffer." |
1821 | (if (not (zerop (length target-name))) | |
9e9bf716 | 1822 | (progn |
72c0ae01 ER |
1823 | (if (not (assoc target-name makefile-target-table)) |
1824 | (setq makefile-target-table | |
9e9bf716 ER |
1825 | (cons (list target-name) makefile-target-table))) |
1826 | (if has-prereqs | |
1827 | (setq makefile-has-prereqs | |
1828 | (cons target-name makefile-has-prereqs)))))) | |
72c0ae01 ER |
1829 | |
1830 | (defun makefile-remember-macro (macro-name) | |
1831 | "Remember a given macro if it is not already remembered for this buffer." | |
1832 | (if (not (zerop (length macro-name))) | |
1833 | (if (not (assoc macro-name makefile-macro-table)) | |
1834 | (setq makefile-macro-table | |
1835 | (cons (list macro-name) makefile-macro-table))))) | |
1836 | ||
1837 | (defun makefile-forward-after-target-colon () | |
308a2860 RS |
1838 | "Move point forward after inserting the terminating colon of a target. |
1839 | This acts according to the value of `makefile-tab-after-target-colon'." | |
72c0ae01 ER |
1840 | (if makefile-tab-after-target-colon |
1841 | (insert "\t") | |
1842 | (insert " "))) | |
1843 | ||
1844 | (defun makefile-browser-on-macro-line-p () | |
1845 | "Determine if point is on a macro line in the browser." | |
1846 | (save-excursion | |
1847 | (beginning-of-line) | |
debe2de2 | 1848 | (re-search-forward "\\$[{(]" (line-end-position) t))) |
72c0ae01 ER |
1849 | |
1850 | (defun makefile-browser-this-line-target-name () | |
1851 | "Extract the target name from a line in the browser." | |
1852 | (save-excursion | |
1853 | (end-of-line) | |
1854 | (skip-chars-backward "^ \t") | |
debe2de2 | 1855 | (buffer-substring (point) (1- (line-end-position))))) |
72c0ae01 ER |
1856 | |
1857 | (defun makefile-browser-this-line-macro-name () | |
1858 | "Extract the macro name from a line in the browser." | |
1859 | (save-excursion | |
1860 | (beginning-of-line) | |
debe2de2 | 1861 | (re-search-forward "\\$[{(]" (line-end-position) t) |
72c0ae01 ER |
1862 | (let ((macro-start (point))) |
1863 | (skip-chars-forward "^})") | |
1864 | (buffer-substring macro-start (point))))) | |
1865 | ||
1866 | (defun makefile-format-macro-ref (macro-name) | |
308a2860 RS |
1867 | "Format a macro reference. |
1868 | Uses `makefile-use-curly-braces-for-macros-p'." | |
b8ca7cc3 RS |
1869 | (if (or (char-equal ?\( (string-to-char macro-name)) |
1870 | (char-equal ?\{ (string-to-char macro-name))) | |
1871 | (format "$%s" macro-name) | |
1872 | (if makefile-use-curly-braces-for-macros-p | |
1873 | (format "${%s}" macro-name) | |
1874 | (format "$(%s)" macro-name)))) | |
72c0ae01 ER |
1875 | |
1876 | (defun makefile-browser-get-state-for-line (n) | |
1877 | (aref makefile-browser-selection-vector (1- n))) | |
1878 | ||
1879 | (defun makefile-browser-set-state-for-line (n to-state) | |
1880 | (aset makefile-browser-selection-vector (1- n) to-state)) | |
1881 | ||
1882 | (defun makefile-browser-toggle-state-for-line (n) | |
1883 | (makefile-browser-set-state-for-line n (not (makefile-browser-get-state-for-line n)))) | |
1884 | ||
72c0ae01 | 1885 | (defun makefile-last-line-p () |
debe2de2 | 1886 | (= (line-end-position) (point-max))) |
72c0ae01 ER |
1887 | |
1888 | (defun makefile-first-line-p () | |
debe2de2 | 1889 | (= (line-beginning-position) (point-min))) |
72c0ae01 | 1890 | |
6783b1ce RS |
1891 | \f |
1892 | ||
3b7f63b1 | 1893 | ;;; Support for other packages, like add-log. |
6783b1ce RS |
1894 | |
1895 | (defun makefile-add-log-defun () | |
32b558fa RS |
1896 | "Return name of target or variable assignment that point is in. |
1897 | If it isn't in one, return nil." | |
6783b1ce | 1898 | (save-excursion |
32b558fa RS |
1899 | (let (found) |
1900 | (beginning-of-line) | |
1901 | ;; Scan back line by line, noticing when we come to a | |
1902 | ;; variable or rule definition, and giving up when we see | |
1903 | ;; a line that is not part of either of those. | |
e006b3cd SM |
1904 | (while (not (or (setq found |
1905 | (when (or (looking-at makefile-macroassign-regex) | |
1906 | (looking-at makefile-dependency-regex)) | |
1907 | (match-string-no-properties 1))) | |
1908 | ;; Don't keep looking across a blank line or comment. | |
1909 | (looking-at "$\\|#") | |
1910 | (not (zerop (forward-line -1)))))) | |
cac9ce0d RS |
1911 | ;; Remove leading and trailing whitespace. |
1912 | (when found | |
1913 | (setq found (replace-regexp-in-string "[ \t]+\\'" "" found)) | |
1914 | (setq found (replace-regexp-in-string "\\`[ \t]+" "" found))) | |
e006b3cd | 1915 | found))) |
6783b1ce | 1916 | |
0017329b SM |
1917 | (provide 'make-mode) |
1918 | ||
c5301b5c | 1919 | ;; arch-tag: bd23545a-de91-44fb-b1b2-feafbb2635a0 |
80e01c19 | 1920 | ;;; make-mode.el ends here |