emacs-devel
[Top][All Lists]
Advanced

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

Re: changes to cfengine-mode


From: Ted Zlatanov
Subject: Re: changes to cfengine-mode
Date: Wed, 07 Dec 2011 06:04:03 -0500
User-agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.90 (gnu/linux)

On Fri, 02 Dec 2011 15:32:25 -0500 Stefan Monnier <address@hidden> wrote: 

>> I'd like to rename `cfengine-mode' to `cfengine2-mode', and
>> `cfengine-auto-mode' to `cfengine-mode' (`cfengine-auto-mode' loads
>> `cfengine3-mode' if it thinks a cfengine v.3 file is edited).

SM> That sounds right.

Thanks for looking.  Attached is a patch that will:

1) rename `cfengine-mode' to `cfengine2-mode' and defalias
'cfengine-mode to 'cfengine-auto-mode.  Provide 'cfengine2.

2) rename all the "cfengine-*" variables used only by `cfengine2-mode'
to "cfengine2-*"

3) adjust the commentary to match

4) give a version and set it to 1.1 for this release

5) use "CFEngine" consistently, capitalized as the author, Mark Burgess,
does

6) add `cfengine3-mode-verbose' to control some debugging info

7) add `cfengine3-parameters-indent' to address some shortcomings in
indentation.  This is a new feature but necessary to fix the lack of a
hanging indent in the current `cfengine3-mode'.  It's very low-risk and
I hope it's acceptable.

8) improve and capitalize comments in many places, though that work is
not complete

9) change the "lighter" modeline indicators from "Cfengine[23]" to
"CFE[23]" to take less space

I also have a font-lock issue I can't figure out with the current
version.  Given the following code (use `cfengine3-mode' to see the
problem):

#+begin_src cfengine3
body common control
{
      bundlesequence => { "g", "cfrun", "rcfiles", "packages", "packages_push" 
};
      inputs => { "cfengine_stdlib.cf" };
}

bundle common g
{
}
#+end_src

These are two defuns as far as `cfengine3-mode' is concerned.

The "bundle common g" line is supposed to be font-locked and it is,
sometimes.  For instance it's not font-locked in a text buffer where
you've just run `cfengine3-mode', but if you remove the blank line
between the two defuns, it gets font-locked.  Then if I do more editing
it keeps flip-flopping between font-locked and undecorated.  I've spend
many hours looking for the cause of this issue and I hope you or someone
else will spot it more easily, or tell me how to debug it better.  I
have a feeling it's due to the defun motion commands but I'm not sure.

>> Another approach is to rename `cfengine-mode' to `cfengine2-mode' and
>> `cfengine3-mode' to `cfengine-mode', effectively making v.2 support less
>> important.  **I like this approach better** because cfengine v.2 is
>> disappearing quickly, but it would break backwards compatibility so I
>> proposed it second.

SM> We can consider it for 24.2,

OK.

Ted

=== modified file 'lisp/progmodes/cfengine.el'
--- lisp/progmodes/cfengine.el  2011-11-20 03:48:53 +0000
+++ lisp/progmodes/cfengine.el  2011-12-07 10:48:58 +0000
@@ -5,6 +5,9 @@
 ;; Author: Dave Love <address@hidden>
 ;; Maintainer: Ted Zlatanov <address@hidden>
 ;; Keywords: languages
+;; Version: 1.1
+(defvar cfengine-version nil)
+(setq cfengine-version "1.1")
 
 ;; This file is part of GNU Emacs.
 
@@ -29,18 +32,18 @@
 ;; The CFEngine 3.x support doesn't have Imenu support but patches are
 ;; welcome.
 
-;; You can set it up so either cfengine-mode (2.x and earlier) or
-;; cfengine3-mode (3.x) will be picked, depending on the buffer
+;; You can set it up so either `cfengine2-mode' (2.x and earlier) or
+;; `cfengine3-mode' (3.x) will be picked, depending on the buffer
 ;; contents:
 
-;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine-auto-mode))
+;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine-mode))
 
 ;; OR you can choose to always use a specific version, if you prefer
-;; it
+;; it:
 
 ;; (add-to-list 'auto-mode-alist '("\\.cf\\'" . cfengine3-mode))
-;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine-mode))
-;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine-mode))
+;; (add-to-list 'auto-mode-alist '("^cf\\." . cfengine2-mode))
+;; (add-to-list 'auto-mode-alist '("^cfagent.conf\\'" . cfengine2-mode))
 
 ;; This is not the same as the mode written by Rolf Ebert
 ;; <address@hidden>, distributed with cfengine-2.0.5.  It does
@@ -49,16 +52,32 @@
 ;;; Code:
 
 (defgroup cfengine ()
-  "Editing Cfengine files."
+  "Editing CFEngine files."
   :group 'languages)
 
 (defcustom cfengine-indent 2
-  "*Size of a Cfengine indentation step in columns."
+  "*Size of a CFEngine indentation step in columns."
   :group 'cfengine
   :type 'integer)
 
-(defcustom cfengine-mode-abbrevs nil
-  "Abbrevs for Cfengine mode."
+(defcustom cfengine3-parameters-indent '(promise pname 0)
+  "*Indentation of CFEngine3 promise parameters (hanging indent)."
+  :group 'cfengine
+  :type '(list
+          (choice (const :tag "Anchor at beginning of promise" promise)
+                  (const :tag "Anchor at beginning of line" bol))
+          (choice (const :tag "Indent parameter name" pname)
+                  (const :tag "Indent arrow" arrow))
+          (integer :tag "Indentation amount from anchor")))
+
+(defcustom cfengine3-mode-verbose nil
+  "Whether `cfengine-mode' should be verbose
+ (only used by the cfengine3 support currently)"
+  :group 'cfengine
+  :type 'boolean)
+
+(defcustom cfengine2-mode-abbrevs nil
+  "Abbrevs for CFEngine2 mode."
   :group 'cfengine
   :type '(repeat (list (string :tag "Name")
                       (string :tag "Expansion")
@@ -66,7 +85,7 @@
 
 ;; Taken from the doc for pre-release 2.1.
 (eval-and-compile
-  (defconst cfengine-actions
+  (defconst cfengine2-actions
     '("acl" "alerts" "binservers" "broadcast" "control" "classes" "copy"
       "defaultroute" "disks" "directories" "disable" "editfiles" "files"
       "filters" "groups" "homeservers" "ignore" "import" "interfaces"
@@ -102,7 +121,7 @@
   `(;; Actions.
     ;; List the allowed actions explicitly, so that errors are more obvious.
     (,(concat "^[ \t]*" (eval-when-compile
-                         (regexp-opt cfengine-actions t))
+                         (regexp-opt cfengine2-actions t))
              ":")
      1 font-lock-keyword-face)
     ;; Classes.
@@ -117,17 +136,6 @@
 
 (defvar cfengine3-font-lock-keywords
   `(
-    (,(concat "^[ \t]*" cfengine3-class-selector-regex)
-     1 font-lock-keyword-face)
-    (,(concat "^[ \t]*" cfengine3-category-regex)
-     1 font-lock-builtin-face)
-    ;; Variables, including scope, e.g. module.var
-    ("address@hidden(\\([[:alnum:]_.]+\\))" 1 font-lock-variable-name-face)
-    ("address@hidden([[:alnum:]_.]+\\)}" 1 font-lock-variable-name-face)
-    ;; Variable definitions.
-    ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face)
-
-    ;; CFEngine 3.x faces
     ;; defuns
     (,(concat "\\<" cfengine3-defuns-regex "\\>"
               "[ \t]+\\<\\([[:alnum:]_]+\\)\\>"
@@ -136,27 +144,43 @@
     (2 font-lock-constant-name-face)
     (3 font-lock-function-name-face)
     (5 font-lock-variable-name-face))
+
+    ;; class selector
+    (,(concat "^[ \t]*" cfengine3-class-selector-regex)
+     1 font-lock-keyword-face)
+
+    ;; category
+    (,(concat "^[ \t]*" cfengine3-category-regex)
+     1 font-lock-builtin-face)
+
+    ;; Variables, including scope, e.g. module.var
+    ("address@hidden(\\([[:alnum:]_.]+\\))" 1 font-lock-variable-name-face)
+    ("address@hidden([[:alnum:]_.]+\\)}" 1 font-lock-variable-name-face)
+
+    ;; Variable definitions.
+    ("\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1 font-lock-variable-name-face)
+
     ;; variable types
     (,(concat "\\<" (eval-when-compile (regexp-opt cfengine3-vartypes t)) 
"\\>")
      1 font-lock-type-face)))
 
-(defvar cfengine-imenu-expression
+(defvar cfengine2-imenu-expression
   `((nil ,(concat "^[ \t]*" (eval-when-compile
-                             (regexp-opt cfengine-actions t))
+                             (regexp-opt cfengine2-actions t))
                  ":[^:]")
         1)
     ("Variables/classes" "\\<\\([[:alnum:]_]+\\)[ \t]*=[ \t]*(" 1)
     ("Variables/classes" "\\<define=\\([[:alnum:]_]+\\)" 1)
     ("Variables/classes" "\\<DefineClass\\>[ \t]+\\([[:alnum:]_]+\\)" 1))
-  "`imenu-generic-expression' for Cfengine mode.")
+  "`imenu-generic-expression' for CFEngine mode.")
 
-(defun cfengine-outline-level ()
-  "`outline-level' function for Cfengine mode."
+(defun cfengine2-outline-level ()
+  "`outline-level' function for CFEngine mode."
   (if (looking-at "[^:]+\\(?:[:]+\\)$")
       (length (match-string 1))))
 
-(defun cfengine-beginning-of-defun ()
-  "`beginning-of-defun' function for Cfengine mode.
+(defun cfengine2-beginning-of-defun ()
+  "`beginning-of-defun' function for CFEngine mode.
 Treats actions as defuns."
   (unless (<= (current-column) (current-indentation))
     (end-of-line))
@@ -165,8 +189,8 @@
     (goto-char (point-min)))
   t)
 
-(defun cfengine-end-of-defun ()
-  "`end-of-defun' function for Cfengine mode.
+(defun cfengine2-end-of-defun ()
+  "`end-of-defun' function for CFEngine mode.
 Treats actions as defuns."
   (end-of-line)
   (if (re-search-forward "^[[:alpha:]]+: *$" nil t)
@@ -176,7 +200,7 @@
 
 ;; Fixme: Should get an extra indent step in editfiles BeginGroup...s.
 
-(defun cfengine-indent-line ()
+(defun cfengine2-indent-line ()
   "Indent a line in Cfengine mode.
 Intended as the value of `indent-line-function'."
   (let ((pos (- (point-max) (point))))
@@ -283,15 +307,17 @@
       (narrow-to-defun)
       (back-to-indentation)
       (setq parse (parse-partial-sexp (point-min) (point)))
-      (message "%S" parse)
+      (when cfengine3-mode-verbose
+        (message "%S" parse))
+
       (cond
-       ;; body/bundle blocks start at 0
+       ;; Body/bundle blocks start at 0.
        ((looking-at (concat cfengine3-defuns-regex "\\>"))
         (indent-line-to 0))
-       ;; categories are indented one step
+       ;; Categories are indented one step.
        ((looking-at (concat cfengine3-category-regex "[ \t]*$"))
         (indent-line-to cfengine-indent))
-       ;; class selectors are indented two steps
+       ;; Class selectors are indented two steps.
        ((looking-at (concat cfengine3-class-selector-regex "[ \t]*$"))
         (indent-line-to (* 2 cfengine-indent)))
        ;; Outdent leading close brackets one step.
@@ -303,13 +329,31 @@
                               (backward-sexp)
                               (current-column)))
           (error nil)))
-       ;; inside a string and it starts before this line
+       ;; Inside a string and it starts before this line.
        ((and (nth 3 parse)
              (< (nth 8 parse) (save-excursion (beginning-of-line) (point))))
         (indent-line-to 0))
-       ;; inside a defun, but not a nested list (depth is 1)
+
+       ;; Inside a defun, but not a nested list (depth is 1).  This is
+       ;; a promise, usually.
        ((= 1 (nth 0 parse))
-        (indent-line-to (* (+ 2 (nth 0 parse)) cfengine-indent)))
+        (let ((p-anchor (nth 0 cfengine3-parameters-indent))
+              (p-what (nth 1 cfengine3-parameters-indent))
+              (p-indent (nth 2 cfengine3-parameters-indent)))
+          ;; Do we have the parameter anchor and location and indent
+          ;; defined, and are we looking at a promise parameter?
+          (if (and p-anchor p-what p-indent
+                   (looking-at  "\\([[:alnum:]_]+[ \t]*\\)=>"))
+              (let* ((arrow-offset (* -1 (length (match-string 1))))
+                     (extra-offset (if (eq p-what 'arrow) arrow-offset 0))
+                     (base-offset (if (eq p-anchor 'promise)
+                                      (* (+ 2 (nth 0 parse)) cfengine-indent)
+                                    0)))
+                (indent-line-to (max 0 (+ p-indent base-offset extra-offset))))
+            ;; Else, indent to cfengine-indent times the nested depth
+            ;; plus 2.  That way, promises indent deeper than class
+            ;; selectors, which in turn are one deeper than categories.
+          (indent-line-to (* (+ 2 (nth 0 parse)) cfengine-indent)))))
        ;; Inside brackets/parens: indent to start column of non-comment
        ;; token on line following open bracket or by one step from open
        ;; bracket's column.
@@ -421,8 +465,8 @@
   (modify-syntax-entry ?\\ "." table))
 
 ;;;###autoload
-(define-derived-mode cfengine3-mode prog-mode "CFEngine3"
-  "Major mode for editing cfengine input.
+(define-derived-mode cfengine3-mode prog-mode "CFE3"
+  "Major mode for editing CFEngine3 input.
 There are no special keybindings by default.
 
 Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
@@ -441,39 +485,39 @@
        #'cfengine3-end-of-defun))
 
 ;;;###autoload
-(define-derived-mode cfengine-mode prog-mode "Cfengine"
-  "Major mode for editing cfengine input.
+(define-derived-mode cfengine2-mode prog-mode "CFE2"
+  "Major mode for editing CFEngine2 input.
 There are no special keybindings by default.
 
 Action blocks are treated as defuns, i.e. \\[beginning-of-defun] moves
 to the action header."
   (cfengine-common-settings)
-  (cfengine-common-syntax cfengine-mode-syntax-table)
+  (cfengine-common-syntax cfengine2-mode-syntax-table)
 
   ;; Shell commands can be quoted by single, double or back quotes.
   ;; It's debatable whether we should define string syntax, but it
   ;; should avoid potential confusion in some cases.
-  (modify-syntax-entry ?\' "\"" cfengine-mode-syntax-table)
-  (modify-syntax-entry ?\` "\"" cfengine-mode-syntax-table)
+  (modify-syntax-entry ?\' "\"" cfengine2-mode-syntax-table)
+  (modify-syntax-entry ?\` "\"" cfengine2-mode-syntax-table)
 
-  (set (make-local-variable 'indent-line-function) #'cfengine-indent-line)
+  (set (make-local-variable 'indent-line-function) #'cfengine2-indent-line)
   (set (make-local-variable 'outline-regexp) "[ \t]*\\(\\sw\\|\\s_\\)+:+")
-  (set (make-local-variable 'outline-level) #'cfengine-outline-level)
+  (set (make-local-variable 'outline-level) #'cfengine2-outline-level)
   (set (make-local-variable 'fill-paragraph-function)
        #'cfengine-fill-paragraph)
-  (define-abbrev-table 'cfengine-mode-abbrev-table cfengine-mode-abbrevs)
+  (define-abbrev-table 'cfengine2-mode-abbrev-table cfengine2-mode-abbrevs)
   (setq font-lock-defaults
-       '(cfengine-font-lock-keywords nil nil nil beginning-of-line))
+        '(cfengine-font-lock-keywords nil nil nil beginning-of-line))
   ;; Fixme: set the args of functions in evaluated classes to string
   ;; syntax, and then obey syntax properties.
-  (setq imenu-generic-expression cfengine-imenu-expression)
+  (setq imenu-generic-expression cfengine2-imenu-expression)
   (set (make-local-variable 'beginning-of-defun-function)
-       #'cfengine-beginning-of-defun)
-  (set (make-local-variable 'end-of-defun-function) #'cfengine-end-of-defun))
+       #'cfengine2-beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function) #'cfengine2-end-of-defun))
 
 ;;;###autoload
 (defun cfengine-auto-mode ()
-  "Choose between `cfengine-mode' and `cfengine3-mode' depending
+  "Choose between `cfengine2-mode' and `cfengine3-mode' depending
 on the buffer contents"
   (let ((v3 nil))
     (save-restriction
@@ -481,9 +525,12 @@
       (while (not (or (eobp) v3))
         (setq v3 (looking-at (concat cfengine3-defuns-regex "\\>")))
         (forward-line)))
-    (if v3 (cfengine3-mode) (cfengine-mode))))
+    (if v3 (cfengine3-mode) (cfengine2-mode))))
+
+(defalias 'cfengine-mode 'cfengine-auto-mode)
 
 (provide 'cfengine3)
+(provide 'cfengine2)
 (provide 'cfengine)
 
 ;;; cfengine.el ends here


reply via email to

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