diff options
| author | Ted Zlatanov | 2013-11-16 17:36:14 -0500 |
|---|---|---|
| committer | Ted Zlatanov | 2013-11-16 17:36:14 -0500 |
| commit | 7e26a6c339371c348dfda84ea7314c2148572b09 (patch) | |
| tree | f519c8ee23ea7d98908644541b3af9b3154d5673 | |
| parent | 86eaab89204363fff25788586e49d050b102bcda (diff) | |
| download | emacs-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/ChangeLog | 17 | ||||
| -rw-r--r-- | lisp/progmodes/cfengine.el | 148 |
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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-11-16 Michael Albinus <michael.albinus@gmx.de> | 18 | 2013-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. | ||
| 74 | Used for syntax discovery and checking. Set to nil to disable | ||
| 75 | the `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. | ||
| 595 | Calls `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. | ||
| 617 | Intended as the value of `eldoc-documentation-function', which | ||
| 618 | see. 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) |