1;;; conf-mode.el --- Simple major mode for editing conf/ini/properties files -*- lexical-binding: t; -*- 2 3;; Copyright (C) 2004-2021 Free Software Foundation, Inc. 4 5;; Author: Daniel Pfeiffer <occitan@esperanto.org> 6;; Keywords: conf ini windows java 7 8;; This file is part of GNU Emacs. 9 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 3 of the License, or 13;; (at your option) any later version. 14 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. 19 20;; You should have received a copy of the GNU General Public License 21;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 22 23;;; Commentary: 24;; 25;; This mode is designed to edit many similar varieties of Conf/Ini files and 26;; Java properties. It started out from Aurélien Tisné's ini-mode. 27;; `conf-space-keywords' were inspired by Robert Fitzgerald's any-ini-mode. 28 29 30;;; Code: 31 32(require 'newcomment) 33 34(defvar outline-heading-end-regexp) 35 36;; Variables: 37 38(defgroup conf nil 39 "Configuration files." 40 :group 'data 41 :version "22.1") 42 43(defcustom conf-assignment-column 24 44 "Align assignments to this column by default with \\[conf-align-assignments]. 45If this number is negative, the `=' comes before the whitespace. Use 0 to 46not align (only setting space according to `conf-assignment-space')." 47 :type 'integer 48 :group 'conf) 49 50(defcustom conf-javaprop-assignment-column 32 51 "Value for `conf-assignment-column' in Java properties buffers." 52 :type 'integer 53 :group 'conf) 54 55(defcustom conf-colon-assignment-column (- (abs conf-assignment-column)) 56 "Value for `conf-assignment-column' in Java properties buffers." 57 :type 'integer 58 :group 'conf) 59 60(defcustom conf-assignment-space t 61 "Put at least one space around assignments when aligning." 62 :type 'boolean 63 :group 'conf) 64 65(defcustom conf-colon-assignment-space nil 66 "Value for `conf-assignment-space' in colon style Conf mode buffers." 67 :type 'boolean 68 :group 'conf) 69 70(defvar conf-mode-map 71 (let ((map (make-sparse-keymap)) 72 (menu-map (make-sparse-keymap))) 73 (define-key map "\C-c\C-u" 'conf-unix-mode) 74 (define-key map "\C-c\C-w" 'conf-windows-mode) 75 (define-key map "\C-c\C-j" 'conf-javaprop-mode) 76 (define-key map "\C-c\C-s" 'conf-space-keywords) 77 (define-key map "\C-c " 'conf-space-keywords) 78 (define-key map "\C-c\C-c" 'conf-colon-mode) 79 (define-key map "\C-c:" 'conf-colon-mode) 80 (define-key map "\C-c\C-x" 'conf-xdefaults-mode) 81 (define-key map "\C-c\C-p" 'conf-ppd-mode) 82 (define-key map "\C-c\C-q" 'conf-quote-normal) 83 (define-key map "\C-c\"" 'conf-quote-normal) 84 (define-key map "\C-c'" 'conf-quote-normal) 85 (define-key map "\C-c\C-a" 'conf-align-assignments) 86 (define-key map [menu-bar sh-script] (cons "Conf" menu-map)) 87 (define-key menu-map [conf-windows-mode] 88 '(menu-item "Windows mode" 89 conf-windows-mode 90 :help "Conf Mode starter for Windows style Conf files" 91 :button (:radio . (eq major-mode 'conf-windows-mode)))) 92 (define-key menu-map [conf-javaprop-mode] 93 '(menu-item "Java properties mode" 94 conf-javaprop-mode 95 :help "Conf Mode starter for Java properties files" 96 :button (:radio . (eq major-mode 'conf-javaprop-mode)))) 97 (define-key menu-map [conf-space-keywords] 98 '(menu-item "Space keywords mode..." 99 conf-space-keywords 100 :help "Enter Conf Space mode using regexp KEYWORDS to match the keywords" 101 :button (:radio . (eq major-mode 'conf-space-keywords)))) 102 (define-key menu-map [conf-ppd-mode] 103 '(menu-item "PPD mode" 104 conf-ppd-mode 105 :help "Conf Mode starter for Adobe/CUPS PPD files" 106 :button (:radio . (eq major-mode 'conf-ppd-mode)))) 107 (define-key menu-map [conf-colon-mode] 108 '(menu-item "Colon mode" 109 conf-colon-mode 110 :help "Conf Mode starter for Colon files" 111 :button (:radio . (eq major-mode 'conf-colon-mode)))) 112 (define-key menu-map [conf-unix-mode] 113 '(menu-item "Unix mode" 114 conf-unix-mode 115 :help "Conf Mode starter for Unix style Conf files" 116 :button (:radio . (eq major-mode 'conf-unix-mode)))) 117 (define-key menu-map [conf-xdefaults-mode] 118 '(menu-item "Xdefaults mode" 119 conf-xdefaults-mode 120 :help "Conf Mode starter for Xdefaults files" 121 :button (:radio . (eq major-mode 'conf-xdefaults-mode)))) 122 (define-key menu-map [c-s0] '("--")) 123 (define-key menu-map [conf-quote-normal] 124 '(menu-item "Set quote syntax normal" conf-quote-normal 125 :help "Set the syntax of \\=' and \" to punctuation")) 126 (define-key menu-map [conf-align-assignments] 127 '(menu-item "Align assignments" conf-align-assignments 128 :help "Align assignments")) 129 map) 130 "Local keymap for `conf-mode' buffers.") 131 132(defvar conf-mode-syntax-table 133 (let ((table (make-syntax-table))) 134 (modify-syntax-entry ?= "." table) 135 (modify-syntax-entry ?_ "_" table) 136 (modify-syntax-entry ?- "_" table) 137 (modify-syntax-entry ?. "_" table) 138 (modify-syntax-entry ?' "\"" table) 139 (modify-syntax-entry ?\; "<" table) 140 (modify-syntax-entry ?\n ">" table) 141 (modify-syntax-entry ?\r ">" table) 142 table) 143 "Syntax table in use in Windows style `conf-mode' buffers.") 144 145(defvar conf-unix-mode-syntax-table 146 (let ((table (make-syntax-table conf-mode-syntax-table))) 147 (modify-syntax-entry ?\# "<" table) 148 ;; override 149 (modify-syntax-entry ?\; "." table) 150 table) 151 "Syntax table in use in Unix style `conf-mode' buffers.") 152 153(defvar conf-javaprop-mode-syntax-table 154 (let ((table (make-syntax-table conf-unix-mode-syntax-table))) 155 (modify-syntax-entry ?/ ". 124" table) 156 (modify-syntax-entry ?* ". 23b" table) 157 table) 158 "Syntax table in use in Java properties buffers.") 159 160(defvar conf-ppd-mode-syntax-table 161 (let ((table (make-syntax-table conf-mode-syntax-table))) 162 (modify-syntax-entry ?* ". 1" table) 163 (modify-syntax-entry ?% ". 2" table) 164 ;; override 165 (modify-syntax-entry ?\' "." table) 166 (modify-syntax-entry ?\; "." table) 167 table) 168 "Syntax table in use in PPD `conf-mode' buffers.") 169 170(defvar conf-xdefaults-mode-syntax-table 171 (let ((table (make-syntax-table conf-mode-syntax-table))) 172 (modify-syntax-entry ?! "<" table) 173 ;; override 174 (modify-syntax-entry ?\; "." table) 175 table) 176 "Syntax table in use in Xdefaults style `conf-mode' buffers.") 177 178(defvar conf-toml-mode-syntax-table 179 (let ((table (make-syntax-table conf-mode-syntax-table))) 180 (modify-syntax-entry ?\" "\"" table) 181 (modify-syntax-entry ?' "\"" table) 182 (modify-syntax-entry ?\\ "\\" table) 183 (modify-syntax-entry ?# "<" table) 184 ;; override 185 (modify-syntax-entry ?\; "." table) 186 table) 187 "Syntax table in use in TOML style `conf-mode' buffers.") 188 189(defvar conf-font-lock-keywords 190 '(;; [section] (do this first because it may look like a parameter) 191 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face) 192 ;; var=val or var[index]=val 193 ("^[ \t]*\\(.+?\\)\\(?:\\[\\(.*?\\)\\]\\)?[ \t]*=" 194 (1 'font-lock-variable-name-face) 195 (2 'font-lock-constant-face nil t)) 196 ;; section { ... } (do this last because some assign ...{...) 197 ("^[ \t]*\\([^#=:\n]+?\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face prepend)) 198 "Keywords to highlight in Conf mode.") 199 200(defvar conf-javaprop-font-lock-keywords 201 '(;; var=val 202 ("^[ \t]*\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(?:\\.\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(?:\\.\\(.+?\\)\\(?:\\.\\([0-9]+\\)\\(\\..+?\\)?\\)?\\)?\\)?\\)?\\)?\\([:= \t]\\|$\\)" 203 (1 'font-lock-variable-name-face) 204 (2 'font-lock-constant-face nil t) 205 (3 'font-lock-variable-name-face nil t) 206 (4 'font-lock-constant-face nil t) 207 (5 'font-lock-variable-name-face nil t) 208 (6 'font-lock-constant-face nil t) 209 (7 'font-lock-variable-name-face nil t))) 210 "Keywords to highlight in Conf Java Properties mode.") 211 212(defvar conf-space-keywords-alist 213 '(("\\`/etc/gpm/" . "key\\|name\\|foreground\\|background\\|border\\|head") 214 ("\\`/etc/magic\\'" . "[^ \t]+[ \t]+\\(?:[bl]?e?\\(?:short\\|long\\)\\|byte\\|string\\)[^ \t]*") 215 ("/mod\\(?:ules\\|probe\\)\\.conf" . "alias\\|in\\(?:clude\\|stall\\)\\|options\\|remove") 216 ("/manpath\\.config" . "MAN\\(?:DATORY_MANPATH\\|PATH_MAP\\|DB_MAP\\)") 217 ("/sensors\\.conf" . "chip\\|bus\\|label\\|compute\\|set\\|ignore") 218 ("/sane\\(\\.d\\)?/" . "option\\|device\\|port\\|usb\\|sc\\(?:si\\|anner\\)") 219 ("/resmgr\\.conf" . "class\\|add\\|allow\\|deny") 220 ("/dictionary\\.lst\\'" . "DICT\\|HYPH\\|THES") 221 ("/tuxracer/options" . "set")) 222 "File-name-based settings for the variable `conf-space-keywords'.") 223 224(defvar conf-space-keywords nil 225 "Regexps for functions that may come before a space assignment. 226This allows constructs such as 227keyword var value 228This variable is best set in the file local variables, or through 229`conf-space-keywords-alist'.") 230(put 'conf-space-keywords 'safe-local-variable 'stringp) 231 232(defvar conf-space-font-lock-keywords 233 '(;; [section] (do this first because it may look like a parameter) 234 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face) 235 ;; section { ... } (do this first because it looks like a parameter) 236 ("^[ \t]*\\(.+?\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face) 237 ;; var val 238 (eval if conf-space-keywords 239 (list (concat "^[ \t]*\\(" conf-space-keywords "\\)[ \t]+\\([^\000- ]+\\)") 240 '(1 'font-lock-keyword-face) 241 '(2 'font-lock-variable-name-face)) 242 '("^[ \t]*\\([^\000- ]+\\)" 1 'font-lock-variable-name-face))) 243 "Keywords to highlight in Conf Space mode.") 244 245(defvar conf-colon-font-lock-keywords 246 '(;; [section] (do this first because it may look like a parameter) 247 ("^[ \t]*\\[\\(.+\\)\\]" 1 'font-lock-type-face) 248 ;; var: val 249 ("^[ \t]*\\(.+?\\)[ \t]*:" 250 (1 'font-lock-variable-name-face)) 251 ;; section { ... } (do this last because some assign ...{...) 252 ("^[ \t]*\\([^:\n]+\\)[ \t\n]*{[^{}]*?$" 1 'font-lock-type-face prepend)) 253 "Keywords to highlight in Conf Colon mode.") 254 255(defvar conf-toml-font-lock-keywords 256 '(;; [section] (do this first because it may look like a parameter) 257 (conf-toml-recognize-section 0 'font-lock-type-face prepend) 258 ;; var=val or var[index]=val 259 ("^\\s-*\\(.+?\\)\\(?:\\[\\(.*?\\)\\]\\)?\\s-*=" 260 (1 'font-lock-variable-name-face) 261 (2 'font-lock-constant-face nil t)) 262 ("\\_<false\\|true\\_>" 0 'font-lock-keyword-face)) 263 "Keywords to highlight in Conf TOML mode.") 264 265(defvar conf-desktop-font-lock-keywords 266 `(,@conf-font-lock-keywords 267 ("\\_<false\\|true\\_>" 0 'font-lock-constant-face) 268 ("\\_<%[uUfFick%]\\_>" 0 'font-lock-constant-face)) 269 "Keywords to highlight in Conf Desktop mode.") 270 271(defvar conf-assignment-sign ?= 272 "Sign used for assignments (char or string).") 273 274(defvar conf-assignment-regexp ".+?\\([ \t]*=[ \t]*\\)" 275 "Regexp to recognize assignments. 276It is anchored after the first sexp on a line. There must be a 277grouping for the assignment sign, including leading and trailing 278whitespace.") 279 280 281;; If anybody can figure out how to get the same effect by configuring 282;; `align', I'd be glad to hear. 283(defun conf-align-assignments (&optional arg) 284 "Align the assignments in the buffer or active region. 285In Transient Mark mode, if the mark is active, operate on the 286contents of the region. Otherwise, operate on the whole buffer." 287 (interactive "P") 288 (setq arg (if arg 289 (prefix-numeric-value arg) 290 conf-assignment-column)) 291 (save-excursion 292 (save-restriction 293 (when (use-region-p) 294 (narrow-to-region (region-beginning) (region-end))) 295 (goto-char (point-min)) 296 (while (not (eobp)) 297 (let ((cs (comment-beginning))) ; go before comment if within 298 (if cs (goto-char cs))) 299 (while (forward-comment 9)) ; max-int? 300 (when (and (not (eobp)) 301 (looking-at conf-assignment-regexp)) 302 (goto-char (match-beginning 1)) 303 (delete-region (point) (match-end 1)) 304 (if conf-assignment-sign 305 (if (>= arg 0) 306 (progn 307 (indent-to-column arg) 308 (or (not conf-assignment-space) 309 (memq (char-before (point)) '(?\s ?\t)) (insert ?\s)) 310 (insert conf-assignment-sign 311 (if (and conf-assignment-space (not (eolp))) ?\s ""))) 312 (insert (if conf-assignment-space ?\s "") conf-assignment-sign) 313 (unless (eolp) 314 (indent-to-column (- arg)) 315 (or (not conf-assignment-space) 316 (memq (char-before (point)) '(?\s ?\t)) (insert ?\s)))) 317 (unless (eolp) 318 (if (>= (current-column) (abs arg)) 319 (insert ?\s) 320 (indent-to-column (abs arg)))))) 321 (forward-line))))) 322 323 324(defun conf-quote-normal (arg) 325 "Set the syntax of \\=' and \" to punctuation. 326With prefix ARG, only do it for \\=' if 1, or only for \" if 2. 327This only affects the current buffer. Some conf files use quotes 328to delimit strings, while others allow quotes as simple parts of 329the assigned value. In those files font locking will be wrong, 330and you can correct it with this command. (Some files even do 331both, i.e. quotes delimit strings, except when they are 332unbalanced, but hey...)" 333 (interactive "P") 334 (let ((table (copy-syntax-table (syntax-table)))) 335 (when (or (not arg) (= (prefix-numeric-value arg) 1)) 336 (modify-syntax-entry ?\' "." table)) 337 (when (or (not arg) (= (prefix-numeric-value arg) 2)) 338 (modify-syntax-entry ?\" "." table)) 339 (set-syntax-table table) 340 (font-lock-flush))) 341 342 343(defun conf-outline-level () 344 (let ((depth 0) 345 (pt (match-end 0))) 346 (condition-case nil 347 (while (setq pt (scan-lists pt -1 1) 348 depth (1+ depth))) 349 (scan-error depth)))) 350 351 352 353;;;###autoload 354(defun conf-mode () 355 "Mode for Unix and Windows Conf files and Java properties. 356Most conf files know only three kinds of constructs: parameter 357assignments optionally grouped into sections and comments. Yet 358there is a great range of variation in the exact syntax of conf 359files. See below for various wrapper commands that set up the 360details for some of the most widespread variants. 361 362This mode sets up font locking, outline, imenu and it provides 363alignment support through `conf-align-assignments'. If strings 364come out wrong, try `conf-quote-normal'. 365 366Some files allow continuation lines, either with a backslash at 367the end of line, or by indenting the next line (further). These 368constructs cannot currently be recognized. 369 370Because of this great variety of nuances, which are often not 371even clearly specified, please don't expect it to get every file 372quite right. Patches that clearly identify some special case, 373without breaking the general ones, are welcome. 374 375If instead you start this mode with the generic `conf-mode' 376command, it will parse the buffer. It will generally well 377identify the first four cases listed below. If the buffer 378doesn't have enough contents to decide, this is identical to 379`conf-windows-mode' on Windows, elsewhere to `conf-unix-mode'. 380See also `conf-space-mode', `conf-colon-mode', `conf-javaprop-mode', 381`conf-ppd-mode' and `conf-xdefaults-mode'. 382 383\\{conf-mode-map}" 384 385 (interactive) 386 ;; `conf-mode' plays two roles: it's the parent of several sub-modes 387 ;; but it's also the function that chooses between those submodes. 388 ;; To tell the difference between those two cases where the function 389 ;; might be called, we check `delay-mode-hooks'. 390 ;; (adopted from tex-mode.el) 391 (if (not delay-mode-hooks) 392 ;; try to guess sub-mode of conf-mode based on buffer content 393 (let ((unix 0) (win 0) (equal 0) (colon 0) (space 0) (jp 0)) 394 (save-excursion 395 (goto-char (point-min)) 396 (while (not (eobp)) 397 (skip-chars-forward " \t\f") 398 (cond ((eq (char-after) ?\#) (setq unix (1+ unix))) 399 ((eq (char-after) ?\;) (setq win (1+ win))) 400 ((eq (char-after) ?\[)) ; nop 401 ((eolp)) ; nop 402 ((eq (char-after) ?})) ; nop 403 ;; recognize at most double spaces within names 404 ((looking-at "[^ \t\n=:]+\\(?: ?[^ \t\n=:]+\\)*[ \t]*[=:]") 405 (if (eq (char-before (match-end 0)) ?=) 406 (setq equal (1+ equal)) 407 (setq colon (1+ colon)))) 408 ((looking-at "/[/*]") (setq jp (1+ jp))) 409 ((looking-at ".*{")) ; nop 410 ((setq space (1+ space)))) 411 (forward-line))) 412 (cond 413 ((> jp (max unix win 3)) (conf-javaprop-mode)) 414 ((> colon (max equal space)) (conf-colon-mode)) 415 ((> space (max equal colon)) (conf-space-mode)) 416 ((or (> win unix) (and (= win unix) (eq system-type 'windows-nt))) 417 (conf-windows-mode)) 418 (t (conf-unix-mode)))) 419 420 (kill-all-local-variables) 421 (use-local-map conf-mode-map) 422 (setq major-mode 'conf-mode 423 mode-name "Conf[?]") 424 (set (make-local-variable 'font-lock-defaults) 425 '(conf-font-lock-keywords nil t nil nil)) 426 ;; Let newcomment.el decide this for itself. 427 ;; (set (make-local-variable 'comment-use-syntax) t) 428 (set (make-local-variable 'parse-sexp-ignore-comments) t) 429 (set (make-local-variable 'outline-regexp) 430 "[ \t]*\\(?:\\[\\|.+[ \t\n]*{\\)") 431 (set (make-local-variable 'outline-heading-end-regexp) 432 "[\n}]") 433 (set (make-local-variable 'outline-level) 434 'conf-outline-level) 435 (set-syntax-table conf-mode-syntax-table) 436 (setq imenu-generic-expression 437 '(("Parameters" "^[ \t]*\\(.+?\\)[ \t]*=" 1) 438 ;; [section] 439 (nil "^[ \t]*\\[[ \t]*\\(.+\\)[ \t]*\\]" 1) 440 ;; section { ... } 441 (nil "^[ \t]*\\([^=:{} \t\n][^=:{}\n]+\\)[ \t\n]*{" 1))) 442 (run-mode-hooks 'conf-mode-hook))) 443 444(defun conf-mode-initialize (comment &optional font-lock) 445 "Initializations for sub-modes of `conf-mode'. 446COMMENT initializes `comment-start' and `comment-start-skip'. 447The optional arg FONT-LOCK is the value for FONT-LOCK-KEYWORDS." 448 (set (make-local-variable 'comment-start) comment) 449 (set (make-local-variable 'comment-start-skip) 450 (concat (regexp-quote comment-start) "+\\s *")) 451 (if font-lock 452 (set (make-local-variable 'font-lock-defaults) 453 `(,font-lock nil t nil nil)))) 454 455;;;###autoload 456(define-derived-mode conf-unix-mode conf-mode "Conf[Unix]" 457 "Conf Mode starter for Unix style Conf files. 458Comments start with `#'. For details see `conf-mode'." 459 (conf-mode-initialize "#")) 460 461;;;###autoload 462(define-derived-mode conf-windows-mode conf-mode "Conf[WinIni]" 463 "Conf Mode starter for Windows style Conf files. 464Comments start with `;'. 465For details see `conf-mode'. Example: 466 467; Conf mode font-locks this right on Windows and with \\[conf-windows-mode] 468 469[ExtShellFolderViews] 470Default={5984FFE0-28D4-11CF-AE66-08002B2E1262} 471{5984FFE0-28D4-11CF-AE66-08002B2E1262}={5984FFE0-28D4-11CF-AE66-08002B2E1262} 472 473[{5984FFE0-28D4-11CF-AE66-08002B2E1262}] 474PersistMoniker=file://Folder.htt" 475 (conf-mode-initialize ";")) 476 477;; Here are a few more or less widespread styles. There are others, so 478;; obscure, they are not covered. E.g. RFC 2614 allows both Unix and Windows 479;; comments. Or the donkey has (* Pascal comments *) -- roll your own starter 480;; if you need it. 481 482;;;###autoload 483(define-derived-mode conf-javaprop-mode conf-mode "Conf[JavaProp]" 484 "Conf Mode starter for Java properties files. 485Comments start with `#' but are also recognized with `//' or 486between `/*' and `*/'. 487For details see `conf-mode'. Example: 488 489# Conf mode font-locks this right with \\[conf-javaprop-mode] (Java properties) 490// another kind of comment 491/* yet another */ 492 493name:value 494name=value 495name value 496x.1 = 497x.2.y.1.z.1 = 498x.2.y.1.z.2.zz =" 499 (conf-mode-initialize "#" 'conf-javaprop-font-lock-keywords) 500 (set (make-local-variable 'conf-assignment-column) 501 conf-javaprop-assignment-column) 502 (set (make-local-variable 'conf-assignment-regexp) 503 ".+?\\([ \t]*[=: \t][ \t]*\\|$\\)") 504 (setq comment-start-skip "\\(?:#+\\|/[/*]+\\)\\s *") 505 (setq imenu-generic-expression 506 '(("Parameters" "^[ \t]*\\(.+?\\)[=: \t]" 1)))) 507 508;;;###autoload 509(define-derived-mode conf-space-mode conf-unix-mode "Conf[Space]" 510 "Conf Mode starter for space separated conf files. 511\"Assignments\" are with ` '. Keywords before the parameters are 512recognized according to the variable `conf-space-keywords-alist'. 513Alternatively, you can specify a value for the file local variable 514`conf-space-keywords'. 515Use the function `conf-space-keywords' if you want to specify keywords 516in an interactive fashion instead. 517 518For details see `conf-mode'. Example: 519 520# Conf mode font-locks this right with \\[conf-space-mode] (space separated) 521 522image/jpeg jpeg jpg jpe 523image/png png 524image/tiff tiff tif 525 526# Or with keywords (from a recognized file name): 527class desktop 528# Standard multimedia devices 529add /dev/audio desktop 530add /dev/mixer desktop" 531 (conf-mode-initialize "#" 'conf-space-font-lock-keywords) 532 (make-local-variable 'conf-assignment-sign) 533 (setq conf-assignment-sign nil) 534 (make-local-variable 'conf-space-keywords) 535 (cond (buffer-file-name 536 ;; We set conf-space-keywords directly, but a value which is 537 ;; in the local variables list or interactively specified 538 ;; (see the function conf-space-keywords) takes precedence. 539 (setq conf-space-keywords 540 (assoc-default buffer-file-name conf-space-keywords-alist 541 'string-match)))) 542 (conf-space-mode-internal) 543 ;; In case the local variables list specifies conf-space-keywords, 544 ;; recompute other things from that afterward. 545 (add-hook 'hack-local-variables-hook 'conf-space-mode-internal nil t)) 546 547;;;###autoload 548(defun conf-space-keywords (keywords) 549 "Enter Conf Space mode using regexp KEYWORDS to match the keywords. 550See `conf-space-mode'." 551 (interactive "sConf Space keyword regexp: ") 552 (delay-mode-hooks 553 (conf-space-mode)) 554 (if (string-equal keywords "") 555 (setq keywords nil)) 556 (setq conf-space-keywords keywords) 557 (conf-space-mode-internal) 558 (run-mode-hooks)) 559 560(defun conf-space-mode-internal () 561 (make-local-variable 'conf-assignment-regexp) 562 (setq conf-assignment-regexp 563 (if conf-space-keywords 564 (concat "\\(?:" conf-space-keywords "\\)[ \t]+.+?\\([ \t]+\\|$\\)") 565 ".+?\\([ \t]+\\|$\\)")) 566 ;; If Font Lock is already enabled, reenable it with new 567 ;; conf-assignment-regexp. 568 (when (and font-lock-mode 569 (boundp 'font-lock-keywords)) ;see `normal-mode' 570 (font-lock-add-keywords nil nil) 571 (font-lock-mode 1)) 572 ;; Copy so that we don't destroy shared structure. 573 (setq imenu-generic-expression (copy-sequence imenu-generic-expression)) 574 ;; Get rid of any existing Parameters element. 575 (setq imenu-generic-expression 576 (delq (assoc "Parameters" imenu-generic-expression) 577 imenu-generic-expression)) 578 ;; Add a new one based on conf-space-keywords. 579 (setq imenu-generic-expression 580 (cons `("Parameters" 581 ,(if conf-space-keywords 582 (concat "^[ \t]*\\(?:" conf-space-keywords 583 "\\)[ \t]+\\([^ \t\n]+\\)\\(?:[ \t]\\|$\\)") 584 "^[ \t]*\\([^ \t\n[]+\\)\\(?:[ \t]\\|$\\)") 585 1) 586 imenu-generic-expression))) 587 588;;;###autoload 589(define-derived-mode conf-colon-mode conf-unix-mode "Conf[Colon]" 590 "Conf Mode starter for Colon files. 591\"Assignments\" are with `:'. 592For details see `conf-mode'. Example: 593 594# Conf mode font-locks this right with \\[conf-colon-mode] (colon) 595 596<Multi_key> <exclam> <exclam> : \"\\241\" exclamdown 597<Multi_key> <c> <slash> : \"\\242\" cent" 598 (conf-mode-initialize "#" 'conf-colon-font-lock-keywords) 599 (set (make-local-variable 'conf-assignment-space) 600 conf-colon-assignment-space) 601 (set (make-local-variable 'conf-assignment-column) 602 conf-colon-assignment-column) 603 (set (make-local-variable 'conf-assignment-sign) 604 ?:) 605 (set (make-local-variable 'conf-assignment-regexp) 606 ".+?\\([ \t]*:[ \t]*\\)") 607 (setq imenu-generic-expression 608 `(("Parameters" "^[ \t]*\\(.+?\\)[ \t]*:" 1) 609 ,@(cdr imenu-generic-expression)))) 610 611;;;###autoload 612(define-derived-mode conf-ppd-mode conf-colon-mode "Conf[PPD]" 613 "Conf Mode starter for Adobe/CUPS PPD files. 614Comments start with `*%' and \"assignments\" are with `:'. 615For details see `conf-mode'. Example: 616 617*% Conf mode font-locks this right with \\[conf-ppd-mode] (PPD) 618 619*DefaultTransfer: Null 620*Transfer Null.Inverse: \"{ 1 exch sub }\"" 621 (conf-mode-initialize "*%") 622 ;; no sections, they match within PostScript code 623 (setq imenu-generic-expression (list (car imenu-generic-expression)))) 624 625;;;###autoload 626(define-derived-mode conf-xdefaults-mode conf-colon-mode "Conf[Xdefaults]" 627 "Conf Mode starter for Xdefaults files. 628Comments start with `!' and \"assignments\" are with `:'. 629For details see `conf-mode'. Example: 630 631! Conf mode font-locks this right with \\[conf-xdefaults-mode] (.Xdefaults) 632 633*background: gray99 634*foreground: black" 635 (conf-mode-initialize "!")) 636 637(defun conf-toml-recognize-section (limit) 638 "Font-lock helper function for conf-toml-mode. 639Handles recognizing TOML section names, like [section], 640\[[section]], or [something.\"else\".section]." 641 (save-excursion 642 ;; Skip any number of "[" to handle things like [[section]]. 643 (when (re-search-forward "^\\s-*\\[+" limit t) 644 (let ((start (point))) 645 (backward-char) 646 (let ((end (min limit 647 (condition-case nil 648 (progn 649 (forward-list) 650 (1- (point))) 651 (scan-error 652 (end-of-line) 653 (point)))))) 654 ;; If there is a comma in the text, then we assume this is 655 ;; an array and not a section. (This could be refined to 656 ;; look only for unquoted commas if necessary.) 657 (save-excursion 658 (goto-char start) 659 (unless (search-forward "," end t) 660 (set-match-data (list start end)) 661 t))))))) 662 663;;;###autoload 664(define-derived-mode conf-toml-mode conf-mode "Conf[TOML]" 665 "Conf Mode starter for TOML files. 666Comments start with `#' and \"assignments\" are with `='. 667For details see `conf-mode'. Example: 668 669# Conf mode font-locks this right with \\[conf-toml-mode] 670 671\[entry] 672value = \"some string\"" 673 (conf-mode-initialize "#" 'conf-toml-font-lock-keywords) 674 (setq-local conf-assignment-column 0) 675 (setq-local conf-assignment-sign ?=)) 676 677;;;###autoload 678(define-derived-mode conf-desktop-mode conf-unix-mode "Conf[Desktop]" 679 "Conf Mode started for freedesktop.org Desktop files. 680Comments start with `#' and \"assignments\" are with `='. 681For details see `conf-mode'. 682 683# Conf mode font-locks this correctly with \\[conf-desktop-mode] 684 [Desktop Entry] 685 Name=GNU Image Manipulation Program 686 Name[oc]=Editor d'imatge GIMP 687 Exec=gimp-2.8 %U 688 Terminal=false" 689 (conf-mode-initialize "#" 'conf-desktop-font-lock-keywords) 690 (conf-quote-normal nil)) 691 692(provide 'conf-mode) 693 694;;; conf-mode.el ends here 695