1 ;;; conf-mode.el --- Simple major mode for editing conf/ini/properties files
3 ;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
5 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
6 ;; Keywords: conf ini windows java
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
27 ;; This mode is designed to edit many similar varieties of Conf/Ini files and
28 ;; Java properties. It started out from Aurélien Tisné's ini-mode.
29 ;; `conf-space-keywords' were inspired by Robert Fitzgerald's any-ini-mode.
36 (defvar outline-heading-end-regexp
)
41 "Configuration files."
45 (defcustom conf-assignment-column
24
46 "Align assignments to this column by default with \\[conf-align-assignments].
47 If this number is negative, the `=' comes before the whitespace. Use 0 to
48 not align (only setting space according to `conf-assignment-space')."
52 (defcustom conf-javaprop-assignment-column
32
53 "Value for `conf-assignment-column' in Java properties buffers."
57 (defcustom conf-colon-assignment-column
(- (abs conf-assignment-column
))
58 "Value for `conf-assignment-column' in Java properties buffers."
62 (defcustom conf-assignment-space t
63 "Put at least one space around assignments when aligning."
67 (defcustom conf-colon-assignment-space nil
68 "Value for `conf-assignment-space' in colon style Conf mode buffers."
74 (let ((map (make-sparse-keymap)))
75 (define-key map
"\C-c\C-u" 'conf-unix-mode
)
76 (define-key map
"\C-c\C-w" 'conf-windows-mode
)
77 (define-key map
"\C-c\C-j" 'conf-javaprop-mode
)
78 (define-key map
"\C-c\C-s" 'conf-space-mode
)
79 (define-key map
"\C-c " 'conf-space-mode
)
80 (define-key map
"\C-c\C-c" 'conf-colon-mode
)
81 (define-key map
"\C-c:" 'conf-colon-mode
)
82 (define-key map
"\C-c\C-x" 'conf-xdefaults-mode
)
83 (define-key map
"\C-c\C-p" 'conf-ppd-mode
)
84 (define-key map
"\C-c\C-q" 'conf-quote-normal
)
85 (define-key map
"\C-c\"" 'conf-quote-normal
)
86 (define-key map
"\C-c'" 'conf-quote-normal
)
87 (define-key map
"\C-c\C-a" 'conf-align-assignments
)
89 "Local keymap for `conf-mode' buffers.")
91 (defvar conf-mode-syntax-table
92 (let ((table (make-syntax-table)))
93 (modify-syntax-entry ?
= "." table
)
94 (modify-syntax-entry ?_
"_" table
)
95 (modify-syntax-entry ?-
"_" table
)
96 (modify-syntax-entry ?.
"_" table
)
97 (modify-syntax-entry ?
\' "\"" table
)
98 (modify-syntax-entry ?\
; "<" table)
99 (modify-syntax-entry ?
\n ">" table
)
100 (modify-syntax-entry ?
\r ">" table
)
102 "Syntax table in use in Windows style `conf-mode' buffers.")
104 (defvar conf-unix-mode-syntax-table
105 (let ((table (make-syntax-table conf-mode-syntax-table
)))
106 (modify-syntax-entry ?\
# "<" table
)
108 (modify-syntax-entry ?\
; "." table)
110 "Syntax table in use in Unix style `conf-mode' buffers.")
112 (defvar conf-javaprop-mode-syntax-table
113 (let ((table (make-syntax-table conf-unix-mode-syntax-table
)))
114 (modify-syntax-entry ?
/ ". 124" table
)
115 (modify-syntax-entry ?
* ". 23b" table
)
117 "Syntax table in use in Java prperties buffers.")
119 (defvar conf-ppd-mode-syntax-table
120 (let ((table (make-syntax-table conf-mode-syntax-table
)))
121 (modify-syntax-entry ?
* ". 1" table
)
122 (modify-syntax-entry ?%
". 2" table
)
124 (modify-syntax-entry ?
\' "." table
)
125 (modify-syntax-entry ?\
; "." table)
127 "Syntax table in use in PPD `conf-mode' buffers.")
129 (defvar conf-xdefaults-mode-syntax-table
130 (let ((table (make-syntax-table conf-mode-syntax-table
)))
131 (modify-syntax-entry ?
! "<" table
)
133 (modify-syntax-entry ?\
; "." table)
135 "Syntax table in use in Xdefaults style `conf-mode' buffers.")
138 (defvar conf-font-lock-keywords
139 `(;; [section] (do this first because it may look like a parameter)
140 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face
)
141 ;; var=val or var[index]=val
142 ("^[ \t]*\\(.+?\\)\\(?:\\[\\(.*?\\)\\]\\)?[ \t]*="
143 (1 'font-lock-variable-name-face
)
144 (2 'font-lock-constant-face nil t
))
145 ;; section { ... } (do this last because some assign ...{...)
146 ("^[ \t]*\\([^=:\n]+?\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face prepend
))
147 "Keywords to hilight in Conf mode.")
149 (defvar conf-javaprop-font-lock-keywords
151 ("^[ \t]*\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(?:\\.\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(?:\\.\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(\\..+?\\)?\\)?\\)?\\)?\\)?\\)?\\([:= \t]\\|$\\)"
152 (1 'font-lock-variable-name-face
)
153 (2 'font-lock-constant-face nil t
)
154 (3 'font-lock-variable-name-face nil t
)
155 (4 'font-lock-constant-face nil t
)
156 (5 'font-lock-variable-name-face nil t
)
157 (6 'font-lock-constant-face nil t
)
158 (7 'font-lock-variable-name-face nil t
)))
159 "Keywords to hilight in Conf Java Properties mode.")
161 (defvar conf-space-keywords-alist
162 '(("\\`/etc/gpm/" .
"key\\|name\\|foreground\\|background\\|border\\|head")
163 ("\\`/etc/magic\\'" .
"[^ \t]+[ \t]+\\(?:[bl]?e?\\(?:short\\|long\\)\\|byte\\|string\\)[^ \t]*")
164 ("/mod\\(?:ules\\|probe\\)\\.conf" .
"alias\\|in\\(?:clude\\|stall\\)\\|options\\|remove")
165 ("/manpath\\.config" .
"MAN\\(?:DATORY_MANPATH\\|PATH_MAP\\|DB_MAP\\)")
166 ("/sensors\\.conf" .
"chip\\|bus\\|label\\|compute\\|set\\|ignore")
167 ("/sane\\(\\.d\\)?/" .
"option\\|device\\|port\\|usb\\|sc\\(?:si\\|anner\\)")
168 ("/resmgr\\.conf" .
"class\\|add\\|allow\\|deny")
169 ("/dictionary\\.lst\\'" .
"DICT\\|HYPH\\|THES")
170 ("/tuxracer/options" .
"set"))
171 "File name based settings for `conf-space-keywords'.")
173 (defvar conf-space-keywords nil
174 "Regexps for functions that may come before a space assignment.
175 This allows constructs such as
177 This variable is best set in the file local variables, or through
178 `conf-space-keywords-alist'.")
180 (defvar conf-space-font-lock-keywords
181 `(;; [section] (do this first because it may look like a parameter)
182 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face
)
183 ;; section { ... } (do this first because it looks like a parameter)
184 ("^[ \t]*\\(.+?\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face
)
186 (eval if conf-space-keywords
187 (list (concat "^[ \t]*\\(" conf-space-keywords
"\\)[ \t]+\\([^\000- ]+\\)")
188 '(1 'font-lock-keyword-face
)
189 '(2 'font-lock-variable-name-face
))
190 '("^[ \t]*\\([^\000- ]+\\)" 1 'font-lock-variable-name-face
)))
191 "Keywords to hilight in Conf Space mode.")
193 (defvar conf-colon-font-lock-keywords
194 `(;; [section] (do this first because it may look like a parameter)
195 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face
)
197 ("^[ \t]*\\(.+?\\)[ \t]*:"
198 (1 'font-lock-variable-name-face
))
199 ;; section { ... } (do this last because some assign ...{...)
200 ("^[ \t]*\\([^:\n]+\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face prepend
))
201 "Keywords to hilight in Conf Colon mode.")
203 (defvar conf-assignment-sign ?
=
204 "What sign is used for assignments.")
206 (defvar conf-assignment-regexp
".+?\\([ \t]*=[ \t]*\\)"
207 "Regexp to recognize assignments.
208 It is anchored after the first sexp on a line. There must a
209 grouping for the assignment sign, including leading and trailing
213 ;; If anybody can figure out how to get the same effect by configuring
214 ;; `align', I'd be glad to hear.
215 (defun conf-align-assignments (&optional arg
)
218 (prefix-numeric-value arg
)
219 conf-assignment-column
))
221 (goto-char (point-min))
223 (let ((cs (comment-beginning))) ; go before comment if within
224 (if cs
(goto-char cs
)))
225 (while (forward-comment 9)) ; max-int?
226 (when (and (not (eobp))
227 (looking-at conf-assignment-regexp
))
228 (goto-char (match-beginning 1))
229 (delete-region (point) (match-end 1))
230 (if conf-assignment-sign
233 (indent-to-column arg
)
234 (or (not conf-assignment-space
)
235 (memq (char-before (point)) '(?\s ?
\t)) (insert ?\s
))
236 (insert conf-assignment-sign
237 (if (and conf-assignment-space
(not (eolp))) ?\s
"")))
238 (insert (if conf-assignment-space ?\s
"") conf-assignment-sign
)
240 (indent-to-column (- arg
))
241 (or (not conf-assignment-space
)
242 (memq (char-before (point)) '(?\s ?
\t)) (insert ?\s
))))
244 (if (>= (current-column) (abs arg
))
246 (indent-to-column (abs arg
))))))
250 (defun conf-quote-normal (arg)
251 "Set the syntax of ' and \" to punctuation.
252 With prefix arg, only do it for ' if 1, or only for \" if 2.
253 This only affects the current buffer. Some conf files use quotes
254 to delimit strings, while others allow quotes as simple parts of
255 the assigned value. In those files font locking will be wrong,
256 and you can correct it with this command. (Some files even do
257 both, i.e. quotes delimit strings, except when they are
258 unbalanced, but hey...)"
260 (let ((table (copy-syntax-table (syntax-table))))
261 (if (or (not arg
) (= (prefix-numeric-value arg
) 1))
262 (modify-syntax-entry ?
\' "." table
))
263 (if (or (not arg
) (= (prefix-numeric-value arg
) 2))
264 (modify-syntax-entry ?
\" "." table
))
265 (set-syntax-table table
)
266 (and (boundp 'font-lock-mode
)
268 (font-lock-fontify-buffer))))
271 (defun conf-outline-level ()
275 (while (setq pt
(scan-lists pt -
1 1)
277 (scan-error depth
))))
282 (defun conf-mode (&optional comment syntax-table name
)
283 "Mode for Unix and Windows Conf files and Java properties.
284 Most conf files know only three kinds of constructs: parameter
285 assignments optionally grouped into sections and comments. Yet
286 there is a great range of variation in the exact syntax of conf
287 files. See below for various wrapper commands that set up the
288 details for some of the most widespread variants.
290 This mode sets up font locking, outline, imenu and it provides
291 alignment support through `conf-align-assignments'. If strings
292 come out wrong, try `conf-quote-normal'.
294 Some files allow continuation lines, either with a backslash at
295 the end of line, or by indenting the next line (further). These
296 constructs cannot currently be recognized.
298 Because of this great variety of nuances, which are often not
299 even clearly specified, please don't expect it to get every file
300 quite right. Patches that clearly identify some special case,
301 without breaking the general ones, are welcome.
303 If instead you start this mode with the generic `conf-mode'
304 command, it will parse the buffer. It will generally well
305 identify the first four cases listed below. If the buffer
306 doesn't have enough contents to decide, this is identical to
307 `conf-windows-mode' on Windows, elsewhere to `conf-unix-mode'.
308 See also `conf-space-mode', `conf-colon-mode', `conf-javaprop-mode',
309 `conf-ppd-mode' and `conf-xdefaults-mode'.
315 (let ((unix 0) (win 0) (equal 0) (colon 0) (space 0) (jp 0))
317 (goto-char (point-min))
319 (skip-chars-forward " \t\f")
320 (cond ((eq (char-after) ?\
#) (setq unix
(1+ unix
)))
321 ((eq (char-after) ?\
;) (setq win (1+ win)))
322 ((eq (char-after) ?\
[)) ; nop
324 ((eq (char-after) ?
})) ; nop
325 ;; recognize at most double spaces within names
326 ((looking-at "[^ \t\n=:]+\\(?: ?[^ \t\n=:]+\\)*[ \t]*[=:]")
327 (if (eq (char-before (match-end 0)) ?
=)
328 (setq equal
(1+ equal
))
329 (setq colon
(1+ colon
))))
330 ((looking-at "/[/*]") (setq jp
(1+ jp
)))
331 ((looking-at ".*{")) ; nop
332 ((setq space
(1+ space
))))
335 ((> jp
(max unix win
3)) (conf-javaprop-mode))
336 ((> colon
(max equal space
)) (conf-colon-mode))
337 ((> space
(max equal colon
)) (conf-space-mode))
338 ((or (> win unix
) (and (= win unix
) (eq system-type
'windows-nt
)))
340 (t (conf-unix-mode))))
341 (kill-all-local-variables)
342 (use-local-map conf-mode-map
)
344 (setq major-mode
'conf-mode
346 (set (make-local-variable 'font-lock-defaults
)
347 '(conf-font-lock-keywords nil t nil nil
))
348 (set (make-local-variable 'comment-start
) comment
)
349 (set (make-local-variable 'comment-start-skip
)
350 (concat (regexp-quote comment-start
) "+\\s *"))
351 ;; Let newcomment.el decide this for himself.
352 ;; (set (make-local-variable 'comment-use-syntax) t)
353 (set (make-local-variable 'parse-sexp-ignore-comments
) t
)
354 (set (make-local-variable 'outline-regexp
)
355 "[ \t]*\\(?:\\[\\|.+[ \t\n]*{\\)")
356 (set (make-local-variable 'outline-heading-end-regexp
)
358 (set (make-local-variable 'outline-level
)
360 (set-syntax-table syntax-table
)
361 (setq imenu-generic-expression
362 '(("Parameters" "^[ \t]*\\(.+?\\)[ \t]*=" 1)
364 (nil "^[ \t]*\\[[ \t]*\\(.+\\)[ \t]*\\]" 1)
366 (nil "^[ \t]*\\([^=:{} \t\n][^=:{}\n]+\\)[ \t\n]*{" 1)))
368 (run-mode-hooks 'conf-mode-hook
)))
371 (defun conf-unix-mode ()
372 "Conf Mode starter for Unix style Conf files.
373 Comments start with `#'.
374 For details see `conf-mode'. Example:
376 # Conf mode font-locks this right on Unix and with \\[conf-unix-mode]
384 (conf-mode "#" conf-unix-mode-syntax-table
"Conf[Unix]"))
387 (defun conf-windows-mode ()
388 "Conf Mode starter for Windows style Conf files.
389 Comments start with `;'.
390 For details see `conf-mode'. Example:
392 ; Conf mode font-locks this right on Windows and with \\[conf-windows-mode]
394 \[ExtShellFolderViews]
395 Default={5984FFE0-28D4-11CF-AE66-08002B2E1262}
396 {5984FFE0-28D4-11CF-AE66-08002B2E1262}={5984FFE0-28D4-11CF-AE66-08002B2E1262}
398 \[{5984FFE0-28D4-11CF-AE66-08002B2E1262}]
399 PersistMoniker=file://Folder.htt"
401 (conf-mode ";" conf-mode-syntax-table
"Conf[WinIni]"))
403 ;; Here are a few more or less widespread styles. There are others, so
404 ;; obscure, they are not covered. E.g. RFC 2614 allows both Unix and Windows
405 ;; comments. Or the donkey has (* Pascal comments *) -- roll your own starter
409 (defun conf-javaprop-mode ()
410 "Conf Mode starter for Java properties files.
411 Comments start with `#' but are also recognized with `//' or
412 between `/*' and `*/'.
413 For details see `conf-mode'. Example:
415 # Conf mode font-locks this right with \\[conf-javaprop-mode] (Java properties)
416 // another kind of comment
426 (conf-mode "#" conf-javaprop-mode-syntax-table
"Conf[JavaProp]")
427 (set (make-local-variable 'conf-assignment-column
)
428 conf-javaprop-assignment-column
)
429 (set (make-local-variable 'conf-assignment-regexp
)
430 ".+?\\([ \t]*[=: \t][ \t]*\\|$\\)")
431 (set (make-local-variable 'conf-font-lock-keywords
)
432 conf-javaprop-font-lock-keywords
)
433 (setq comment-start-skip
"\\(?:#+\\|/[/*]+\\)\\s *")
434 (setq imenu-generic-expression
435 '(("Parameters" "^[ \t]*\\(.+?\\)[=: \t]" 1))))
438 (defun conf-space-mode (&optional keywords
)
439 "Conf Mode starter for space separated conf files.
440 \"Assignments\" are with ` '. Keywords before the parameters are
441 recognized according to `conf-space-keywords'. Interactively
442 with a prefix ARG of `0' no keywords will be recognized. With
443 any other prefix arg you will be prompted for a regexp to match
444 the keywords. Programmatically you can pass such a regexp as
445 KEYWORDS, or any non-nil non-string for no keywords.
447 For details see `conf-mode'. Example:
449 # Conf mode font-locks this right with \\[conf-space-mode] (space separated)
451 image/jpeg jpeg jpg jpe
455 # Or with keywords (from a recognized file name):
457 # Standard multimedia devices
458 add /dev/audio desktop
459 add /dev/mixer desktop"
461 (list (if current-prefix-arg
462 (if (> (prefix-numeric-value current-prefix-arg
) 0)
463 (read-string "Regexp to match keywords: ")
466 (setq mode-name
"Conf[Space]")
467 (set (make-local-variable 'conf-assignment-sign
)
469 (set (make-local-variable 'conf-font-lock-keywords
)
470 conf-space-font-lock-keywords
)
471 ;; This doesn't seem right, but the next two depend on conf-space-keywords
472 ;; being set, while after-change-major-mode-hook might set up imenu, needing
473 ;; the following result:
474 (hack-local-variables-prop-line)
475 (hack-local-variables)
477 (set (make-local-variable 'conf-space-keywords
)
478 (if (stringp keywords
) keywords
))
479 (or conf-space-keywords
480 (not buffer-file-name
)
481 (set (make-local-variable 'conf-space-keywords
)
482 (assoc-default buffer-file-name conf-space-keywords-alist
484 (set (make-local-variable 'conf-assignment-regexp
)
485 (if conf-space-keywords
486 (concat "\\(?:" conf-space-keywords
"\\)[ \t]+.+?\\([ \t]+\\|$\\)")
487 ".+?\\([ \t]+\\|$\\)"))
488 (setq imenu-generic-expression
489 `(,@(cdr imenu-generic-expression
)
491 ,(if conf-space-keywords
492 (concat "^[ \t]*\\(?:" conf-space-keywords
493 "\\)[ \t]+\\([^ \t\n]+\\)\\(?:[ \t]\\|$\\)")
494 "^[ \t]*\\([^ \t\n[]+\\)\\(?:[ \t]\\|$\\)")
498 (defun conf-colon-mode (&optional comment syntax-table name
)
499 "Conf Mode starter for Colon files.
500 \"Assignments\" are with `:'.
501 For details see `conf-mode'. Example:
503 # Conf mode font-locks this right with \\[conf-colon-mode] (colon)
505 <Multi_key> <exclam> <exclam> : \"\\241\" exclamdown
506 <Multi_key> <c> <slash> : \"\\242\" cent"
509 (conf-mode comment syntax-table name
)
511 (setq mode-name
"Conf[Colon]"))
512 (set (make-local-variable 'conf-assignment-space
)
513 conf-colon-assignment-space
)
514 (set (make-local-variable 'conf-assignment-column
)
515 conf-colon-assignment-column
)
516 (set (make-local-variable 'conf-assignment-sign
)
518 (set (make-local-variable 'conf-assignment-regexp
)
519 ".+?\\([ \t]*:[ \t]*\\)")
520 (set (make-local-variable 'conf-font-lock-keywords
)
521 conf-colon-font-lock-keywords
)
522 (setq imenu-generic-expression
523 `(("Parameters" "^[ \t]*\\(.+?\\)[ \t]*:" 1)
524 ,@(cdr imenu-generic-expression
))))
527 (defun conf-ppd-mode ()
528 "Conf Mode starter for Adobe/CUPS PPD files.
529 Comments start with `*%' and \"assignments\" are with `:'.
530 For details see `conf-mode'. Example:
532 *% Conf mode font-locks this right with \\[conf-ppd-mode] (PPD)
534 *DefaultTransfer: Null
535 *Transfer Null.Inverse: \"{ 1 exch sub }\""
537 (conf-colon-mode "*%" conf-ppd-mode-syntax-table
"Conf[PPD]")
538 ;; no sections, they match within PostScript code
539 (setq imenu-generic-expression
(list (car imenu-generic-expression
))))
542 (defun conf-xdefaults-mode ()
543 "Conf Mode starter for Xdefaults files.
544 Comments start with `!' and \"assignments\" are with `:'.
545 For details see `conf-mode'. Example:
547 ! Conf mode font-locks this right with \\[conf-xdefaults-mode] (.Xdefaults)
552 (conf-colon-mode "!" conf-xdefaults-mode-syntax-table
"Conf[Xdefaults]"))
556 ;; arch-tag: 0a3805b2-0371-4d3a-8498-8897116b2356
557 ;;; conf-mode.el ends here