aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/cfengine.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/cfengine.el')
-rw-r--r--lisp/progmodes/cfengine.el268
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.
66This includes those for cfservd as well as cfagent.")) 74This 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.
255Treats 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.
265Treats 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.
274Intended 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.
421There are no special keybindings by default.
422
423Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
424to 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
205Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves 443Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
206to the action header." 444to 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