[slime-devel] Patch to make slime-insert-arglist more useful
Matthias Koeppe
mkoeppe+slime at mail.math.uni-magdeburg.de
Fri Dec 17 13:39:58 UTC 2004
Please find below a patch that makes C-c C-s (slime-insert-arglist)
much more useful. Instead of inserting a formal argument list, it
inserts a template for a function call; this makes a difference for
functions with optional and keyword arguments. After inserting the
arguments, point is left on the first argument, like ILISP's C-u M-x
arglist-lisp does; this allows editing the arguments easily.
Index: slime.el
===================================================================
RCS file: /project/slime/cvsroot/slime/slime.el,v
retrieving revision 1.443
diff -u -p -u -r1.443 slime.el
--- slime.el 16 Dec 2004 22:24:41 -0000 1.443
+++ slime.el 17 Dec 2004 13:24:07 -0000
@@ -4227,7 +4227,17 @@ more than one space."
"Insert the argument list for NAME behind the symbol point is
currently looking at."
(interactive (list (slime-read-symbol-name "Arglist of: ")))
- (insert (slime-eval `(swank:arglist-for-insertion ',name))))
+ (let ((arglist (slime-eval `(swank:arglist-for-insertion ',name))))
+ (cond
+ ((eq arglist :not-available)
+ (error "Arglist not available"))
+ ((string-match "^(" arglist)
+ (insert " ")
+ (save-excursion
+ (insert (substring arglist 1))))
+ (t
+ (save-excursion
+ (insert arglist))))))
(defun slime-get-arglist (symbol-name)
"Return the argument list for SYMBOL-NAME."
Index: swank.lisp
===================================================================
RCS file: /project/slime/cvsroot/slime/swank.lisp,v
retrieving revision 1.272
diff -u -p -u -r1.272 swank.lisp
--- swank.lisp 16 Dec 2004 21:16:50 -0000 1.272
+++ swank.lisp 17 Dec 2004 13:25:18 -0000
@@ -1143,17 +1143,108 @@ pretty printing of (function foo) as #'f
(*print-length* 10) (*print-circle* t))
(format nil "~A => ~A" sym (symbol-value sym)))))))
+(defun decode-keyword-arg (arg)
+ "Decode a keyword item of formal argument list.
+Return three values: keyword, argument name, default arg."
+ (cond
+ ((symbolp arg)
+ (values (intern (symbol-name arg) keyword-package)
+ arg
+ nil))
+ ((and (consp arg)
+ (consp (car arg)))
+ (values (caar arg)
+ (cadar arg)
+ (cadr arg)))
+ ((consp arg)
+ (values (intern (symbol-name (car arg)) keyword-package)
+ (car arg)
+ (cadr arg)))
+ (t
+ (error "Bad keyword item of formal argument list"))))
+(progn
+ (assert (equal (multiple-value-list (decode-keyword-arg 'x)) '(:x x nil)))
+ (assert (equal (multiple-value-list (decode-keyword-arg '(x t))) '(:x x t)))
+ (assert (equal (multiple-value-list (decode-keyword-arg '((:x y)))) '(:x y nil)))
+ (assert (equal (multiple-value-list (decode-keyword-arg '((:x y) t))) '(:x y t))))
+(defun decode-optional-arg (arg)
+ "Decode an optional item of a formal argument list.
+Return two values: argument name, default arg."
+ (etypecase arg
+ (symbol
+ (values arg nil))
+ (list
+ (values (car arg) (cadr arg)))))
+(progn
+ (assert (equal (multiple-value-list (decode-optional-arg 'x)) '(x nil)))
+ (assert (equal (multiple-value-list (decode-optional-arg '(x t))) '(x t))))
+
+(defun arglist-to-template-string (arglist package)
+ "Print the list ARGLIST for insertion as a template for a function call."
+ (setq arglist (clean-arglist arglist))
+ (etypecase arglist
+ (null "()")
+ (cons
+ (with-output-to-string (*standard-output*)
+ (with-standard-io-syntax
+ (let ((*package* package) (*print-case* :downcase)
+ (*print-pretty* t) (*print-circle* nil) (*print-readably* nil)
+ (*print-level* 10) (*print-length* 20))
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (let ((mode nil))
+ (loop
+ (let ((arg (pop arglist)))
+ (typecase arg
+ ((member &key &optional &rest &body)
+ (setq mode arg))
+ (string
+ (princ arg)
+ (unless (null arglist)
+ (write-char #\space)))
+ (t
+ (case mode
+ (&key
+ (multiple-value-bind (keyword arg-symbol default-arg)
+ (decode-keyword-arg arg)
+ (declare (ignore default-arg))
+ (write keyword)
+ (write-char #\space)
+ (princ arg-symbol)))
+ (&optional
+ (multiple-value-bind (arg-symbol default-arg)
+ (decode-optional-arg arg)
+ (declare (ignore default-arg))
+ (write-char #\[)
+ (princ arg-symbol)
+ (write-char #\])))
+ (&body
+ (pprint-newline :mandatory)
+ (princ arg)
+ (princ "..."))
+ (&rest
+ (princ arg)
+ (princ "..."))
+ (otherwise
+ (princ arg)))
+ (unless (null arglist)
+ (write-char #\space)))))
+ (when (null arglist) (return))
+ (pprint-newline :fill))))))))))
+
+(defun test-print-template (list string)
+ (string= (arglist-to-template-string list (find-package :swank)) string))
+
(defslimefun arglist-for-insertion (name)
(with-buffer-syntax ()
(cond ((valid-operator-name-p name)
(let ((arglist (arglist (parse-symbol name))))
(etypecase arglist
((member :not-available)
- " <not available>")
+ :not-available)
(list
- (arglist-to-string arglist *buffer-package*)))))
+ (arglist-to-template-string arglist *buffer-package*)))))
(t
- " <not available>"))))
+ :not-available))))
;;;; Evaluation
--
Matthias Köppe -- http://www.math.uni-magdeburg.de/~mkoeppe
More information about the slime-devel
mailing list