[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