1;;; makefile.el --- makefile editing commands for Emacs 2 3;; Copyright (C) 1992, 1994 Free Software Foundation, Inc. 4 5;; Author: Thomas Neumann <tom@smart.bo.open.de> 6;; Eric S. Raymond <esr@snark.thyrsus.com> 7;; Adapted-By: ESR 8;; Keywords: unix, tools 9 10;; RMS: 11;; This needs work. The electric characters are too obnoxious. 12;; It should not define C-c LETTER. 13;; It should support knowing the list of existing macros and targets 14;; via M-TAB completion, not by preempting insertion of references. 15;; Also, the doc strings need fixing: the first line doesn't stand alone, 16;; and other usage is not high quality. Symbol names don't have `...'. 17 18;; So, for the meantime, this is not the default mode for makefiles. 19 20;; $Id: makefile.el,v 1.16 1994/05/22 22:10:39 rms Exp $ 21 22;; This file is part of GNU Emacs. 23 24;; GNU Emacs is free software; you can redistribute it and/or modify 25;; it under the terms of the GNU General Public License as published by 26;; the Free Software Foundation; either version 1, or (at your option) 27;; any later version. 28 29;; GNU Emacs is distributed in the hope that it will be useful, 30;; but WITHOUT ANY WARRANTY; without even the implied warranty of 31;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32;; GNU General Public License for more details. 33 34;; You should have received a copy of the GNU General Public License 35;; along with GNU Emacs; see the file COPYING. If not, write to 36;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 37 38;;; Commentary: 39 40;; A major mode for editing makefiles. The mode knows about Makefile 41;; syntax and defines M-n and M-p to move to next and previous productions. 42;; 43;; The keys $, =, : and . are electric; they try to help you fill in a 44;; macro reference, macro definition, ordinary target name, or special 45;; target name, respectively. Such names are completed using a list of 46;; targets and macro names parsed out of the makefile. This list is 47;; automatically updated, if necessary, whenever you invoke one of 48;; these commands. You can force it to be updated with C-c C-p. 49;; 50;; The command C-c f adds certain filenames in the current directory 51;; as targets. You can filter out filenames by setting the variable 52;; makefile-ignored-files-in-pickup-regex. 53;; 54;; The command C-c C-u grinds for a bit, then pops up a report buffer 55;; showing which target names are up-to-date with respect to their 56;; prerequisites, which targets are out-of-date, and which have no 57;; prerequisites. 58;; 59;; The command C-c b pops up a browser window listing all target and 60;; macro names. You can mark or unmark items wit C-c SPC, and insert 61;; all marked items back in the Makefile with C-c TAB. 62;; 63;; The command C-c TAB in the makefile buffer inserts a GNU make builtin. 64;; You will be prompted for the builtin's args. 65;; 66;; There are numerous other customization variables. 67 68;;; Code: 69 70(provide 'makefile) 71 72;;; ------------------------------------------------------------ 73;;; Configurable stuff 74;;; ------------------------------------------------------------ 75 76(defconst makefile-mode-name "Makefile" 77 "The \"pretty name\" of makefile-mode, as it appears in the modeline.") 78 79(defvar makefile-browser-buffer-name "*Macros and Targets*" 80 "Name of the macro- and target browser buffer.") 81 82(defvar makefile-target-colon ":" 83 "The string that gets appended to all target names 84inserted by makefile-insert-target. 85\":\" or \"::\" are quite common values.") 86 87(defvar makefile-macro-assign " = " 88 "The string that gets appended to all macro names 89inserted by makefile-insert-macro. 90The normal value should be \" = \", since this is what 91standard make expects. However, newer makes such as dmake 92allow a larger variety of different macro assignments, so you 93might prefer to use \" += \" or \" := \" .") 94 95(defvar makefile-use-curly-braces-for-macros-p nil 96 "Controls the style of generated macro references. 97Set this variable to a non-nil value if you prefer curly braces 98in macro-references, so it looks like ${this}. A value of nil 99will cause makefile-mode to use parentheses, making macro references 100look like $(this) .") 101 102(defvar makefile-tab-after-target-colon t 103 "If you want a TAB (instead of a space) to be appended after the 104target colon, then set this to a non-nil value.") 105 106(defvar makefile-browser-leftmost-column 10 107 "Number of blanks to the left of the browser selection mark.") 108 109(defvar makefile-browser-cursor-column 10 110 "Column in which the cursor is positioned when it moves 111up or down in the browser.") 112 113(defvar makefile-browser-selected-mark "+ " 114 "String used to mark selected entries in the browser.") 115 116(defvar makefile-browser-unselected-mark " " 117 "String used to mark unselected entries in the browser.") 118 119(defvar makefile-browser-auto-advance-after-selection-p t 120 "If non-nil, the cursor will automagically advance to the next line after 121an item has been selected in the browser.") 122 123(defvar makefile-pickup-everything-picks-up-filenames-p nil 124 "If non-nil, makefile-pickup-everything also picks up filenames as targets 125\(i.e. it calls makefile-find-filenames-as-targets), otherwise filenames are 126omitted.") 127 128(defvar makefile-cleanup-continuations-p t 129 "If non-nil, makefile-mode will assure that no line in the file ends with a 130backslash (the continuation character) followed by any whitespace. This is 131done by silently removing the trailing whitespace, leaving the backslash itself 132intact. IMPORTANT: Please note that enabling this option causes makefile-mode 133to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'.") 134 135(defvar makefile-browser-hook '() 136 "A function or list of functions to be called just before the 137browser is entered. This is executed in the makefile buffer.") 138 139;; 140;; Special targets for DMake, Sun's make ... 141;; 142(defvar makefile-special-targets-list 143 '(("DEFAULT") ("DONE") ("ERROR") ("EXPORT") 144 ("FAILED") ("GROUPEPILOG") ("GROUPPROLOG") ("IGNORE") 145 ("IMPORT") ("INCLUDE") ("INCLUDEDIRS") ("INIT") 146 ("KEEP_STATE") ("MAKEFILES") ("MAKE_VERSION") ("NO_PARALLEL") 147 ("PARALLEL") ("PHONY") ("PRECIOUS") ("REMOVE") 148 ("SCCS_GET") ("SILENT") ("SOURCE") ("SUFFIXES") 149 ("WAIT") ("c.o") ("C.o") ("m.o") 150 ("el.elc") ("y.c") ("s.o")) 151 "List of special targets. You will be offered to complete 152on one of those in the minibuffer whenever you enter a \".\" 153at the beginning of a line in makefile-mode.") 154 155(defvar makefile-runtime-macros-list 156 '(("@") ("&") (">") ("<") ("*") ("^") ("?") ("%")) 157 "List of macros that are resolved by make at runtime. 158If you insert a macro reference using makefile-insert-macro-ref, the name 159of the macro is checked against this list. If it can be found its name will 160not be enclosed in { } or ( ).") 161 162(defconst makefile-dependency-regex 163 "^[^ \t#:]+\\([ \t]+[^ \t#:]+\\)*[ \t]*:\\([ \t]*$\\|\\([^=\n].*$\\)\\)" 164 "Regex used to find dependency lines in a makefile.") 165 166(defconst makefile-macroassign-regex 167 "^[^ \t][^:#=]*[\\*:\\+]?:?=.*$" 168 "Regex used to find macro assignment lines in a makefile.") 169 170(defconst makefile-ignored-files-in-pickup-regex 171 "\\(^\\..*\\)\\|\\(.*~$\\)\\|\\(.*,v$\\)\\|\\(\\.[chy]\\)" 172 "Regex for filenames that will NOT be included in the target list.") 173 174;;; ------------------------------------------------------------ 175;;; The following configurable variables are used in the 176;;; up-to-date overview . 177;;; The standard configuration assumes that your `make' program 178;;; can be run in question/query mode using the `-q' option, this 179;;; means that the command 180;;; 181;;; make -q foo 182;;; 183;;; should return an exit status of zero if the target `foo' is 184;;; up to date and a nonzero exit status otherwise. 185;;; Many makes can do this although the docs/manpages do not mention 186;;; it. Try it with your favourite one. GNU make, System V make, and 187;;; Dennis Vadura's DMake have no problems. 188;;; Set the variable `makefile-brave-make' to the name of the 189;;; make utility that does this on your system. 190;;; To understand what this is all about see the function definition 191;;; of `makefile-query-by-make-minus-q' . 192;;; ------------------------------------------------------------ 193 194(defvar makefile-brave-make "make" 195 "A make that can handle the \'-q\' option.") 196 197(defvar makefile-query-one-target-method 'makefile-query-by-make-minus-q 198 "A function symbol [one that can be used as the first argument to 199funcall] that provides a function that must conform to the following 200interface: 201 202* As its first argument, it must accept the name of the target to 203 be checked, as a string. 204 205* As its second argument, it may accept the name of a makefile 206 as a string. Depending on what you're going to do you may 207 not need this. 208 209* It must return the integer value 0 (zero) if the given target 210 should be considered up-to-date in the context of the given 211 makefile, any nonzero integer value otherwise.") 212 213(defvar makefile-up-to-date-buffer-name "*Makefile Up-to-date overview*" 214 "Name of the Up-to-date overview buffer.") 215 216;;; --- end of up-to-date-overview configuration ------------------ 217 218(defvar makefile-mode-map nil 219 "The keymap that is used in makefile-mode.") 220(if makefile-mode-map 221 () 222 (setq makefile-mode-map (make-sparse-keymap)) 223 ;; set up the keymap 224 (define-key makefile-mode-map "$" 'makefile-insert-macro-ref) 225 (define-key makefile-mode-map "\C-c:" 'makefile-insert-target-ref) 226 (define-key makefile-mode-map ":" 'makefile-electric-colon) 227 (define-key makefile-mode-map "=" 'makefile-electric-equal) 228 (define-key makefile-mode-map "." 'makefile-electric-dot) 229 (define-key makefile-mode-map "\C-c\C-f" 'makefile-pickup-filenames-as-targets) 230 (define-key makefile-mode-map "\C-c\C-b" 'makefile-switch-to-browser) 231 (define-key makefile-mode-map "\C-c\C-p" 'makefile-pickup-everything) 232 (define-key makefile-mode-map "\C-c\C-u" 'makefile-create-up-to-date-overview) 233 (define-key makefile-mode-map "\C-c\C-i" 'makefile-insert-gmake-function) 234 (define-key makefile-mode-map "\M-p" 'makefile-previous-dependency) 235 (define-key makefile-mode-map "\M-n" 'makefile-next-dependency)) 236 237(defvar makefile-browser-map nil 238 "The keymap that is used in the macro- and target browser.") 239(if makefile-browser-map 240 () 241 (setq makefile-browser-map (make-sparse-keymap)) 242 (define-key makefile-browser-map "n" 'makefile-browser-next-line) 243 (define-key makefile-browser-map "\C-n" 'makefile-browser-next-line) 244 (define-key makefile-browser-map "p" 'makefile-browser-previous-line) 245 (define-key makefile-browser-map "\C-p" 'makefile-browser-previous-line) 246 (define-key makefile-browser-map " " 'makefile-browser-toggle) 247 (define-key makefile-browser-map "i" 'makefile-browser-insert-selection) 248 (define-key makefile-browser-map "I" 'makefile-browser-insert-selection-and-quit) 249 (define-key makefile-browser-map "\C-c\C-m" 'makefile-browser-insert-continuation) 250 (define-key makefile-browser-map "q" 'makefile-browser-quit) 251 ;; disable horizontal movement 252 (define-key makefile-browser-map "\C-b" 'undefined) 253 (define-key makefile-browser-map "\C-f" 'undefined)) 254 255 256(defvar makefile-mode-syntax-table nil 257 "The syntax-table used in makefile mode.") 258(if makefile-mode-syntax-table 259 () 260 (setq makefile-mode-syntax-table (make-syntax-table)) 261 (modify-syntax-entry ?\( "() " makefile-mode-syntax-table) 262 (modify-syntax-entry ?\) ")( " makefile-mode-syntax-table) 263 (modify-syntax-entry ?\[ "(] " makefile-mode-syntax-table) 264 (modify-syntax-entry ?\] "([ " makefile-mode-syntax-table) 265 (modify-syntax-entry ?\{ "(} " makefile-mode-syntax-table) 266 (modify-syntax-entry ?\} "){ " makefile-mode-syntax-table) 267 (modify-syntax-entry ?# "< " makefile-mode-syntax-table) 268 (modify-syntax-entry ?\n "> " makefile-mode-syntax-table)) 269 270 271;;; ------------------------------------------------------------ 272;;; Internal variables. 273;;; You don't need to configure below this line. 274;;; ------------------------------------------------------------ 275 276(defvar makefile-target-table nil 277 "Table of all targets that have been inserted in 278this Makefile buffer using makefile-insert-target or picked up 279using makefile-pickup-targets.") 280 281(defvar makefile-macro-table nil 282 "Table of all macros that have been iserted in 283this Makefile buffer using makefile-insert-macro or picked up 284using makefile-pickup-macros.") 285 286(defvar makefile-browser-client 287 "A buffer in makefile-mode that is currently using the browser.") 288 289(defvar makefile-browser-selection-vector nil) 290(defvar makefile-has-prereqs nil) 291(defvar makefile-need-target-pickup t) 292(defvar makefile-need-macro-pickup t) 293 294(defvar makefile-mode-hook '()) 295 296(defconst makefile-gnumake-functions-alist 297 '( 298 ;; Text functions 299 ("subst" "From" "To" "In") 300 ("patsubst" "Pattern" "Replacement" "In") 301 ("strip" "Text") 302 ("findstring" "Find what" "In") 303 ("filter" "Pattern" "Text") 304 ("filter-out" "Pattern" "Text") 305 ("sort" "List") 306 ;; Filename functions 307 ("dir" "Names") 308 ("notdir" "Names") 309 ("suffix" "Names") 310 ("basename" "Names") 311 ("addsuffix" "Suffix" "Names") 312 ("join" "List 1" "List 2") 313 ("word" "Index" "Text") 314 ("words" "Text") 315 ("firstword" "Text") 316 ("wildcard" "Pattern") 317 ;; Misc functions 318 ("foreach" "Variable" "List" "Text") 319 ("origin" "Variable") 320 ("shell" "Command")) 321 "A list of GNU make function names associated with 322the prompts for each function. 323This is used in the function makefile-insert-gmake-function .") 324 325 326;;; ------------------------------------------------------------ 327;;; The mode function itself. 328;;; ------------------------------------------------------------ 329 330;;;###autoload 331(defun makefile-mode () 332 "Major mode for editing Makefiles. 333Calling this function invokes the function(s) \"makefile-mode-hook\" before 334doing anything else. 335 336\\{makefile-mode-map} 337 338In the browser, use the following keys: 339 340\\{makefile-browser-map} 341 342makefile-mode can be configured by modifying the following 343variables: 344 345makefile-mode-name: 346 The \"pretty name\" of makefile-mode, as it 347 appears in the modeline. 348 349makefile-browser-buffer-name: 350 Name of the macro- and target browser buffer. 351 352makefile-target-colon: 353 The string that gets appended to all target names 354 inserted by makefile-insert-target. 355 \":\" or \"::\" are quite common values. 356 357makefile-macro-assign: 358 The string that gets appended to all macro names 359 inserted by makefile-insert-macro. 360 The normal value should be \" = \", since this is what 361 standard make expects. However, newer makes such as dmake 362 allow a larger variety of different macro assignments, so you 363 might prefer to use \" += \" or \" := \" . 364 365makefile-tab-after-target-colon: 366 If you want a TAB (instead of a space) to be appended after the 367 target colon, then set this to a non-nil value. 368 369makefile-browser-leftmost-column: 370 Number of blanks to the left of the browser selection mark. 371 372makefile-browser-cursor-column: 373 Column in which the cursor is positioned when it moves 374 up or down in the browser. 375 376makefile-browser-selected-mark: 377 String used to mark selected entries in the browser. 378 379makefile-browser-unselected-mark: 380 String used to mark unselected entries in the browser. 381 382makefile-browser-auto-advance-after-selection-p: 383 If this variable is set to a non-nil value the cursor 384 will automagically advance to the next line after an item 385 has been selected in the browser. 386 387makefile-pickup-everything-picks-up-filenames-p: 388 If this variable is set to a non-nil value then 389 makefile-pickup-everything also picks up filenames as targets 390 (i.e. it calls makefile-find-filenames-as-targets), otherwise 391 filenames are omitted. 392 393makefile-cleanup-continuations-p: 394 If this variable is set to a non-nil value then makefile-mode 395 will assure that no line in the file ends with a backslash 396 (the continuation character) followed by any whitespace. 397 This is done by silently removing the trailing whitespace, leaving 398 the backslash itself intact. 399 IMPORTANT: Please note that enabling this option causes makefile-mode 400 to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \'it seems necessary\'. 401 402makefile-browser-hook: 403 A function or list of functions to be called just before the 404 browser is entered. This is executed in the makefile buffer. 405 406makefile-special-targets-list: 407 List of special targets. You will be offered to complete 408 on one of those in the minibuffer whenever you enter a \".\" 409 at the beginning of a line in makefile-mode." 410 (interactive) 411 (kill-all-local-variables) 412 (make-local-variable 'local-write-file-hooks) 413 (setq local-write-file-hooks 414 '(makefile-cleanup-continuations makefile-warn-suspicious-lines)) 415 (make-local-variable 'makefile-target-table) 416 (make-local-variable 'makefile-macro-table) 417 (make-local-variable 'makefile-has-prereqs) 418 (make-local-variable 'makefile-need-target-pickup) 419 (make-local-variable 'makefile-need-macro-pickup) 420 (make-local-variable 'comment-start) 421 (make-local-variable 'comment-end) 422 (make-local-variable 'comment-start-skip) 423 (setq comment-start "#") 424 (setq comment-end "") 425 (setq comment-start-skip "#[ \t]*") 426 ;; become the current major mode 427 (setq major-mode 'makefile-mode) 428 (setq mode-name makefile-mode-name) 429 ;; activate keymap 430 (use-local-map makefile-mode-map) 431 (set-syntax-table makefile-mode-syntax-table) 432 (setq indent-tabs-mode t) ;real TABs are important in makefiles 433 (run-hooks 'makefile-mode-hook)) 434 435(defun makefile-next-dependency () 436 "Move (point) to the beginning of the next dependency line below (point)." 437 (interactive) 438 (let ((here (point))) 439 (end-of-line) 440 (if (re-search-forward makefile-dependency-regex (point-max) t) 441 (progn (beginning-of-line) t) ; indicate success 442 (goto-char here) nil))) 443 444(defun makefile-previous-dependency () 445 "Move (point) to the beginning of the next dependency line above (point)." 446 (interactive) 447 (let ((here (point))) 448 (beginning-of-line) 449 (if (re-search-backward makefile-dependency-regex (point-min) t) 450 (progn (beginning-of-line) t) ; indicate success 451 (goto-char here) nil))) 452 453 454;;; Stuff below here depends on the pickup state 455 456(defun makefile-electric-dot () 457 "At (bol), offer completion on makefile-special-targets-list. 458Anywhere else just insert a dot." 459 (interactive) 460 (if (bolp) 461 (makefile-insert-special-target) 462 (insert "."))) 463 464(defun makefile-insert-special-target () 465 "Complete on makefile-special-targets-list, insert result at (point)." 466 (interactive) 467 (makefile-pickup-targets) 468 (let 469 ((special-target 470 (completing-read "Special target: " 471 makefile-special-targets-list nil nil nil))) 472 (if (zerop (length special-target)) 473 () 474 (insert (format ".%s:" special-target)) 475 (makefile-forward-after-target-colon)))) 476 477(defun makefile-electric-equal () 478 "At (bol) do makefile-insert-macro. Anywhere else just self-insert." 479 (interactive) 480 (makefile-pickup-macros) 481 (if (bolp) 482 (call-interactively 'makefile-insert-macro) 483 (insert "="))) 484 485(defun makefile-insert-macro (macro-name) 486 "Prepare definition of a new macro." 487 (interactive "sMacro Name: ") 488 (makefile-pickup-macros) 489 (if (not (zerop (length macro-name))) 490 (progn 491 (beginning-of-line) 492 (insert (format "%s%s" macro-name makefile-macro-assign)) 493 (setq makefile-need-macro-pickup t) 494 (makefile-remember-macro macro-name)))) 495 496(defun makefile-insert-macro-ref (macro-name) 497 "Complete on a list of known macros, then insert complete ref at (point)." 498 (interactive 499 (list 500 (progn 501 (makefile-pickup-macros) 502 (completing-read "Refer to macro: " makefile-macro-table nil nil nil)))) 503 (if (not (zerop (length macro-name))) 504 (if (assoc macro-name makefile-runtime-macros-list) 505 (insert (format "$%s" macro-name)) 506 (insert (makefile-format-macro-ref macro-name))))) 507 508(defun makefile-insert-target (target-name) 509 "Prepare definition of a new target (dependency line)." 510 (interactive "sTarget: ") 511 (if (not (zerop (length target-name))) 512 (progn 513 (beginning-of-line) 514 (insert (format "%s%s" target-name makefile-target-colon)) 515 (makefile-forward-after-target-colon) 516 (end-of-line) 517 (setq makefile-need-target-pickup t) 518 (makefile-remember-target target-name)))) 519 520(defun makefile-insert-target-ref (target-name) 521 "Complete on a list of known targets, then insert target-ref at (point) ." 522 (interactive 523 (list 524 (progn 525 (makefile-pickup-targets) 526 (completing-read "Refer to target: " makefile-target-table nil nil nil)))) 527 (if (not (zerop (length target-name))) 528 (progn 529 (insert (format "%s " target-name))))) 530 531(defun makefile-electric-colon () 532 "At (bol) defines a new target, anywhere else just self-insert ." 533 (interactive) 534 (if (bolp) 535 (call-interactively 'makefile-insert-target) 536 (insert ":"))) 537 538;;; ------------------------------------------------------------ 539;;; Extracting targets and macros from an existing makefile 540;;; ------------------------------------------------------------ 541 542(defun makefile-pickup-targets () 543 "Scan a buffer that contains a makefile for target definitions (dependencies) 544and add them to the list of known targets." 545 (interactive) 546 (if (not makefile-need-target-pickup) 547 nil 548 (setq makefile-need-target-pickup nil) 549 (setq makefile-target-table nil) 550 (setq makefile-has-prereqs nil) 551 (save-excursion 552 (goto-char (point-min)) 553 (while (re-search-forward makefile-dependency-regex (point-max) t) 554 (makefile-add-this-line-targets))) 555 (message "Read targets OK."))) 556 557(defun makefile-add-this-line-targets () 558 (save-excursion 559 (beginning-of-line) 560 (let ((done-with-line nil) 561 (line-number (1+ (count-lines (point-min) (point))))) 562 (while (not done-with-line) 563 (skip-chars-forward " \t") 564 (if (not (setq done-with-line (or (eolp) 565 (char-equal (char-after (point)) ?:)))) 566 (progn 567 (let* ((start-of-target-name (point)) 568 (target-name 569 (progn 570 (skip-chars-forward "^ \t:#") 571 (buffer-substring start-of-target-name (point)))) 572 (has-prereqs 573 (not (looking-at ":[ \t]*$")))) 574 (if (makefile-remember-target target-name has-prereqs) 575 (message "Picked up target \"%s\" from line %d" 576 target-name line-number))))))))) 577 578 579(defun makefile-pickup-macros () 580 "Scan a buffer that contains a makefile for macro definitions 581and add them to the list of known macros." 582 (interactive) 583 (if (not makefile-need-macro-pickup) 584 nil 585 (setq makefile-need-macro-pickup nil) 586 (setq makefile-macro-table nil) 587 (save-excursion 588 (goto-char (point-min)) 589 (while (re-search-forward makefile-macroassign-regex (point-max) t) 590 (makefile-add-this-line-macro) 591 (forward-line 1))) 592 (message "Read macros OK."))) 593 594(defun makefile-add-this-line-macro () 595 (save-excursion 596 (beginning-of-line) 597 (skip-chars-forward " \t") 598 (if (not (eolp)) 599 (let* ((start-of-macro-name (point)) 600 (line-number (1+ (count-lines (point-min) (point)))) 601 (macro-name (progn 602 (skip-chars-forward "^ \t:#=*") 603 (buffer-substring start-of-macro-name (point))))) 604 (if (makefile-remember-macro macro-name) 605 (message "Picked up macro \"%s\" from line %d" 606 macro-name line-number)))))) 607 608(defun makefile-pickup-everything () 609 "Calls makefile-pickup-targets and makefile-pickup-macros. 610See their documentation for what they do." 611 (interactive) 612 (makefile-pickup-macros) 613 (makefile-pickup-targets) 614 (if makefile-pickup-everything-picks-up-filenames-p 615 (makefile-pickup-filenames-as-targets))) 616 617 618(defun makefile-pickup-filenames-as-targets () 619 "Scan the current directory for filenames, check each filename 620against makefile-ignored-files-in-pickup-regex and add all qualifying 621names to the list of known targets." 622 (interactive) 623 (let* ((dir (file-name-directory (buffer-file-name))) 624 (raw-filename-list (if dir 625 (file-name-all-completions "" dir) 626 (file-name-all-completions "" "")))) 627 (mapcar '(lambda (name) 628 (if (and (not (file-directory-p name)) 629 (not (string-match makefile-ignored-files-in-pickup-regex 630 name))) 631 (if (makefile-remember-target name) 632 (message "Picked up file \"%s\" as target" name)))) 633 raw-filename-list))) 634 635;;; ------------------------------------------------------------ 636;;; The browser window 637;;; ------------------------------------------------------------ 638 639(defun makefile-browser-format-target-line (target selected) 640 (format 641 (concat (make-string makefile-browser-leftmost-column ?\ ) 642 (if selected 643 makefile-browser-selected-mark 644 makefile-browser-unselected-mark) 645 "%s%s") 646 target makefile-target-colon)) 647 648(defun makefile-browser-format-macro-line (macro selected) 649 (format 650 (concat (make-string makefile-browser-leftmost-column ?\ ) 651 (if selected 652 makefile-browser-selected-mark 653 makefile-browser-unselected-mark) 654 (makefile-format-macro-ref macro)))) 655 656(defun makefile-browser-fill (targets macros) 657 (let ((inhibit-read-only t)) 658 (goto-char (point-min)) 659 (erase-buffer) 660 (mapconcat 661 (function 662 (lambda (item) (insert (makefile-browser-format-target-line (car item) nil) "\n"))) 663 targets 664 "") 665 (mapconcat 666 (function 667 (lambda (item) (insert (makefile-browser-format-macro-line (car item) nil) "\n"))) 668 macros 669 "") 670 (sort-lines nil (point-min) (point-max)) 671 (goto-char (1- (point-max))) 672 (delete-char 1) ; remove unnecessary newline at eob 673 (goto-char (point-min)) 674 (forward-char makefile-browser-cursor-column))) 675 676;;; 677;;; Moving up and down in the browser 678;;; 679 680(defun makefile-browser-next-line () 681 "Move the browser selection cursor to the next line." 682 (interactive) 683 (if (not (makefile-last-line-p)) 684 (progn 685 (forward-line 1) 686 (forward-char makefile-browser-cursor-column)))) 687 688(defun makefile-browser-previous-line () 689 "Move the browser selection cursor to the previous line." 690 (interactive) 691 (if (not (makefile-first-line-p)) 692 (progn 693 (forward-line -1) 694 (forward-char makefile-browser-cursor-column)))) 695 696;;; 697;;; Quitting the browser (returns to client buffer) 698;;; 699 700(defun makefile-browser-quit () 701 "Leave the makefile-browser-buffer and return to the buffer 702from that it has been entered." 703 (interactive) 704 (let ((my-client makefile-browser-client)) 705 (setq makefile-browser-client nil) ; we quitted, so NO client! 706 (set-buffer-modified-p nil) 707 (kill-buffer (current-buffer)) 708 (pop-to-buffer my-client))) 709 710;;; 711;;; Toggle state of a browser item 712;;; 713 714(defun makefile-browser-toggle () 715 "Toggle the selection state of the browser item at the cursor position." 716 (interactive) 717 (let ((this-line (count-lines (point-min) (point)))) 718 (setq this-line (max 1 this-line)) 719 (makefile-browser-toggle-state-for-line this-line) 720 (goto-line this-line) 721 (let ((inhibit-read-only t)) 722 (beginning-of-line) 723 (if (makefile-browser-on-macro-line-p) 724 (let ((macro-name (makefile-browser-this-line-macro-name))) 725 (kill-line) 726 (insert 727 (makefile-browser-format-macro-line 728 macro-name 729 (makefile-browser-get-state-for-line this-line)))) 730 (let ((target-name (makefile-browser-this-line-target-name))) 731 (kill-line) 732 (insert 733 (makefile-browser-format-target-line 734 target-name 735 (makefile-browser-get-state-for-line this-line)))))) 736 (beginning-of-line) 737 (forward-char makefile-browser-cursor-column) 738 (if makefile-browser-auto-advance-after-selection-p 739 (makefile-browser-next-line)))) 740 741;;; 742;;; Making insertions into the client buffer 743;;; 744 745(defun makefile-browser-insert-continuation () 746 "Insert a makefile continuation. 747In the browser\'s client buffer, go to (end-of-line), insert a \'\\\' 748character, insert a new blank line, go to that line and indent by one TAB. 749This is most useful in the process of creating continued lines when copying 750large dependencies from the browser to the client buffer. 751\(point) advances accordingly in the client buffer." 752 (interactive) 753 (save-excursion 754 (set-buffer makefile-browser-client) 755 (end-of-line) 756 (insert "\\\n\t"))) 757 758(defun makefile-browser-insert-selection () 759 "Insert all browser-selected targets and/or macros in the browser\'s 760client buffer. 761Insertion takes place at (point)." 762 (interactive) 763 (save-excursion 764 (goto-line 1) 765 (let ((current-line 1)) 766 (while (not (eobp)) 767 (if (makefile-browser-get-state-for-line current-line) 768 (makefile-browser-send-this-line-item)) 769 (forward-line 1) 770 (setq current-line (1+ current-line)))))) 771 772(defun makefile-browser-insert-selection-and-quit () 773 (interactive) 774 (makefile-browser-insert-selection) 775 (makefile-browser-quit)) 776 777(defun makefile-browser-send-this-line-item () 778 (if (makefile-browser-on-macro-line-p) 779 (save-excursion 780 (let ((macro-name (makefile-browser-this-line-macro-name))) 781 (set-buffer makefile-browser-client) 782 (insert (makefile-format-macro-ref macro-name) " "))) 783 (save-excursion 784 (let ((target-name (makefile-browser-this-line-target-name))) 785 (set-buffer makefile-browser-client) 786 (insert target-name " "))))) 787 788(defun makefile-browser-start-interaction () 789 (use-local-map makefile-browser-map) 790 (setq buffer-read-only t)) 791 792(defun makefile-browse (targets macros) 793 (interactive) 794 (if (zerop (+ (length targets) (length macros))) 795 (progn 796 (beep) 797 (message "No macros or targets to browse! Consider running 'makefile-pickup-everything\'")) 798 (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name))) 799 (pop-to-buffer browser-buffer) 800 (make-variable-buffer-local 'makefile-browser-selection-vector) 801 (makefile-browser-fill targets macros) 802 (shrink-window-if-larger-than-buffer) 803 (setq makefile-browser-selection-vector 804 (make-vector (+ (length targets) (length macros)) nil)) 805 (makefile-browser-start-interaction)))) 806 807(defun makefile-switch-to-browser () 808 (interactive) 809 (run-hooks 'makefile-browser-hook) 810 (setq makefile-browser-client (current-buffer)) 811 (makefile-pickup-targets) 812 (makefile-pickup-macros) 813 (makefile-browse makefile-target-table makefile-macro-table)) 814 815 816;;; ------------------------------------------------------------ 817;;; Up-to-date overview buffer 818;;; ------------------------------------------------------------ 819 820(defun makefile-create-up-to-date-overview () 821 "Create a buffer containing an overview of the state of all known targets. 822Known targets are targets that are explicitly defined in that makefile; 823in other words, all targets that appear on the left hand side of a 824dependency in the makefile." 825 (interactive) 826 (if (y-or-n-p "Are you sure that the makefile being edited is consistent? ") 827 ;; 828 ;; The rest of this function operates on a temporary makefile, created by 829 ;; writing the current contents of the makefile buffer. 830 ;; 831 (let ((saved-target-table makefile-target-table) 832 (this-buffer (current-buffer)) 833 (makefile-up-to-date-buffer 834 (get-buffer-create makefile-up-to-date-buffer-name)) 835 (filename (makefile-save-temporary)) 836 ;; 837 ;; Forget the target table because it may contain picked-up filenames 838 ;; that are not really targets in the current makefile. 839 ;; We don't want to query these, so get a new target-table with just the 840 ;; targets that can be found in the makefile buffer. 841 ;; The 'old' target table will be restored later. 842 ;; 843 (real-targets (progn 844 (makefile-pickup-targets) 845 makefile-target-table)) 846 (prereqs makefile-has-prereqs) 847 ) 848 849 (set-buffer makefile-up-to-date-buffer) 850 (setq buffer-read-only nil) 851 (erase-buffer) 852 (makefile-query-targets filename real-targets prereqs) 853 (if (zerop (buffer-size)) ; if it did not get us anything 854 (progn 855 (kill-buffer (current-buffer)) 856 (message "No overview created!"))) 857 (set-buffer this-buffer) 858 (setq makefile-target-table saved-target-table) 859 (if (get-buffer makefile-up-to-date-buffer-name) 860 (progn 861 (pop-to-buffer (get-buffer makefile-up-to-date-buffer-name)) 862 (shrink-window-if-larger-than-buffer) 863 (sort-lines nil (point-min) (point-max)) 864 (setq buffer-read-only t)))))) 865 866(defun makefile-save-temporary () 867 "Create a temporary file from the current makefile buffer." 868 (let ((filename (makefile-generate-temporary-filename))) 869 (write-region (point-min) (point-max) filename nil 0) 870 filename)) ; return the filename 871 872(defun makefile-generate-temporary-filename () 873 "Create a filename suitable for use in makefile-save-temporary. 874Be careful to allow brain-dead file systems (DOS, SYSV ...) to cope 875with the generated name !" 876 (let ((my-name (user-login-name)) 877 (my-uid (int-to-string (user-uid)))) 878 (concat "mktmp" 879 (if (> (length my-name) 3) 880 (substring my-name 0 3) 881 my-name) 882 "." 883 (if (> (length my-uid) 3) 884 (substring my-uid 0 3) 885 my-uid)))) 886 887(defun makefile-query-targets (filename target-table prereq-list) 888 "This function fills the up-to-date-overview-buffer. 889It checks each target in target-table using makefile-query-one-target-method 890and generates the overview, one line per target name." 891 (insert 892 (mapconcat 893 (function (lambda (item) 894 (let* ((target-name (car item)) 895 (no-prereqs (not (member target-name prereq-list))) 896 (needs-rebuild (or no-prereqs 897 (funcall 898 makefile-query-one-target-method 899 target-name 900 filename)))) 901 (format "\t%s%s" 902 target-name 903 (cond (no-prereqs " .. has no prerequisites") 904 (needs-rebuild " .. NEEDS REBUILD") 905 (t " .. is up to date")))) 906 )) 907 target-table "\n")) 908 (goto-char (point-min)) 909 (delete-file filename)) ; remove the tmpfile 910 911(defun makefile-query-by-make-minus-q (target &optional filename) 912 (not (zerop (call-process makefile-brave-make nil nil nil "-f" filename "-q" target)))) 913 914;;; ------------------------------------------------------------ 915;;; Continuation cleanup 916;;; ------------------------------------------------------------ 917 918(defun makefile-cleanup-continuations () 919 (if (eq major-mode 'makefile-mode) 920 (if (and makefile-cleanup-continuations-p 921 (not buffer-read-only)) 922 (save-excursion 923 (goto-char (point-min)) 924 (while (re-search-forward "\\\\[ \t]+$" (point-max) t) 925 (replace-match "\\" t t)))))) 926 927 928;;; ------------------------------------------------------------ 929;;; Warn of suspicious lines 930;;; ------------------------------------------------------------ 931 932(defun makefile-warn-suspicious-lines () 933 (let ((dont-save nil)) 934 (if (eq major-mode 'makefile-mode) 935 (let ((suspicious 936 (save-excursion 937 (goto-char (point-min)) 938 (re-search-forward 939 "\\(^[\t]+$\\)\\|\\(^[ ]+[\t]\\)" (point-max) t)))) 940 (if suspicious 941 (let ((line-nr (count-lines (point-min) suspicious))) 942 (setq dont-save 943 (not (y-or-n-p 944 (format "Suspicious line %d. Save anyway " 945 line-nr)))))))) 946 dont-save)) 947 948 949;;; ------------------------------------------------------------ 950;;; GNU make function support 951;;; ------------------------------------------------------------ 952 953(defun makefile-insert-gmake-function () 954 "This function is intended to help you using the numerous 955macro-like \'function calls\' of GNU make. 956It will ask you for the name of the function you wish to 957use (with completion), then, after you selected the function, 958it will prompt you for all required parameters. 959This function \'knows\' about the required parameters of every 960GNU make function and will use meaningfull prompts for the 961various args, making it much easier to take advantage of this 962powerful GNU make feature." 963 (interactive) 964 (let* ((gm-function-name (completing-read 965 "Function: " 966 makefile-gnumake-functions-alist 967 nil t nil)) 968 (gm-function-prompts 969 (cdr (assoc gm-function-name makefile-gnumake-functions-alist)))) 970 (if (not (zerop (length gm-function-name))) 971 (insert (makefile-format-macro-ref 972 (concat gm-function-name " " 973 (makefile-prompt-for-gmake-funargs 974 gm-function-name gm-function-prompts))) 975 " ")))) 976 977(defun makefile-prompt-for-gmake-funargs (function-name prompt-list) 978 (mapconcat 979 (function (lambda (one-prompt) 980 (read-string (format "[%s] %s: " function-name one-prompt) nil))) 981 prompt-list 982 ",")) 983 984 985 986;;; ------------------------------------------------------------ 987;;; Utility functions 988;;; ------------------------------------------------------------ 989 990(defun makefile-remember-target (target-name &optional has-prereqs) 991 "Remember a given target if it is not already remembered for this buffer." 992 (if (not (zerop (length target-name))) 993 (progn 994 (if (not (assoc target-name makefile-target-table)) 995 (setq makefile-target-table 996 (cons (list target-name) makefile-target-table))) 997 (if has-prereqs 998 (setq makefile-has-prereqs 999 (cons target-name makefile-has-prereqs)))))) 1000 1001(defun makefile-remember-macro (macro-name) 1002 "Remember a given macro if it is not already remembered for this buffer." 1003 (if (not (zerop (length macro-name))) 1004 (if (not (assoc macro-name makefile-macro-table)) 1005 (setq makefile-macro-table 1006 (cons (list macro-name) makefile-macro-table))))) 1007 1008(defun makefile-forward-after-target-colon () 1009"Move point forward after the terminating colon 1010of a target has been inserted. 1011This accts according to the value of makefile-tab-after-target-colon ." 1012 (if makefile-tab-after-target-colon 1013 (insert "\t") 1014 (insert " "))) 1015 1016(defun makefile-browser-on-macro-line-p () 1017 "Determine if point is on a macro line in the browser." 1018 (save-excursion 1019 (beginning-of-line) 1020 (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t))) 1021 1022(defun makefile-browser-this-line-target-name () 1023 "Extract the target name from a line in the browser." 1024 (save-excursion 1025 (end-of-line) 1026 (skip-chars-backward "^ \t") 1027 (buffer-substring (point) (1- (makefile-end-of-line-point))))) 1028 1029(defun makefile-browser-this-line-macro-name () 1030 "Extract the macro name from a line in the browser." 1031 (save-excursion 1032 (beginning-of-line) 1033 (re-search-forward "\\$[{(]" (makefile-end-of-line-point) t) 1034 (let ((macro-start (point))) 1035 (skip-chars-forward "^})") 1036 (buffer-substring macro-start (point))))) 1037 1038(defun makefile-format-macro-ref (macro-name) 1039 "Format a macro reference according to the value of the 1040configuration variable makefile-use-curly-braces-for-macros-p ." 1041 (if (or (char-equal ?\( (string-to-char macro-name)) 1042 (char-equal ?\{ (string-to-char macro-name))) 1043 (format "$%s" macro-name) 1044 (if makefile-use-curly-braces-for-macros-p 1045 (format "${%s}" macro-name) 1046 (format "$(%s)" macro-name)))) 1047 1048(defun makefile-browser-get-state-for-line (n) 1049 (aref makefile-browser-selection-vector (1- n))) 1050 1051(defun makefile-browser-set-state-for-line (n to-state) 1052 (aset makefile-browser-selection-vector (1- n) to-state)) 1053 1054(defun makefile-browser-toggle-state-for-line (n) 1055 (makefile-browser-set-state-for-line n (not (makefile-browser-get-state-for-line n)))) 1056 1057(defun makefile-beginning-of-line-point () 1058 (save-excursion 1059 (beginning-of-line) 1060 (point))) 1061 1062(defun makefile-end-of-line-point () 1063 (save-excursion 1064 (end-of-line) 1065 (point))) 1066 1067(defun makefile-last-line-p () 1068 (= (makefile-end-of-line-point) (point-max))) 1069 1070(defun makefile-first-line-p () 1071 (= (makefile-beginning-of-line-point) (point-min))) 1072 1073;; makefile.el ends here 1074