[slime-cvs] CVS slime/contrib

CVS User nsiivola nsiivola at common-lisp.net
Sat Jun 11 14:34:59 UTC 2011


Update of /project/slime/cvsroot/slime/contrib
In directory common-lisp.net:/tmp/cvs-serv10212/contrib

Modified Files:
	ChangeLog slime-cl-indent.el 
Log Message:
slime-indentation: refactor named styles

 Now changes from a redefined style take immediate effect, including
 inheritance. (Previously you had to redefine the style you wanted to see the
 changes in as well, and then use common-lisp-set-style to activate it again.)

 Additionally, calling `common-lisp-set-style' is no longer necessary: just
 setting the buffer-local variable will cause the style to activate as long as
 common-lisp-indent-function is being used. (It remains a /good idea/ to
 call it, though, and that's what we do in the lisp-mode hook.)

 How this works:

  * common-lisp-styles now stores the specifications only: inheritance
    is marked there, but its effects are not precomputed.

  * common-lisp-active-style holds a cons:

     (<style> . <methods>)

    where <style> is the specification for the currently active style,
    and <method> is a hash-table of indentation method for it -- including
    inherited methods.

 * common-lisp-get-indentation calls common-lisp-active-style-methods,
   which does:

     (eq (car common-lisp-active-style)
         (gethash common-lisp-style common-lisp-styles))

   If this is true, it just returns the table in the cdr. Otherwise it calls
   common-lisp-activate-style to compute the methods, which also binds any
   local variables, runs initialization hooks, etc.

 * defining or redefining a style copies of style specifications currently
   in common-lisp-styles, so next time common-lisp-get-style is called,
   methods are computed anew, etc.


--- /project/slime/cvsroot/slime/contrib/ChangeLog	2011/06/10 20:03:33	1.477
+++ /project/slime/cvsroot/slime/contrib/ChangeLog	2011/06/11 14:34:59	1.478
@@ -1,3 +1,23 @@
+2011-06-11  Nikodemus Siivola  <nikodemus at random-state.net>
+
+	Refactoring named styles.
+
+	* slime-cl-indent.el (define-common-lisp-style): Not a list of hooks anymore,
+	but just a single hook. Document the fact that code in :eval option may get
+	called multiple times over the lifetime of a buffer.
+	(common-lisp-style-name, common-lisp-style-inherits)
+	(common-lisp-style-variables, common-lisp-style-indentation)
+	(common-lisp-style-hook, common-lisp-style-docstring)
+	(common-lisp-make-style, common-lisp-find-style): New functions.
+	Convenience accessors, locator, and constructor.
+	(common-lisp-add-style): Don't precompute inheritance.
+	(common-lisp-safe-style-p): For use with safe-local-variable.
+	(common-lisp-activate-style): Now handles inheritance.
+	(common-lisp-active-style-methods): New function, computes and caches
+	inheritance.
+	(common-lisp-set-style): Changes to match others.
+	(common-lisp-get-indentation): Use common-lisp-active-style-methods.
+
 2011-06-10  Nikodemus Siivola  <nikodemus at random-state.net>
 
 	Boa-constructor indentation.
--- /project/slime/cvsroot/slime/contrib/slime-cl-indent.el	2011/06/10 20:03:33	1.40
+++ /project/slime/cvsroot/slime/contrib/slime-cl-indent.el	2011/06/11 14:34:59	1.41
@@ -1,4 +1,4 @@
-;;; cl-indent.el --- enhanced lisp-indent mode
+ ;;; cl-indent.el --- enhanced lisp-indent mode
 
 ;; Copyright (C) 1987, 2000-2011 Free Software Foundation, Inc.
 
@@ -176,26 +176,40 @@
 ;;;;
 ;;;; A Common Lisp style is a list of the form:
 ;;;;
-;;;;  (NAME VARIABLES TABLE HOOKS DOCSTRING)
+;;;;  (NAME INHERIT VARIABLES INDENTATION HOOK DOCSTRING)
 ;;;;
-;;;; where NAME is a symbol naming the style, VARIABLES is an alist specifying
-;;;; buffer local variables for the style, and TABLE is a hashtable specifying
-;;;; non-standard indentations for Common Lisp symbols. HOOKS is a list of
-;;;; functions to call when activating the style. DOCSTRING is the
-;;;; documentation for the style.
+;;;; where NAME is a symbol naming the style, INHERIT is the name of the style
+;;;; it inherits from, VARIABLES is an alist specifying buffer local variables
+;;;; for the style, and INDENTATION is an alist specifying non-standard
+;;;; indentations for Common Lisp symbols. HOOK is a function to call when
+;;;; activating the style. DOCSTRING is the documentation for the style.
+;;;;
+;;;; Convenience accessors `common-lisp-style-name', &co exist.
 ;;;;
 ;;;; `common-lisp-style' stores the name of the current style.
 ;;;;
-;;;; `common-lisp-default-style' stores the name of the style to use when none
+;;;; `common-lisp-style-default' stores the name of the style to use when none
 ;;;; has been specified.
 ;;;;
-;;;; `common-lisp-active-style' stores the list specifying the current style.
-;;;; Whenever we're indenting, we check that they match -- and update the
-;;;; latter to match the former if necessary.
-;;;;
-;;;; Hence just setting the buffer local common-lisp-style will be enough
-;;;; to have the style take effect. `common-lisp-set-style' can also be called
-;;;; explicitly, however.
+;;;; `common-lisp-active-style' stores a cons of the list specifying the
+;;;; current style, and a hash-table containing all indentation methods of
+;;;; that style and any styles it inherits from. Whenever we're indenting, we
+;;;; check that this is up to date, and recompute when necessary.
+;;;;
+;;;; Just setting the buffer local common-lisp-style will be enough to have
+;;;; the style take effect. `common-lisp-set-style' can also be called
+;;;; explicitly, however, and offers name completion, etc.
+
+;;; Convenience accessors
+(defun common-lisp-style-name (style) (first style))
+(defun common-lisp-style-inherits (style) (second style))
+(defun common-lisp-style-variables (style) (third style))
+(defun common-lisp-style-indentation (style) (fourth style))
+(defun common-lisp-style-hook (style) (fifth style))
+(defun common-lisp-style-docstring (style) (sixth style))
+
+(defun common-lisp-make-style (stylename inherits variables indentation hook documentation)
+  (list stylename inherits variables indentation hook documentation))
 
 (defvar common-lisp-style nil)
 
@@ -217,20 +231,22 @@
   :type 'string
   :group 'lisp-indent)
 
-;;; Common Lisp indentation style specification for the current buffer.
-(defvar common-lisp-active-style nil)
+(make-variable-buffer-local 'common-lisp-style)
+(set-default 'common-lisp-style nil)
 
 ;;; `lisp-mode' kills all buffer-local variables. Setting the
 ;;; `permanent-local' property allows us to retain the style.
 (put 'common-lisp-style 'permanent-local t)
 
+;;; Mark as safe when the style doesn't evaluate arbitrary code.
+(put 'common-lisp-style 'safe-local-variable 'common-lisp-safe-style-p)
+
 ;;; If style is being used, that's a sufficient invitation to snag
 ;;; the indentation function.
 (defun common-lisp-lisp-mode-hook ()
   (let ((style (or common-lisp-style common-lisp-style-default)))
     (when style
-      (set (make-local-variable 'lisp-indent-function)
-           'common-lisp-indent-function)
+      (set (make-local-variable 'lisp-indent-function) 'common-lisp-indent-function)
       (common-lisp-set-style style))))
 (add-hook 'lisp-mode-hook 'common-lisp-lisp-mode-hook)
 
@@ -240,70 +256,119 @@
 (defun common-lisp-delete-style (stylename)
   (remhash stylename common-lisp-styles))
 
-(defun common-lisp-add-style (stylename base variables indentation hooks documentation)
-  (let* ((style (or (gethash stylename common-lisp-styles)
-                    (let ((new (list (intern stylename)             ; name
-                                     nil                            ; variable bindings
-                                     (make-hash-table :test 'equal) ; indentation table
-                                     nil                            ; hooks
-                                     nil)))                         ; docstring
-                      (puthash stylename new common-lisp-styles)
-                      new)))
-         (base-style (when base
-                       (or (gethash base common-lisp-styles)
-                           (error "Unknown base Common Lisp style: %s" base))))
-         (base-vars (second base-style))
-         (base-methods (third base-style))
-         (base-hooks (fourth base-style)))
-    ;; Variables
-    (setf (second style) variables)
-    (dolist (var base-vars)
-      (unless (assoc (car var) variables)
-        (push var (second style))))
-    ;; Indentation
-    (let ((methods (third style)))
-      (clrhash methods)
-      (when base-methods
-        (maphash (lambda (s m)
-                   (puthash s m methods))
-                 base-methods))
-      (dolist (indent indentation)
-        (let* ((name (car indent))
-               (spec (cdr indent))
-               (method
-                (if (symbolp spec)
-                    (list :as spec)
-                  (when (cdr spec)
-                    (error "Malformed Common Lisp indentation spec: %s" indent))
-                  (car spec))))
-          (puthash name method methods))))
-    ;; Hooks
-    (setf (fourth style) nil)
-    (dolist (hook (reverse base-hooks))
-      (unless (member hook hooks)
-        (push hook (fourth style))))
-    (dolist (hook (reverse hooks))
-      (push hook (fourth style)))
-    ;; Documentation
-    (setf (fifth style) documentation)
-    ;; Frob `common-lisp-style' docstring.
-    (let ((doc (get 'common-lisp-style 'common-lisp-style-base-doc))
-          (all nil))
-      (setq doc (concat doc "\n\nAvailable styles are:\n"))
-      (maphash (lambda (name style)
-                 (push (list name (fifth style)) all))
-               common-lisp-styles)
-      (dolist (info (sort all (lambda (a b) (string< (car a) (car b)))))
-        (let ((style-name (first info))
-              (style-doc (second info)))
-          (if style-doc
-              (setq doc (concat doc
-                                "\n " style-name "\n"
-                                "   " style-doc "\n"))
-                     (setq doc (concat doc
-                                       "\n " style-name " (undocumented)\n")))))
-      (put 'common-lisp-style 'variable-documentation doc))
-    stylename))
+(defun common-lisp-find-style (stylename)
+  (let ((name (if (symbolp stylename)
+                  (symbol-name stylename)
+                stylename)))
+    (or (gethash name common-lisp-styles)
+        (error "Unknown Common Lisp style: %s" name))))
+
+(defun common-lisp-safe-style-p (stylename)
+  "True for known Common Lisp style which doesn't have or inherit an :EVAL option.
+Ie. styles that will not evaluate arbitrary code on activation."
+  (let* ((style (ignore-errors (common-lisp-find-style stylename)))
+         (base (common-lisp-style-inherits style)))
+    (and style
+         (not (common-lisp-style-hook style))
+         (or (not base)
+             (common-lisp-safe-style-p base)))))
+
+(defun common-lisp-add-style (stylename inherits variables indentation hooks documentation)
+  ;; Invalidate indentation methods cached in common-lisp-active-style.
+  (maphash (lambda (k v)
+             (puthash k (copy-list v) common-lisp-styles))
+           common-lisp-styles)
+  ;; Add/Redefine the specified style.
+  (puthash stylename
+           (common-lisp-make-style stylename inherits variables indentation hooks
+                                   documentation)
+           common-lisp-styles)
+  ;; Frob `common-lisp-style' docstring.
+  (let ((doc (get 'common-lisp-style 'common-lisp-style-base-doc))
+        (all nil))
+    (setq doc (concat doc "\n\nAvailable styles are:\n"))
+    (maphash (lambda (name style)
+               (push (list name (common-lisp-style-docstring style)) all))
+             common-lisp-styles)
+    (dolist (info (sort all (lambda (a b) (string< (car a) (car b)))))
+      (let ((style-name (first info))
+            (style-doc (second info)))
+        (if style-doc
+            (setq doc (concat doc
+                              "\n " style-name "\n"
+                              "   " style-doc "\n"))
+          (setq doc (concat doc
+                            "\n " style-name " (undocumented)\n")))))
+    (put 'common-lisp-style 'variable-documentation doc))
+  stylename)
+
+;;; Activate STYLENAME, adding its indentation methods to METHODS -- and
+;;; recurse on style inherited from.
+(defun common-lisp-activate-style (stylename methods)
+  (let* ((style (common-lisp-find-style stylename))
+         (basename (common-lisp-style-inherits style)))
+    ;; Recurse on parent.
+    (when basename
+      (common-lisp-activate-style basename methods))
+    ;; Copy methods
+    (dolist (spec (common-lisp-style-indentation style))
+      (puthash (first spec) (second spec) methods))
+    ;; Bind variables.
+    (dolist (var (common-lisp-style-variables style))
+      (set (make-local-variable (first var)) (second var)))
+    ;; Run hook.
+    (let ((hook (common-lisp-style-hook style)))
+      (when hook
+        (funcall hook)))))
+
+;;; When a style is being used, `common-lisp-active-style' holds a cons
+;;;
+;;;   (STYLE . METHODS)
+;;;
+;;; where STYLE is the list specifying the currently active style, and
+;;; METHODS is the table of indentation methods --  including inherited
+;;; ones -- for it. `common-lisp-active-style-methods' is reponsible
+;;; for keeping this up to date.
+(make-variable-buffer-local 'common-lisp-active-style)
+(set-default 'common-lisp-active-style nil)
+
+;;; Makes sure common-lisp-active-style corresponds to common-lisp-style, and
+;;; pick up redefinitions, etc. Returns the method table for the currently
+;;; active style.
+(defun common-lisp-active-style-methods ()
+  (let* ((name common-lisp-style)
+         (style (when name (common-lisp-find-style name))))
+    (if (eq style (car common-lisp-active-style))
+        (cdr common-lisp-active-style)
+      (when style
+        (let ((methods (make-hash-table :test 'equal)))
+          (common-lisp-activate-style name methods)
+          (setq common-lisp-active-style (cons style methods))
+          methods)))))
+
+(defvar common-lisp-set-style-history nil)
+
+(defun common-lisp-set-style (stylename)
+  "Set current buffer to use the Common Lisp style STYLENAME.
+STYLENAME, a string, must be an existing Common Lisp style. Styles
+are added (and updated) using `define-common-lisp-style'.
+
+The buffer-local variable `common-lisp-style' will get set to STYLENAME.
+
+A Common Lisp style is composed of local variables, indentation
+specifications, and may also contain arbitrary elisp code to run upon
+activation."
+  (interactive
+   (list (let ((completion-ignore-case t)
+               (prompt "Specify Common Lisp indentation style: "))
+           (completing-read prompt
+                            common-lisp-styles nil t nil
+                            'common-lisp-set-style-history))))
+  (setq common-lisp-style (common-lisp-style-name (common-lisp-find-style stylename))
+        common-lisp-active-style nil)
+  ;; Actually activates the style.
+  (common-lisp-active-style-methods)
+  stylename)
 
 (defmacro define-common-lisp-style (name documentation &rest options)
   "Define a Common Lisp indentation style.
@@ -331,7 +396,9 @@
  (:eval form ...)
 
   Lisp code to evaluate when activating the style. This can be used to
-  eg. activate other modes.
+  eg. activate other modes. It is possible that over the lifetime of
+  a buffer same style gets activated multiple times, so code in :eval
+  option should cope with that.
 "
   (when (consp documentation)
     (setq documentation nil
@@ -341,9 +408,8 @@
                           ',(cdr (assoc :variables options))
                           ',(cdr (assoc :indentation options))
                           ,(when (assoc :eval options)
-                            `(list
-                              (lambda ()
-                                ,@(cdr (assoc :eval options)))))
+                             `(lambda ()
+                                ,@(cdr (assoc :eval options))))
                           ,documentation))
 
 (define-common-lisp-style "basic"
@@ -414,41 +480,6 @@
    (def!struct         (:as defstruct))
    (def!type           (:as deftype))
    (defmacro-mundanely (:as defmacro))))
-
-(defvar common-lisp-set-style-history nil)
-
-(defun common-lisp-set-style (stylename)
-  "Set current buffer to use the Common Lisp style STYLENAME.
-STYLENAME, a string, must be an existing Common Lisp style. Styles
-are added (and updated) using `common-lisp-add-style'.
-
-The buffer-local variable `common-lisp-style' will get set to STYLENAME.
-Simply setting
-
-A Common Lisp style is composed of variable and indentation specifications."
-  (interactive
-   (list (let ((completion-ignore-case t)
-               (prompt "Specify Common Lisp indentation style: "))
-           (completing-read prompt
-                            common-lisp-styles nil t nil
-                            'common-lisp-set-style-history))))
-  (let* ((stylename (if (stringp stylename)
-                        stylename
-                      (symbol-name stylename)))
-         (style (or (gethash stylename common-lisp-styles)
-                    (error "Unknown Common Lisp style: %s" stylename))))
-    (common-lisp-activate-style style)))
-
-(defun common-lisp-activate-style (style)
-  (let ((vars (second style))
-        (methods (third style))
-        (hooks (fourth style)))
-    (dolist (var vars)
-      (set (make-local-variable (car var)) (cadr var)))
-    (dolist (hook hooks)
-      (funcall hook))
-    (set (make-local-variable 'common-lisp-style) (car style))
-    (set (make-local-variable 'common-lisp-active-style) style)))
 
 ;;;; The indentation specs are stored at three levels. In order of priority:
 ;;;;
@@ -504,8 +535,8 @@
   (let ((method
          (or
           ;; From style
-          (when common-lisp-active-style
-            (gethash name (third common-lisp-active-style)))
+          (when common-lisp-style
+            (gethash name (common-lisp-active-style-methods)))
           ;; From global settings.
           (get name 'common-lisp-indent-function)
           ;; From system derived information.





More information about the slime-cvs mailing list