diff options
Diffstat (limited to 'lisp/progmodes/cfengine.el')
| -rw-r--r-- | lisp/progmodes/cfengine.el | 268 |
1 files changed, 244 insertions, 24 deletions
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el index 22ece17cb28..7989c60f80c 100644 --- a/lisp/progmodes/cfengine.el +++ b/lisp/progmodes/cfengine.el | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | ;; Copyright (C) 2001-2011 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2001-2011 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Dave Love <fx@gnu.org> | 5 | ;; Author: Dave Love <fx@gnu.org> |
| 6 | ;; Maintainer: Ted Zlatanov <tzz@lifelogs.com> | ||
| 6 | ;; Keywords: languages | 7 | ;; Keywords: languages |
| 7 | 8 | ||
| 8 | ;; This file is part of GNU Emacs. | 9 | ;; This file is part of GNU Emacs. |
| @@ -28,6 +29,13 @@ | |||
| 28 | ;; Possible customization for auto-mode selection: | 29 | ;; Possible customization for auto-mode selection: |
| 29 | ;; (push '(("^cfagent.conf\\'" . cfengine-mode)) auto-mode-alist) | 30 | ;; (push '(("^cfagent.conf\\'" . cfengine-mode)) auto-mode-alist) |
| 30 | ;; (push '(("^cf\\." . cfengine-mode)) auto-mode-alist) | 31 | ;; (push '(("^cf\\." . cfengine-mode)) auto-mode-alist) |
| 32 | ;; (push '(("\\.cf\\'" . cfengine-mode)) auto-mode-alist) | ||
| 33 | |||
| 34 | ;; Or, if you want to use the CFEngine 3.x support: | ||
| 35 | |||
| 36 | ;; (push '(("^cfagent.conf\\'" . cfengine3-mode)) auto-mode-alist) | ||
| 37 | ;; (push '(("^cf\\." . cfengine3-mode)) auto-mode-alist) | ||
| 38 | ;; (push '(("\\.cf\\'" . cfengine3-mode)) auto-mode-alist) | ||
| 31 | 39 | ||
| 32 | ;; This is not the same as the mode written by Rolf Ebert | 40 | ;; This is not the same as the mode written by Rolf Ebert |
| 33 | ;; <ebert@waporo.muc.de>, distributed with cfengine-2.0.5. It does | 41 | ;; <ebert@waporo.muc.de>, distributed with cfengine-2.0.5. It does |
| @@ -63,7 +71,27 @@ | |||
| 63 | ;; cfservd | 71 | ;; cfservd |
| 64 | "admit" "grant" "deny") | 72 | "admit" "grant" "deny") |
| 65 | "List of the action keywords supported by Cfengine. | 73 | "List of the action keywords supported by Cfengine. |
| 66 | This includes those for cfservd as well as cfagent.")) | 74 | This includes those for cfservd as well as cfagent.") |
| 75 | |||
| 76 | (defconst cfengine3-defuns | ||
| 77 | (mapcar | ||
| 78 | 'symbol-name | ||
| 79 | '(bundle body)) | ||
| 80 | "List of the CFEngine 3.x defun headings.") | ||
| 81 | |||
| 82 | (defconst cfengine3-defuns-regex | ||
| 83 | (regexp-opt cfengine3-defuns t) | ||
| 84 | "Regex to match the CFEngine 3.x defuns.") | ||
| 85 | |||
| 86 | (defconst cfengine3-class-selector-regex "\\([[:alnum:]_().&|!]+\\)::") | ||
| 87 | |||
| 88 | (defconst cfengine3-category-regex "\\([[:alnum:]_]+\\):") | ||
| 89 | |||
| 90 | (defconst cfengine3-vartypes | ||
| 91 | (mapcar | ||
| 92 | 'symbol-name | ||
| 93 | '(string int real slist ilist rlist irange rrange counter)) | ||
| 94 | "List of the CFEngine 3.x variable types.")) | ||
| 67 | 95 | ||
| 68 | (defvar cfengine-font-lock-keywords | 96 | (defvar cfengine-font-lock-keywords |
| 69 | `(;; Actions. | 97 | `(;; Actions. |
| @@ -82,6 +110,31 @@ This includes those for cfservd as well as cfagent.")) | |||
| 82 | ;; File, acl &c in group: { token ... } | 110 | ;; File, acl &c in group: { token ... } |
| 83 | ("{[ \t]*\\([^ \t\n]+\\)" 1 font-lock-constant-face))) | 111 | ("{[ \t]*\\([^ \t\n]+\\)" 1 font-lock-constant-face))) |
| 84 | 112 | ||
| 113 | (defvar cfengine3-font-lock-keywords | ||
| 114 | `( | ||
| 115 | (,(concat "^[ \t]*" cfengine3-class-selector-regex) | ||
| 116 | 1 font-lock-keyword-face) | ||
| 117 | (,(concat "^[ \t]*" cfengine3-category-regex) | ||
| 118 | 1 font-lock-builtin-face) | ||
| 119 | ;; Variables, including scope, e.g. module.var | ||
| 120 | ("[@$](\\([[:alnum:]_.]+\\))" 1 font-lock-variable-name-face) | ||
| 121 | ("[@$]{\\([[:alnum:]_.]+\\)}" 1 font-lock-variable-name-face) | ||
| 122 | ;; Variable definitions. | ||
| 123 | ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face) | ||
| 124 | |||
| 125 | ;; CFEngine 3.x faces | ||
| 126 | ;; defuns | ||
| 127 | (,(concat "\\<" cfengine3-defuns-regex "\\>" | ||
| 128 | "[ \t]+\\<\\([[:alnum:]_]+\\)\\>" | ||
| 129 | "[ \t]+\\<\\([[:alnum:]_]+\\)\\((\\([^)]*\\))\\)?") | ||
| 130 | (1 font-lock-builtin-face) | ||
| 131 | (2 font-lock-constant-name-face) | ||
| 132 | (3 font-lock-function-name-face) | ||
| 133 | (5 font-lock-variable-name-face)) | ||
| 134 | ;; variable types | ||
| 135 | (,(concat "\\<" (eval-when-compile (regexp-opt cfengine3-vartypes t)) "\\>") | ||
| 136 | 1 font-lock-type-face))) | ||
| 137 | |||
| 85 | (defvar cfengine-imenu-expression | 138 | (defvar cfengine-imenu-expression |
| 86 | `((nil ,(concat "^[ \t]*" (eval-when-compile | 139 | `((nil ,(concat "^[ \t]*" (eval-when-compile |
| 87 | (regexp-opt cfengine-actions t)) | 140 | (regexp-opt cfengine-actions t)) |
| @@ -197,6 +250,191 @@ Intended as the value of `indent-line-function'." | |||
| 197 | (fill-paragraph justify)) | 250 | (fill-paragraph justify)) |
| 198 | t)) | 251 | t)) |
| 199 | 252 | ||
| 253 | (defun cfengine3-beginning-of-defun () | ||
| 254 | "`beginning-of-defun' function for Cfengine 3 mode. | ||
| 255 | Treats body/bundle blocks as defuns." | ||
| 256 | (unless (<= (current-column) (current-indentation)) | ||
| 257 | (end-of-line)) | ||
| 258 | (if (re-search-backward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) | ||
| 259 | (beginning-of-line) | ||
| 260 | (goto-char (point-min))) | ||
| 261 | t) | ||
| 262 | |||
| 263 | (defun cfengine3-end-of-defun () | ||
| 264 | "`end-of-defun' function for Cfengine 3 mode. | ||
| 265 | Treats body/bundle blocks as defuns." | ||
| 266 | (end-of-line) | ||
| 267 | (if (re-search-forward (concat "^[ \t]*" cfengine3-defuns-regex "\\>") nil t) | ||
| 268 | (beginning-of-line) | ||
| 269 | (goto-char (point-max))) | ||
| 270 | t) | ||
| 271 | |||
| 272 | (defun cfengine3-indent-line () | ||
| 273 | "Indent a line in Cfengine 3 mode. | ||
| 274 | Intended as the value of `indent-line-function'." | ||
| 275 | (let ((pos (- (point-max) (point))) | ||
| 276 | parse) | ||
| 277 | (save-restriction | ||
| 278 | (narrow-to-defun) | ||
| 279 | (back-to-indentation) | ||
| 280 | (setq parse (parse-partial-sexp (point-min) (point))) | ||
| 281 | (message "%S" parse) | ||
| 282 | (cond | ||
| 283 | ;; body/bundle blocks start at 0 | ||
| 284 | ((looking-at (concat cfengine3-defuns-regex "\\>")) | ||
| 285 | (indent-line-to 0)) | ||
| 286 | ;; categories are indented one step | ||
| 287 | ((looking-at (concat cfengine3-category-regex "[ \t]*$")) | ||
| 288 | (indent-line-to cfengine-indent)) | ||
| 289 | ;; class selectors are indented two steps | ||
| 290 | ((looking-at (concat cfengine3-class-selector-regex "[ \t]*$")) | ||
| 291 | (indent-line-to (* 2 cfengine-indent))) | ||
| 292 | ;; Outdent leading close brackets one step. | ||
| 293 | ((or (eq ?\} (char-after)) | ||
| 294 | (eq ?\) (char-after))) | ||
| 295 | (condition-case () | ||
| 296 | (indent-line-to (save-excursion | ||
| 297 | (forward-char) | ||
| 298 | (backward-sexp) | ||
| 299 | (current-column))) | ||
| 300 | (error nil))) | ||
| 301 | ;; inside a string and it starts before this line | ||
| 302 | ((and (nth 3 parse) | ||
| 303 | (< (nth 8 parse) (save-excursion (beginning-of-line) (point)))) | ||
| 304 | (indent-line-to 0)) | ||
| 305 | ;; inside a defun, but not a nested list (depth is 1) | ||
| 306 | ((= 1 (nth 0 parse)) | ||
| 307 | (indent-line-to (* (+ 2 (nth 0 parse)) cfengine-indent))) | ||
| 308 | ;; Inside brackets/parens: indent to start column of non-comment | ||
| 309 | ;; token on line following open bracket or by one step from open | ||
| 310 | ;; bracket's column. | ||
| 311 | ((condition-case () | ||
| 312 | (progn (indent-line-to (save-excursion | ||
| 313 | (backward-up-list) | ||
| 314 | (forward-char) | ||
| 315 | (skip-chars-forward " \t") | ||
| 316 | (cond | ||
| 317 | ((looking-at "[^\n#]") | ||
| 318 | (current-column)) | ||
| 319 | ((looking-at "[^\n#]") | ||
| 320 | (current-column)) | ||
| 321 | (t | ||
| 322 | (skip-chars-backward " \t") | ||
| 323 | (+ (current-column) -1 | ||
| 324 | cfengine-indent))))) | ||
| 325 | t) | ||
| 326 | (error nil))) | ||
| 327 | ;; Else don't indent. | ||
| 328 | (t (indent-line-to 0)))) | ||
| 329 | ;; If initial point was within line's indentation, | ||
| 330 | ;; position after the indentation. Else stay at same point in text. | ||
| 331 | (if (> (- (point-max) pos) (point)) | ||
| 332 | (goto-char (- (point-max) pos))))) | ||
| 333 | |||
| 334 | ;; CFEngine 3.x grammar | ||
| 335 | |||
| 336 | ;; specification: blocks | ||
| 337 | ;; blocks: block | blocks block; | ||
| 338 | ;; block: bundle typeid blockid bundlebody | ||
| 339 | ;; | bundle typeid blockid usearglist bundlebody | ||
| 340 | ;; | body typeid blockid bodybody | ||
| 341 | ;; | body typeid blockid usearglist bodybody; | ||
| 342 | |||
| 343 | ;; typeid: id | ||
| 344 | ;; blockid: id | ||
| 345 | ;; usearglist: '(' aitems ')'; | ||
| 346 | ;; aitems: aitem | aitem ',' aitems |; | ||
| 347 | ;; aitem: id | ||
| 348 | |||
| 349 | ;; bundlebody: '{' statements '}' | ||
| 350 | ;; statements: statement | statements statement; | ||
| 351 | ;; statement: category | classpromises; | ||
| 352 | |||
| 353 | ;; bodybody: '{' bodyattribs '}' | ||
| 354 | ;; bodyattribs: bodyattrib | bodyattribs bodyattrib; | ||
| 355 | ;; bodyattrib: class | selections; | ||
| 356 | ;; selections: selection | selections selection; | ||
| 357 | ;; selection: id ASSIGN rval ';' ; | ||
| 358 | |||
| 359 | ;; classpromises: classpromise | classpromises classpromise; | ||
| 360 | ;; classpromise: class | promises; | ||
| 361 | ;; promises: promise | promises promise; | ||
| 362 | ;; category: CATEGORY | ||
| 363 | ;; promise: promiser ARROW rval constraints ';' | promiser constraints ';'; | ||
| 364 | ;; constraints: constraint | constraints ',' constraint |; | ||
| 365 | ;; constraint: id ASSIGN rval; | ||
| 366 | ;; class: CLASS | ||
| 367 | ;; id: ID | ||
| 368 | ;; rval: ID | QSTRING | NAKEDVAR | list | usefunction | ||
| 369 | ;; list: '{' litems '}' ; | ||
| 370 | ;; litems: litem | litem ',' litems |; | ||
| 371 | ;; litem: ID | QSTRING | NAKEDVAR | list | usefunction | ||
| 372 | |||
| 373 | ;; functionid: ID | NAKEDVAR | ||
| 374 | ;; promiser: QSTRING | ||
| 375 | ;; usefunction: functionid givearglist | ||
| 376 | ;; givearglist: '(' gaitems ')' | ||
| 377 | ;; gaitems: gaitem | gaitems ',' gaitem |; | ||
| 378 | ;; gaitem: ID | QSTRING | NAKEDVAR | list | usefunction | ||
| 379 | |||
| 380 | ;; # from lexer: | ||
| 381 | |||
| 382 | ;; bundle: "bundle" | ||
| 383 | ;; body: "body" | ||
| 384 | ;; COMMENT #[^\n]* | ||
| 385 | ;; NAKEDVAR [$@][(][a-zA-Z0-9_\200-\377.]+[)]|[$@][{][a-zA-Z0-9_\200-\377.]+[}] | ||
| 386 | ;; ID: [a-zA-Z0-9_\200-\377]+ | ||
| 387 | ;; ASSIGN: "=>" | ||
| 388 | ;; ARROW: "->" | ||
| 389 | ;; QSTRING: \"((\\\")|[^"])*\"|\'((\\\')|[^'])*\'|`[^`]*` | ||
| 390 | ;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+:: | ||
| 391 | ;; CATEGORY: [a-zA-Z_]+: | ||
| 392 | |||
| 393 | (defun cfengine-common-settings () | ||
| 394 | (set (make-local-variable 'syntax-propertize-function) | ||
| 395 | ;; In the main syntax-table, \ is marked as a punctuation, because | ||
| 396 | ;; of its use in DOS-style directory separators. Here we try to | ||
| 397 | ;; recognize the cases where \ is used as an escape inside strings. | ||
| 398 | (syntax-propertize-rules ("\\(\\(?:\\\\\\)+\\)\"" (1 "\\")))) | ||
| 399 | (set (make-local-variable 'parens-require-spaces) nil) | ||
| 400 | (set (make-local-variable 'comment-start) "# ") | ||
| 401 | (set (make-local-variable 'comment-start-skip) | ||
| 402 | "\\(\\(?:^\\|[^\\\\\n]\\)\\(?:\\\\\\\\\\)*\\)#+[ \t]*") | ||
| 403 | ;; Like Lisp mode. Without this, we lose with, say, | ||
| 404 | ;; `backward-up-list' when there's an unbalanced quote in a | ||
| 405 | ;; preceding comment. | ||
| 406 | (set (make-local-variable 'parse-sexp-ignore-comments) t)) | ||
| 407 | |||
| 408 | (defun cfengine-common-syntax (table) | ||
| 409 | ;; the syntax defaults seem OK to give reasonable word movement | ||
| 410 | (modify-syntax-entry ?# "<" table) | ||
| 411 | (modify-syntax-entry ?\n ">#" table) | ||
| 412 | (modify-syntax-entry ?\" "\"" table) | ||
| 413 | ;; variable substitution: | ||
| 414 | (modify-syntax-entry ?$ "." table) | ||
| 415 | ;; Doze path separators: | ||
| 416 | (modify-syntax-entry ?\\ "." table)) | ||
| 417 | |||
| 418 | ;;;###autoload | ||
| 419 | (define-derived-mode cfengine3-mode prog-mode "CFEngine3" | ||
| 420 | "Major mode for editing cfengine input. | ||
| 421 | There are no special keybindings by default. | ||
| 422 | |||
| 423 | Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves | ||
| 424 | to the action header." | ||
| 425 | (cfengine-common-settings) | ||
| 426 | (cfengine-common-syntax cfengine3-mode-syntax-table) | ||
| 427 | |||
| 428 | (set (make-local-variable 'indent-line-function) #'cfengine3-indent-line) | ||
| 429 | (setq font-lock-defaults | ||
| 430 | '(cfengine3-font-lock-keywords nil nil nil beginning-of-defun)) | ||
| 431 | |||
| 432 | ;; use defuns as the essential syntax block | ||
| 433 | (set (make-local-variable 'beginning-of-defun-function) | ||
| 434 | #'cfengine3-beginning-of-defun) | ||
| 435 | (set (make-local-variable 'end-of-defun-function) | ||
| 436 | #'cfengine3-end-of-defun)) | ||
| 437 | |||
| 200 | ;;;###autoload | 438 | ;;;###autoload |
| 201 | (define-derived-mode cfengine-mode prog-mode "Cfengine" | 439 | (define-derived-mode cfengine-mode prog-mode "Cfengine" |
| 202 | "Major mode for editing cfengine input. | 440 | "Major mode for editing cfengine input. |
| @@ -204,25 +442,15 @@ There are no special keybindings by default. | |||
| 204 | 442 | ||
| 205 | Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves | 443 | Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves |
| 206 | to the action header." | 444 | to the action header." |
| 207 | (modify-syntax-entry ?# "<" cfengine-mode-syntax-table) | 445 | (cfengine-common-settings) |
| 208 | (modify-syntax-entry ?\n ">#" cfengine-mode-syntax-table) | 446 | (cfengine-common-syntax cfengine-mode-syntax-table) |
| 447 | |||
| 209 | ;; Shell commands can be quoted by single, double or back quotes. | 448 | ;; Shell commands can be quoted by single, double or back quotes. |
| 210 | ;; It's debatable whether we should define string syntax, but it | 449 | ;; It's debatable whether we should define string syntax, but it |
| 211 | ;; should avoid potential confusion in some cases. | 450 | ;; should avoid potential confusion in some cases. |
| 212 | (modify-syntax-entry ?\" "\"" cfengine-mode-syntax-table) | ||
| 213 | (modify-syntax-entry ?\' "\"" cfengine-mode-syntax-table) | 451 | (modify-syntax-entry ?\' "\"" cfengine-mode-syntax-table) |
| 214 | (modify-syntax-entry ?\` "\"" cfengine-mode-syntax-table) | 452 | (modify-syntax-entry ?\` "\"" cfengine-mode-syntax-table) |
| 215 | ;; variable substitution: | ||
| 216 | (modify-syntax-entry ?$ "." cfengine-mode-syntax-table) | ||
| 217 | ;; Doze path separators: | ||
| 218 | (modify-syntax-entry ?\\ "." cfengine-mode-syntax-table) | ||
| 219 | ;; Otherwise, syntax defaults seem OK to give reasonable word | ||
| 220 | ;; movement. | ||
| 221 | 453 | ||
| 222 | (set (make-local-variable 'parens-require-spaces) nil) | ||
| 223 | (set (make-local-variable 'comment-start) "# ") | ||
| 224 | (set (make-local-variable 'comment-start-skip) | ||
| 225 | "\\(\\(?:^\\|[^\\\\\n]\\)\\(?:\\\\\\\\\\)*\\)#+[ \t]*") | ||
| 226 | (set (make-local-variable 'indent-line-function) #'cfengine-indent-line) | 454 | (set (make-local-variable 'indent-line-function) #'cfengine-indent-line) |
| 227 | (set (make-local-variable 'outline-regexp) "[ \t]*\\(\\sw\\|\\s_\\)+:+") | 455 | (set (make-local-variable 'outline-regexp) "[ \t]*\\(\\sw\\|\\s_\\)+:+") |
| 228 | (set (make-local-variable 'outline-level) #'cfengine-outline-level) | 456 | (set (make-local-variable 'outline-level) #'cfengine-outline-level) |
| @@ -233,20 +461,12 @@ to the action header." | |||
| 233 | '(cfengine-font-lock-keywords nil nil nil beginning-of-line)) | 461 | '(cfengine-font-lock-keywords nil nil nil beginning-of-line)) |
| 234 | ;; Fixme: set the args of functions in evaluated classes to string | 462 | ;; Fixme: set the args of functions in evaluated classes to string |
| 235 | ;; syntax, and then obey syntax properties. | 463 | ;; syntax, and then obey syntax properties. |
| 236 | (set (make-local-variable 'syntax-propertize-function) | ||
| 237 | ;; In the main syntax-table, \ is marked as a punctuation, because | ||
| 238 | ;; of its use in DOS-style directory separators. Here we try to | ||
| 239 | ;; recognize the cases where \ is used as an escape inside strings. | ||
| 240 | (syntax-propertize-rules ("\\(\\(?:\\\\\\)+\\)\"" (1 "\\")))) | ||
| 241 | (setq imenu-generic-expression cfengine-imenu-expression) | 464 | (setq imenu-generic-expression cfengine-imenu-expression) |
| 242 | (set (make-local-variable 'beginning-of-defun-function) | 465 | (set (make-local-variable 'beginning-of-defun-function) |
| 243 | #'cfengine-beginning-of-defun) | 466 | #'cfengine-beginning-of-defun) |
| 244 | (set (make-local-variable 'end-of-defun-function) #'cfengine-end-of-defun) | 467 | (set (make-local-variable 'end-of-defun-function) #'cfengine-end-of-defun)) |
| 245 | ;; Like Lisp mode. Without this, we lose with, say, | ||
| 246 | ;; `backward-up-list' when there's an unbalanced quote in a | ||
| 247 | ;; preceding comment. | ||
| 248 | (set (make-local-variable 'parse-sexp-ignore-comments) t)) | ||
| 249 | 468 | ||
| 469 | (provide 'cfengine3) | ||
| 250 | (provide 'cfengine) | 470 | (provide 'cfengine) |
| 251 | 471 | ||
| 252 | ;;; cfengine.el ends here | 472 | ;;; cfengine.el ends here |