cosmetix in lz unpacker
[k8jam.git] / emacs / jam-mode.el
blob82ce7a19e7d287d09663eb8cbb7a0ddc78f1445e
1 ;; *****************************************************************************
2 ;;
3 ;; jam-mode.el
4 ;; Font-lock and indentation support for Jam files
5 ;;
6 ;; Copyright (C) 2006, Google Inc (www.google.com)
7 ;; Author Kai Backman <kaib at google.com>
8 ;; 19 June 2006 - 0.5 - Extended indentation for most common structures.
9 ;;
10 ;; Copyright (C) 2003, 2004, Rob Walker <rob at tenfoot.org.uk>
11 ;; http://www.tenfoot.org.uk/emacs/
12 ;; 12 May 2004 - 0.3 - Fix keyword quoting, XEmacs support
13 ;; 22 Mar 2003 - 0.2 - Autoload
14 ;; 04 Mar 2003 - 0.1 - Added imenu support and basic indentation
16 ;; Copyright (C) 2000, Eric Scouten
17 ;; Started Sat, 05 Aug 2000
19 ;; *****************************************************************************
21 ;; This is free software; you can redistribute it and/or modify
22 ;; it under the terms of the GNU General Public License as published by
23 ;; the Free Software Foundation; either version 2, or (at your option)
24 ;; any later version.
26 ;; jam-mode.el is distributed in the hope that it will be useful,
27 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
28 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 ;; General Public License for more details.
31 ;; You should have received a copy of the GNU General Public License
32 ;; along with GNU Emacs; see the file COPYING. If not, write to the
33 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
34 ;; Boston, MA 02111-1307, USA.
36 ;; *****************************************************************************
38 ;; To add font-lock support for Jam files, simply add the line
39 ;; (require 'jam-mode) to your .emacs file. Make sure generic-mode.el
40 ;; is visible in your load-path as well.
42 ;; *****************************************************************************
45 ;; Generic-mode is a meta-mode which can be used to define small modes
46 ;; which provide basic comment and font-lock support. Jam-mode depends on
47 ;; this mode.
49 ;; generic.el for GNU emacs, generic-mode.el for XEmacs
50 (if (string-match "XEmacs\\|Lucid" emacs-version)
51 (require 'generic-mode)
52 (require 'generic))
54 (defun jam-mode-quote-keywords (keywords)
55 "Returns a list of expressions that match each element in KEYWORDS.
56 For generic-mode, each element is quoted. For generic, each element is unchanged."
57 (if (featurep 'generic-mode)
58 (mapcar 'regexp-quote keywords)
59 keywords))
61 ;;;###autoload
62 (define-generic-mode 'jam-mode
64 ; Jam comments always start with '#'
65 (list ?# )
67 ; Jam keywords (defined later)
68 nil
70 ; Extra stuff to colorize
71 (list
73 ; Jam keywords
74 (generic-make-keywords-list
75 (list "actions" "bind" "case" "default" "else" "existing" "for" "if"
76 "ignore" "in" "include" "local" "on" "piecemeal" "quietly" "rule" "switch"
77 "together" "updated")
78 'font-lock-keyword-face)
80 ; Jam built-in variables
81 (generic-make-keywords-list
82 (list
83 "JAMDATE" "JAMSHELL" "JAMUNAME" "JAMVERSION" "MAC" "NT" "OS" "OS2"
84 "OSPLAT" "OSVER" "UNIX" "VMS")
85 'font-lock-constant-face)
87 ; Jam built-in targets
88 (generic-make-keywords-list
89 (list
90 "ALWAYS" "DEPENDS" "ECHO" "INCLUDES" "LEAVES" "LOCATE" "NOCARE"
91 "NOTFILE" "NOUPDATE" "SEARCH" "TEMPORARY")
92 'font-lock-builtin-face)
94 ; Jam built-in targets (warnings)
95 (generic-make-keywords-list
96 (list
97 "EXIT")
98 'font-lock-warning-face)
100 ; Jambase rules
101 (generic-make-keywords-list
102 (jam-mode-quote-keywords
103 (list
104 "Archive" "As" "Bulk" "Cc" "CcMv" "C++" "Chgrp" "Chmod" "Chown" "Clean" "CreLib"
105 "Depends" "File" "Fortran" "GenFile" "GenFile1" "HardLink"
106 "HdrRule" "Install" "InstallBin" "InstallFile" "InstallInto" "InstallLib" "InstallMan"
107 "InstallShell" "Lex" "Library" "LibraryFromObjects" "Link" "LinkLibraries"
108 "Main" "MainFromObjects" "MakeLocate" "MkDir" "MkDir1" "Object" "ObjectC++Flags"
109 "ObjectCcFlags" "ObjectHdrs" "Objects" "Ranlib" "RmTemps" "Setuid" "SubDir"
110 "SubDirC++Flags" "SubDirCcFlags" "SubDirHdrs" "SubInclude" "Shell" "Undefines"
111 "UserObject" "Yacc" "Yacc1" "BULK" "FILE" "HDRRULE" "INSTALL" "INSTALLBIN" "INSTALLLIB"
112 "INSTALLMAN" "LIBRARY" "LIBS" "LINK" "MAIN" "SETUID" "SHELL" "UNDEFINES"
113 "addDirName" "makeCommon" "makeDirName" "makeGrist" "makeGristedName" "makeRelPath"
114 "makeString" "makeSubDir" "makeSuffixed" "unmakeDir"))
115 'font-lock-function-name-face)
117 ; Jambase built-in targets
118 (generic-make-keywords-list
119 (list
120 "all" "clean" "dirs" "exe" "files" "first" "install" "lib" "obj" "shell" "uninstall")
121 'font-lock-builtin-face)
123 ; Jambase built-in variables
124 (generic-make-keywords-list
125 (jam-mode-quote-keywords
126 (list
127 "ALL_LOCATE_TARGET" "AR" "ARFLAGS" "AS" "ASFLAGS" "AWK" "BCCROOT" "BINDIR" "CC" "CCFLAGS"
128 "C++" "C++FLAGS" "CHMOD" "CP" "CRELIB" "CW" "CWGUSI" "CWMAC" "CWMSL" "DOT" "DOTDOT"
129 "EXEMODE" "FILEMODE" "FORTRAN" "FORTRANFLAGS" "GROUP" "HDRGRIST" "HDRPATTERN" "HDRRULE"
130 "HDRS" "HDRSCAN" "HDRSEARCH" "INSTALL" "JAMFILE" "JAMRULES" "LEX" "LIBDIR" "LINK"
131 "LINKFLAGS" "LINKLIBS" "LOCATE_SOURCE" "LOCATE_TARGET" "LN" "MACINC" "MANDIR" "MKDIR"
132 "MODE" "MSLIB" "MSLINK" "MSIMPLIB" "MSRC" "MSVC" "MSVCNT" "MV" "NEEDLIBS" "NOARSCAN"
133 "OSFULL" "OPTIM" "OWNER" "RANLIB" "RCP" "RELOCATE" "RM" "RSH" "RUNVMS" "SEARCH_SOURCE"
134 "SED" "SHELLHEADER" "SHELLMODE" "SLASH" "SLASHINC" "SOURCE_GRIST" "STDHDRS" "STDLIBPATH"
135 "SUBDIR" "SUBDIRASFLAGS" "SUBDIRC++FLAGS" "SUBDIRCCFLAGS" "SUBDIRHDRS" "SUBDIR_TOKENS"
136 "SUFEXE" "SUFLIB" "SUFOBJ" "UNDEFFLAG" "UNDEFS" "WATCOM" "YACC" "YACCFLAGS" "YACCFILES"))
137 'font-lock-function-name-face)
139 ; Jam variable references $(foo)
140 '("$(\\([^ :\\[()\t\r\n]+\\)[)\\[:]" 1 font-lock-variable-name-face))
142 ; Apply this mode to all files called Jamfile, Jamrules or Jambase
143 (list "\\(Jamfile\\|Jamrules\\|Jambase\\)\\'")
145 ; Attach setup function so we can modify syntax table.
146 (list 'jam-mode-setup-function)
148 ; Brief description
149 "Generic mode for Jam rules files")
151 (defun jam-mode-setup-function ()
152 (modify-syntax-entry ?_ "w")
153 (modify-syntax-entry ?. "w")
154 (modify-syntax-entry ?/ "w")
155 (modify-syntax-entry ?+ "w")
156 (modify-syntax-entry ?# "<")
157 (modify-syntax-entry ?\n ">")
158 (setq imenu-generic-expression
159 '(("Rules" "^rule\\s-+\\([A-Za-z0-9_]+\\)" 1)
160 ("Actions" "^actions\\s-+\\([A-Za-z0-9_]+\\)" 1)))
161 (imenu-add-to-menubar "Jam")
162 (make-local-variable 'indent-line-function)
163 (setq indent-line-function 'jam-indent-line)
164 (run-hooks 'jam-mode-hook)
167 (defvar jam-mode-hook nil)
169 (defvar jam-indent-size 2
170 "Amount to indent by in jam-mode")
172 (defvar jam-case-align-to-colon t
173 "Whether to align case statements to the colons")
175 (defun jam-indent-line (&optional whole-exp)
176 "Indent current line"
177 (interactive)
178 (let ((indent (jam-indent-level))
179 (pos (- (point-max) (point))) beg)
180 (beginning-of-line)
181 (setq beg (point))
182 (skip-chars-forward " \t")
183 (if (zerop (- indent (current-column)))
185 (delete-region beg (point))
186 (indent-to indent))
187 (if (> (- (point-max) pos) (point))
188 (goto-char (- (point-max) pos)))
191 (defun jam-skip-chars-backward (pattern)
192 (let ((line-start (save-excursion
193 (forward-line 0)
194 (point))))
195 (skip-chars-backward pattern line-start)
196 (while (and (not (bobp))
197 (= (point) line-start))
198 (forward-line -1)
199 (setq line-start (point))
200 (skip-chars-forward "^\n\r#")
201 (skip-chars-backward pattern line-start))))
204 (defun jam-goto-block-start ()
205 "Goto the start of the block containing point (or beginning of buffer if not
206 in a block"
207 (let ((l 1))
208 (while (and (not (bobp)) (> l 0))
209 (jam-skip-chars-backward "^{}")
210 (unless (bobp)
211 (backward-char)
212 (setq l (cond
213 ((eq (char-after) ?{) (1- l))
214 ((eq (char-after) ?}) (1+ l))
217 (bobp))
220 (defun jam-indent-level ()
221 (save-excursion
222 (let ((p (point))
224 (is-block-start nil)
225 (is-block-end nil)
226 (is-case nil)
227 (is-switch nil)
228 switch-ind)
229 ;; see what's on this line
230 (beginning-of-line)
231 (setq is-block-end (looking-at "^[^#{\n\r]*}\\s-*\\(#.*\\)?$"))
232 (setq is-block-start (looking-at "^[^#\n]*{\\s-*\\(#.*\\)?$"))
233 (setq is-case (looking-at "\\s-*case.*:"))
235 ;; Find indentation for standard line
236 (setq ind
237 (catch 'find-ind
238 ;; If we are at beginning the indent is 0
239 (if (bobp)
240 (throw 'find-ind 0))
241 ;; Now check if we are in the middle of an opened statement
242 (let ((line-start (point))
243 block-ind
244 block-start)
245 (save-excursion
246 (if (jam-goto-block-start)
247 (setq block-ind 0)
248 (setq block-ind (+ (current-indentation) jam-indent-size)))
249 ;; Check if this block is an actions block
250 (if (and (not (bobp))
251 (looking-at "^\\s-*{\\s-*\\(#.*\\)?$"))
252 (progn
253 (forward-line -1)
254 (if (looking-at "^\\s-*actions")
255 (throw 'find-ind block-ind)
256 (forward-line 1))))
257 (setq block-start (point)))
259 (forward-line -1)
260 ;; Block start is on previous line, then we automatically take the block indent
261 (if (= (point) block-start)
262 (throw 'find-ind block-ind))
263 ;; Loop backwards until we hit a line with a semicolon or block start
264 (while (and (> (point) block-start)
265 (not (looking-at "^[^#\n\r]*[;}]\\s-*\\(#.*\\)?$")))
266 (forward-line -1))
267 ;; Now our deciding statement is on next non-empty line
268 (forward-line 1)
269 (while (and (< (point) line-start)
270 (looking-at "^\\s-*\\(#.*\\)?$"))
271 (forward-line 1))
272 ;; If we ended up on our original line, just take block indent
273 (if (= (point) line-start)
274 (throw 'find-ind block-ind))
275 ;; Now we need to pick the indentation based on if we are a block start or not.
276 (if is-block-start
277 (current-indentation)
278 (+ (current-indentation) jam-indent-size))
281 ;; increase indent in switch statements (not cases)
282 (setq is-switch (re-search-backward "^\\s-*switch" (- (point) 100) t))
283 (when (and is-switch (not (or is-block-end is-case)))
284 (goto-char p)
285 (setq ind (if (and jam-case-align-to-colon
286 (re-search-backward "^\\s-*case.*?\\(:\\)"))
287 (+ (- (match-beginning 1) (match-beginning 0))
288 jam-indent-size)
289 (+ ind jam-indent-size)))
292 ;; indentation of this line is jam-indent-size more than that of the
293 ;; previous block
294 (cond (is-block-start ind)
295 (is-block-end (- ind jam-indent-size))
296 (is-case ind)
297 (t ind)
301 (provide 'jam-mode)
303 ;; jam-mode.el ends here