aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Zlatanov2013-11-16 17:36:14 -0500
committerTed Zlatanov2013-11-16 17:36:14 -0500
commit7e26a6c339371c348dfda84ea7314c2148572b09 (patch)
treef519c8ee23ea7d98908644541b3af9b3154d5673
parent86eaab89204363fff25788586e49d050b102bcda (diff)
downloademacs-7e26a6c339371c348dfda84ea7314c2148572b09.tar.gz
emacs-7e26a6c339371c348dfda84ea7314c2148572b09.zip
Add CFEngine 3 ElDoc, completion, and compilation glue to cf-promises.
* progmodes/cfengine.el: Version bump. (cfengine-cf-promises): New defcustom to locate cf-promises. (cfengine3-vartypes): Add new "data" type. (cfengine3--current-word): New function to get current name-like word or its bounds. (cfengine3--current-function): New function to look up a CFEngine function's definition. (cfengine3-format-function-docstring): New function. (cfengine3-make-syntax-cache): New function. (cfengine3-documentation-function): New function: ElDoc glue. (cfengine3-completion-function): New function: completion glue. (cfengine3-mode): Set `compile-command', `eldoc-documentation-function', and add to `completion-at-point-functions'.
-rw-r--r--lisp/ChangeLog17
-rw-r--r--lisp/progmodes/cfengine.el148
2 files changed, 163 insertions, 2 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index ce887ff3e11..2b4f941048c 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,20 @@
12013-11-16 Teodor Zlatanov <tzz@lifelogs.com>
2
3 * progmodes/cfengine.el: Version bump.
4 (cfengine-cf-promises): New defcustom to locate cf-promises.
5 (cfengine3-vartypes): Add new "data" type.
6 (cfengine3--current-word): New function to get current name-like
7 word or its bounds.
8 (cfengine3--current-function): New function to look up a CFEngine
9 function's definition.
10 (cfengine3-format-function-docstring): New function.
11 (cfengine3-make-syntax-cache): New function.
12 (cfengine3-documentation-function): New function: ElDoc glue.
13 (cfengine3-completion-function): New function: completion glue.
14 (cfengine3-mode): Set `compile-command',
15 `eldoc-documentation-function', and add to
16 `completion-at-point-functions'.
17
12013-11-16 Michael Albinus <michael.albinus@gmx.de> 182013-11-16 Michael Albinus <michael.albinus@gmx.de>
2 19
3 * net/tramp-cmds.el (tramp-cleanup-connection): Clean up 20 * net/tramp-cmds.el (tramp-cleanup-connection): Clean up
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index 85a9074760d..a5cd863f2e1 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -5,7 +5,7 @@
5;; Author: Dave Love <fx@gnu.org> 5;; Author: Dave Love <fx@gnu.org>
6;; Maintainer: Ted Zlatanov <tzz@lifelogs.com> 6;; Maintainer: Ted Zlatanov <tzz@lifelogs.com>
7;; Keywords: languages 7;; Keywords: languages
8;; Version: 1.2 8;; Version: 1.3
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
11 11
@@ -45,6 +45,10 @@
45;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode)) 45;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode))
46;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode)) 46;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode))
47 47
48;; It's *highly* recommended that you enable the eldoc minor mode:
49
50;; (add-hook 'cfengine-mode-hook 'turn-on-eldoc-mode)
51
48;; This is not the same as the mode written by Rolf Ebert 52;; This is not the same as the mode written by Rolf Ebert
49;; <ebert@waporo.muc.de>, distributed with cfengine-2.0.5. It does 53;; <ebert@waporo.muc.de>, distributed with cfengine-2.0.5. It does
50;; better fontification and indentation, inter alia. 54;; better fontification and indentation, inter alia.
@@ -60,6 +64,18 @@
60 :group 'cfengine 64 :group 'cfengine
61 :type 'integer) 65 :type 'integer)
62 66
67(defcustom cfengine-cf-promises
68 (or (executable-find "cf-promises")
69 (executable-find "/var/cfengine/bin/cf-promises")
70 (executable-find "/usr/bin/cf-promises")
71 (executable-find "/usr/local/bin/cf-promises")
72 (executable-find "~/bin/cf-promises"))
73 "The location of the cf-promises executable.
74Used for syntax discovery and checking. Set to nil to disable
75the `compile-command' override and the ElDoc support."
76 :group 'cfengine
77 :type 'file)
78
63(defcustom cfengine-parameters-indent '(promise pname 0) 79(defcustom cfengine-parameters-indent '(promise pname 0)
64 "*Indentation of CFEngine3 promise parameters (hanging indent). 80 "*Indentation of CFEngine3 promise parameters (hanging indent).
65 81
@@ -127,6 +143,9 @@ bundle agent rcfiles
127(defvar cfengine-mode-debug nil 143(defvar cfengine-mode-debug nil
128 "Whether `cfengine-mode' should print debugging info.") 144 "Whether `cfengine-mode' should print debugging info.")
129 145
146(defvar cfengine-mode-syntax-cache nil
147 "Cache for `cfengine-mode' syntax trees obtained from 'cf-promises -s json'.")
148
130(defcustom cfengine-mode-abbrevs nil 149(defcustom cfengine-mode-abbrevs nil
131 "Abbrevs for CFEngine2 mode." 150 "Abbrevs for CFEngine2 mode."
132 :group 'cfengine 151 :group 'cfengine
@@ -167,7 +186,7 @@ This includes those for cfservd as well as cfagent.")
167 (defconst cfengine3-vartypes 186 (defconst cfengine3-vartypes
168 (mapcar 187 (mapcar
169 'symbol-name 188 'symbol-name
170 '(string int real slist ilist rlist irange rrange counter)) 189 '(string int real slist ilist rlist irange rrange counter data))
171 "List of the CFEngine 3.x variable types.")) 190 "List of the CFEngine 3.x variable types."))
172 191
173(defvar cfengine2-font-lock-keywords 192(defvar cfengine2-font-lock-keywords
@@ -501,6 +520,116 @@ Intended as the value of `indent-line-function'."
501;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+:: 520;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+::
502;; CATEGORY: [a-zA-Z_]+: 521;; CATEGORY: [a-zA-Z_]+:
503 522
523(defun cfengine3--current-word (&optional bounds)
524 "Propose a word around point in the current CFEngine 3 buffer."
525 (let ((c (char-after (point)))
526 (s (syntax-ppss)))
527 (when (not (nth 3 s)) ; not inside a string
528 (if bounds
529 (save-excursion
530 (let ((oldpoint (point))
531 start end)
532 (skip-syntax-backward "w_") (setq start (point))
533 (goto-char oldpoint)
534 (skip-syntax-forward "w_") (setq end (point))
535 (when (not (and (eq start oldpoint)
536 (eq end oldpoint)))
537 (list start (point)))))
538 (and c
539 (memq (char-syntax c) '(?_ ?w))
540 (current-word))))))
541
542(defun cfengine3--current-function ()
543 "Look up current CFEngine 3 function"
544 (let* ((syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache))
545 (flist (assoc 'functions syntax)))
546 (when flist
547 (let ((w (cfengine3--current-word)))
548 (and w (assq (intern w) flist))))))
549
550;; format from "cf-promises -s json", e.g. "sort" function:
551;; ((category . "data")
552;; (variadic . :json-false)
553;; (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))
554;; ((range . "lex,int,real,IP,ip,MAC,mac") (type . "option"))])
555;; (returnType . "slist")
556;; (status . "normal"))
557
558(defun cfengine3-format-function-docstring (fdef)
559 (let* ((f (format "%s" (car-safe fdef)))
560 (def (cdr fdef))
561 (rtype (cdr (assq 'returnType def)))
562 (plist (cdr (assq 'parameters def)))
563 (has-some-parameters (> (length plist) 0))
564 (variadic (eq t (cdr (assq 'variadic def)))))
565
566 ;; (format "[%S]%s %s(%s%s)" def
567 (format "%s %s(%s%s)"
568 (if rtype
569 (propertize rtype 'face 'font-lock-variable-name-face)
570 "???")
571 (propertize f 'face 'font-lock-function-name-face)
572 (mapconcat (lambda (p)
573 (let ((type (cdr (assq 'type p)))
574 (range (cdr (assq 'range p))))
575 (cond
576 ((not (stringp type)) "???type???")
577 ((not (stringp range)) "???range???")
578 ;; options are lists of possible keywords
579 ((equal type "option")
580 (propertize (concat "[" range "]")
581 'face
582 'font-lock-keyword-face))
583 ;; anything else is a type name as a variable
584 (t (propertize type
585 'face
586 'font-lock-variable-name-face)))))
587 plist
588 ", ")
589 (if variadic
590 (if has-some-parameters ", ..." "...")
591 ""))))
592
593(defun cfengine3-make-syntax-cache ()
594 "Build the CFEngine 3 syntax cache.
595Calls `cfengine-cf-promises' with \"-s json\""
596 (when cfengine-cf-promises
597 (let ((loaded-json-lib (require 'json nil t))
598 (syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache)))
599 (if (not loaded-json-lib)
600 (message "JSON library could not be loaded!")
601 (unless syntax
602 (with-demoted-errors
603 (with-temp-buffer
604 (call-process-shell-command cfengine-cf-promises
605 nil ; no input
606 t ; current buffer
607 nil ; no redisplay
608 "-s" "json")
609 (goto-char (point-min))
610 (setq syntax (json-read))
611 (setq cfengine-mode-syntax-cache
612 (cons (cons cfengine-cf-promises syntax)
613 cfengine-mode-syntax-cache)))))))))
614
615(defun cfengine3-documentation-function ()
616 "Document CFengine 3 functions around point.
617Intended as the value of `eldoc-documentation-function', which
618see. Use it by executing `turn-on-eldoc-mode'."
619 (cfengine3-make-syntax-cache)
620 (let ((fdef (cfengine3--current-function)))
621 (when fdef
622 (cfengine3-format-function-docstring fdef))))
623
624(defun cfengine3-completion-function ()
625 "Return completions for function name around or before point."
626 (cfengine3-make-syntax-cache)
627 (let* ((bounds (cfengine3--current-word t))
628 (syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache))
629 (flist (assoc 'functions syntax)))
630 (when bounds
631 (append bounds (list (cdr flist))))))
632
504(defun cfengine-common-settings () 633(defun cfengine-common-settings ()
505 (set (make-local-variable 'syntax-propertize-function) 634 (set (make-local-variable 'syntax-propertize-function)
506 ;; In the main syntax-table, \ is marked as a punctuation, because 635 ;; In the main syntax-table, \ is marked as a punctuation, because
@@ -549,6 +678,21 @@ to the action header."
549 nil nil nil beginning-of-defun)) 678 nil nil nil beginning-of-defun))
550 (setq-local prettify-symbols-alist cfengine3--prettify-symbols-alist) 679 (setq-local prettify-symbols-alist cfengine3--prettify-symbols-alist)
551 680
681 ;; `compile-command' is almost never a `make' call with CFEngine so
682 ;; we override it
683 (when cfengine-cf-promises
684 (set (make-local-variable 'compile-command)
685 (concat cfengine-cf-promises
686 " -f "
687 (when buffer-file-name
688 (shell-quote-argument buffer-file-name)))))
689
690 (set (make-local-variable 'eldoc-documentation-function)
691 #'cfengine3-documentation-function)
692
693 (add-hook 'completion-at-point-functions
694 #'cfengine3-completion-function nil t)
695
552 ;; Use defuns as the essential syntax block. 696 ;; Use defuns as the essential syntax block.
553 (set (make-local-variable 'beginning-of-defun-function) 697 (set (make-local-variable 'beginning-of-defun-function)
554 #'cfengine3-beginning-of-defun) 698 #'cfengine3-beginning-of-defun)