emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r115125: Add CFEngine 3 ElDoc, completion, and compi


From: Teodor Zlatanov
Subject: [Emacs-diffs] trunk r115125: Add CFEngine 3 ElDoc, completion, and compilation glue to cf-promises.
Date: Sat, 16 Nov 2013 22:35:37 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 115125
revision-id: address@hidden
parent: address@hidden
committer: Ted Zlatanov <address@hidden>
branch nick: quickfixes
timestamp: Sat 2013-11-16 17:36:14 -0500
message:
  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'.
modified:
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/progmodes/cfengine.el     
cfengine.el-20091113204419-o5vbwnq5f7feedwu-2944
=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-11-16 11:37:45 +0000
+++ b/lisp/ChangeLog    2013-11-16 22:36:14 +0000
@@ -1,3 +1,20 @@
+2013-11-16  Teodor Zlatanov  <address@hidden>
+
+       * 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'.
+
 2013-11-16  Michael Albinus  <address@hidden>
 
        * net/tramp-cmds.el (tramp-cleanup-connection): Clean up

=== modified file 'lisp/progmodes/cfengine.el'
--- a/lisp/progmodes/cfengine.el        2013-07-10 14:34:13 +0000
+++ b/lisp/progmodes/cfengine.el        2013-11-16 22:36:14 +0000
@@ -5,7 +5,7 @@
 ;; Author: Dave Love <address@hidden>
 ;; Maintainer: Ted Zlatanov <address@hidden>
 ;; Keywords: languages
-;; Version: 1.2
+;; Version: 1.3
 
 ;; This file is part of GNU Emacs.
 
@@ -45,6 +45,10 @@
 ;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode))
 ;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode))
 
+;; It's *highly* recommended that you enable the eldoc minor mode:
+
+;; (add-hook 'cfengine-mode-hook 'turn-on-eldoc-mode)
+
 ;; This is not the same as the mode written by Rolf Ebert
 ;; <address@hidden>, distributed with cfengine-2.0.5.  It does
 ;; better fontification and indentation, inter alia.
@@ -60,6 +64,18 @@
   :group 'cfengine
   :type 'integer)
 
+(defcustom cfengine-cf-promises
+  (or (executable-find "cf-promises")
+      (executable-find "/var/cfengine/bin/cf-promises")
+      (executable-find "/usr/bin/cf-promises")
+      (executable-find "/usr/local/bin/cf-promises")
+      (executable-find "~/bin/cf-promises"))
+  "The location of the cf-promises executable.
+Used for syntax discovery and checking.  Set to nil to disable
+the `compile-command' override and the ElDoc support."
+  :group 'cfengine
+  :type 'file)
+
 (defcustom cfengine-parameters-indent '(promise pname 0)
   "*Indentation of CFEngine3 promise parameters (hanging indent).
 
@@ -127,6 +143,9 @@
 (defvar cfengine-mode-debug nil
   "Whether `cfengine-mode' should print debugging info.")
 
+(defvar cfengine-mode-syntax-cache nil
+  "Cache for `cfengine-mode' syntax trees obtained from 'cf-promises -s 
json'.")
+
 (defcustom cfengine-mode-abbrevs nil
   "Abbrevs for CFEngine2 mode."
   :group 'cfengine
@@ -167,7 +186,7 @@
   (defconst cfengine3-vartypes
     (mapcar
      'symbol-name
-     '(string int real slist ilist rlist irange rrange counter))
+     '(string int real slist ilist rlist irange rrange counter data))
     "List of the CFEngine 3.x variable types."))
 
 (defvar cfengine2-font-lock-keywords
@@ -501,6 +520,116 @@
 ;; CLASS: [.|&!()a-zA-Z0-9_\200-\377]+::
 ;; CATEGORY: [a-zA-Z_]+:
 
+(defun cfengine3--current-word (&optional bounds)
+  "Propose a word around point in the current CFEngine 3 buffer."
+  (let ((c (char-after (point)))
+        (s (syntax-ppss)))
+    (when (not (nth 3 s)) ; not inside a string
+      (if bounds
+          (save-excursion
+            (let ((oldpoint (point))
+                  start end)
+              (skip-syntax-backward "w_") (setq start (point))
+              (goto-char oldpoint)
+              (skip-syntax-forward "w_") (setq end (point))
+              (when (not (and (eq start oldpoint)
+                              (eq end oldpoint)))
+                (list start (point)))))
+        (and c
+             (memq (char-syntax c) '(?_ ?w))
+             (current-word))))))
+
+(defun cfengine3--current-function ()
+  "Look up current CFEngine 3 function"
+  (let* ((syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache))
+         (flist (assoc 'functions syntax)))
+    (when flist
+      (let ((w (cfengine3--current-word)))
+        (and w (assq (intern w) flist))))))
+
+;; format from "cf-promises -s json", e.g. "sort" function:
+;; ((category . "data")
+;;  (variadic . :json-false)
+;;  (parameters . [((range . "[a-zA-Z0-9_$(){}\\[\\].:]+") (type . "string"))
+;;                 ((range . "lex,int,real,IP,ip,MAC,mac") (type . "option"))])
+;;  (returnType . "slist")
+;;  (status . "normal"))
+
+(defun cfengine3-format-function-docstring (fdef)
+  (let* ((f (format "%s" (car-safe fdef)))
+         (def (cdr fdef))
+         (rtype (cdr (assq 'returnType def)))
+         (plist (cdr (assq 'parameters def)))
+         (has-some-parameters (> (length plist) 0))
+         (variadic (eq t (cdr (assq 'variadic def)))))
+
+    ;; (format "[%S]%s %s(%s%s)" def
+    (format "%s %s(%s%s)"
+            (if rtype
+                (propertize rtype 'face 'font-lock-variable-name-face)
+              "???")
+            (propertize f 'face 'font-lock-function-name-face)
+            (mapconcat (lambda (p)
+                         (let ((type (cdr (assq 'type p)))
+                               (range (cdr (assq 'range p))))
+                           (cond
+                            ((not (stringp type)) "???type???")
+                            ((not (stringp range)) "???range???")
+                            ;; options are lists of possible keywords
+                            ((equal type "option")
+                             (propertize (concat "[" range "]")
+                                         'face
+                                         'font-lock-keyword-face))
+                            ;; anything else is a type name as a variable
+                            (t (propertize type
+                                           'face
+                                           'font-lock-variable-name-face)))))
+                       plist
+                       ", ")
+            (if variadic
+                (if has-some-parameters ", ..." "...")
+              ""))))
+
+(defun cfengine3-make-syntax-cache ()
+  "Build the CFEngine 3 syntax cache.
+Calls `cfengine-cf-promises' with \"-s json\""
+  (when cfengine-cf-promises
+    (let ((loaded-json-lib (require 'json nil t))
+          (syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache)))
+      (if (not loaded-json-lib)
+          (message "JSON library could not be loaded!")
+        (unless 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)))))))))
+
+(defun cfengine3-documentation-function ()
+  "Document CFengine 3 functions around point.
+Intended as the value of `eldoc-documentation-function', which
+see.  Use it by executing `turn-on-eldoc-mode'."
+  (cfengine3-make-syntax-cache)
+  (let ((fdef (cfengine3--current-function)))
+    (when fdef
+      (cfengine3-format-function-docstring fdef))))
+
+(defun cfengine3-completion-function ()
+  "Return completions for function name around or before point."
+  (cfengine3-make-syntax-cache)
+  (let* ((bounds (cfengine3--current-word t))
+         (syntax (assoc cfengine-cf-promises cfengine-mode-syntax-cache))
+         (flist (assoc 'functions syntax)))
+    (when bounds
+      (append bounds (list (cdr flist))))))
+
 (defun cfengine-common-settings ()
   (set (make-local-variable 'syntax-propertize-function)
        ;; In the main syntax-table, \ is marked as a punctuation, because
@@ -549,6 +678,21 @@
           nil nil nil beginning-of-defun))
   (setq-local prettify-symbols-alist cfengine3--prettify-symbols-alist)
 
+  ;; `compile-command' is almost never a `make' call with CFEngine so
+  ;; we override it
+  (when cfengine-cf-promises
+    (set (make-local-variable 'compile-command)
+         (concat cfengine-cf-promises
+                 " -f "
+                 (when buffer-file-name
+                   (shell-quote-argument buffer-file-name)))))
+
+  (set (make-local-variable '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)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]