summaryrefslogtreecommitdiff
path: root/lisp/progmodes/cfengine.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/cfengine.el')
-rw-r--r--lisp/progmodes/cfengine.el127
1 files changed, 74 insertions, 53 deletions
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index 7d4f6dc25b9..53d5be90cab 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -27,9 +27,6 @@
;; Provides support for editing GNU Cfengine files, including
;; font-locking, Imenu and indentation, but with no special keybindings.
-;; The CFEngine 3.x support doesn't have Imenu support but patches are
-;; welcome.
-
;; By default, CFEngine 3.x syntax is used.
;; You can set it up so either `cfengine2-mode' (2.x and earlier) or
@@ -56,7 +53,6 @@
;;; Code:
(autoload 'json-read "json")
-(autoload 'regexp-opt "regexp-opt")
(defgroup cfengine ()
"Editing CFEngine files."
@@ -815,24 +811,24 @@ bundle agent rcfiles
"List of the action keywords supported by Cfengine.
This includes those for cfservd as well as cfagent.")
- (defconst cfengine3-defuns
- (mapcar
- 'symbol-name
- '(bundle body))
+ (defconst cfengine3-defuns '("bundle" "body")
"List of the CFEngine 3.x defun headings.")
- (defconst cfengine3-defuns-regex
- (regexp-opt cfengine3-defuns t)
+ (defconst cfengine3-defuns-regex (regexp-opt cfengine3-defuns t)
"Regex to match the CFEngine 3.x defuns.")
+ (defconst cfengine3-defun-full-re (concat "^\\s-*" cfengine3-defuns-regex
+ "\\s-+\\(\\(?:\\w\\|\\s_\\)+\\)" ;type
+ "\\s-+\\(\\(?:\\w\\|\\s_\\)+\\)" ;id
+ )
+ "Regexp matching full defun declaration (excluding argument list).")
+
(defconst cfengine3-class-selector-regex "\\([[:alnum:]_().&|!:]+\\)::")
(defconst cfengine3-category-regex "\\([[:alnum:]_]+\\):")
- (defconst cfengine3-vartypes
- (mapcar
- 'symbol-name
- '(string int real slist ilist rlist irange rrange counter data))
+ (defconst cfengine3-vartypes '("string" "int" "real" "slist" "ilist" "rlist"
+ "irange" "rrange" "counter" "data")
"List of the CFEngine 3.x variable types."))
(defvar cfengine2-font-lock-keywords
@@ -1231,29 +1227,32 @@ Should not be necessary unless you reinstall CFEngine."
(setq cfengine-mode-syntax-cache nil))
(defun cfengine3-make-syntax-cache ()
- "Build the CFEngine 3 syntax cache.
-Calls `cfengine-cf-promises' with \"-s json\""
- (let ((syntax (cddr (assoc cfengine-cf-promises cfengine-mode-syntax-cache))))
- (if cfengine-cf-promises
- (or syntax
- (with-demoted-errors
- (with-temp-buffer
- (call-process-shell-command cfengine-cf-promises
- nil ; no input
- t ; current buffer
- nil ; no redisplay
- "-s" "json")
- (goto-char (point-min))
- (setq syntax (json-read))
- (setq cfengine-mode-syntax-cache
- (cons (cons cfengine-cf-promises syntax)
- cfengine-mode-syntax-cache))
- (setq cfengine-mode-syntax-functions-regex
- (regexp-opt (mapcar (lambda (def)
- (format "%s" (car def)))
- (cdr (assq 'functions syntax)))
- 'symbols))))))
- cfengine3-fallback-syntax))
+ "Build the CFEngine 3 syntax cache and return the syntax.
+Calls `cfengine-cf-promises' with \"-s json\"."
+ (or (cdr (assoc cfengine-cf-promises cfengine-mode-syntax-cache))
+ (let ((syntax (or (when cfengine-cf-promises
+ (with-demoted-errors "cfengine3-make-syntax-cache: %S"
+ (with-temp-buffer
+ (or (zerop (process-file cfengine-cf-promises
+ nil ; no input
+ t ; output
+ nil ; no redisplay
+ "-s" "json"))
+ (error "%s" (buffer-substring
+ (point-min)
+ (progn (goto-char (point-min))
+ (line-end-position)))))
+ (goto-char (point-min))
+ (json-read))))
+ cfengine3-fallback-syntax)))
+ (push (cons cfengine-cf-promises syntax)
+ cfengine-mode-syntax-cache)
+ (setq cfengine-mode-syntax-functions-regex
+ (regexp-opt (mapcar (lambda (def)
+ (format "%s" (car def)))
+ (cdr (assq 'functions syntax)))
+ 'symbols))
+ syntax)))
(defun cfengine3-documentation-function ()
"Document CFengine 3 functions around point.
@@ -1265,7 +1264,6 @@ Use it by enabling `eldoc-mode'."
(defun cfengine3-completion-function ()
"Return completions for function name around or before point."
- (cfengine3-make-syntax-cache)
(let* ((bounds (save-excursion
(let ((p (point)))
(skip-syntax-backward "w_" (point-at-bol))
@@ -1306,6 +1304,26 @@ Use it by enabling `eldoc-mode'."
("=>" . ?⇒)
("::" . ?∷)))
+(defun cfengine3-create-imenu-index ()
+ "A function for `imenu-create-index-function'.
+Note: defun name is separated by space such as `body
+package_method opencsw' and imenu will replace spaces according
+to `imenu-space-replacement' (which see)."
+ (goto-char (point-min))
+ (let ((defuns ()))
+ (while (re-search-forward cfengine3-defun-full-re nil t)
+ (push (cons (mapconcat #'match-string '(1 2 3) " ")
+ (copy-marker (match-beginning 3)))
+ defuns))
+ (nreverse defuns)))
+
+(defun cfengine3-current-defun ()
+ "A function for `add-log-current-defun-function'."
+ (end-of-line)
+ (beginning-of-defun)
+ (and (looking-at cfengine3-defun-full-re)
+ (mapconcat #'match-string '(1 2 3) " ")))
+
;;;###autoload
(define-derived-mode cfengine3-mode prog-mode "CFE3"
"Major mode for editing CFEngine3 input.
@@ -1332,17 +1350,17 @@ to the action header."
(when buffer-file-name
(shell-quote-argument buffer-file-name)))))
- (set (make-local-variable 'eldoc-documentation-function)
- #'cfengine3-documentation-function)
+ (setq-local eldoc-documentation-function #'cfengine3-documentation-function)
(add-hook 'completion-at-point-functions
#'cfengine3-completion-function nil t)
;; Use defuns as the essential syntax block.
- (set (make-local-variable 'beginning-of-defun-function)
- #'cfengine3-beginning-of-defun)
- (set (make-local-variable 'end-of-defun-function)
- #'cfengine3-end-of-defun))
+ (setq-local beginning-of-defun-function #'cfengine3-beginning-of-defun)
+ (setq-local end-of-defun-function #'cfengine3-end-of-defun)
+
+ (setq-local imenu-create-index-function #'cfengine3-create-imenu-index)
+ (setq-local add-log-current-defun-function #'cfengine3-current-defun))
;;;###autoload
(define-derived-mode cfengine2-mode prog-mode "CFE2"
@@ -1376,15 +1394,18 @@ to the action header."
;;;###autoload
(defun cfengine-auto-mode ()
- "Choose between `cfengine2-mode' and `cfengine3-mode' depending
-on the buffer contents"
- (let ((v3 nil))
- (save-restriction
- (goto-char (point-min))
- (while (not (or (eobp) v3))
- (setq v3 (looking-at (concat cfengine3-defuns-regex "\\_>")))
- (forward-line)))
- (if v3 (cfengine3-mode) (cfengine2-mode))))
+ "Choose `cfengine2-mode' or `cfengine3-mode' by buffer contents."
+ (interactive)
+ (if (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-comment (point-max))
+ (or (eobp)
+ (re-search-forward
+ (concat "^\\s-*" cfengine3-defuns-regex "\\_>") nil t))))
+ (cfengine3-mode)
+ (cfengine2-mode)))
(defalias 'cfengine-mode 'cfengine3-mode)