[clim-desktop-cvs] CVS clim-desktop

thenriksen thenriksen at common-lisp.net
Sun May 28 12:26:08 UTC 2006


Update of /project/clim-desktop/cvsroot/clim-desktop
In directory clnet:/tmp/cvs-serv28292

Modified Files:
	swine.lisp swine-cmds.lisp 
Log Message:
* Cleaned some of the mechanics of the parameter hinting code,
factored some of the hairy bits to a reusable
`with-code-insight'-macro.

* Begun the construction of a form traits protocol for customizing the
parameter hinting of forms.

* Fixed handling of values for &optional parameters with default values.

* Added parameter hinting for ((lambda (...) ...) ...)-style
  forms. :-)


--- /project/clim-desktop/cvsroot/clim-desktop/swine.lisp	2006/05/20 17:30:30	1.9
+++ /project/clim-desktop/cvsroot/clim-desktop/swine.lisp	2006/05/28 12:26:08	1.10
@@ -449,7 +449,7 @@
                                                    optional-args-count)
                                                 provided-args-count))))
           (append (mapcar #'cons
-                          (get-args '&optional)
+                          (mapcar #'unlisted (get-args '&optional))
                           opt-args-values)
 
                   (loop
@@ -667,57 +667,81 @@
                                  operator)))
         arglist)))
 
-(defun show-arglist-silent (symbol &optional
+(defmethod arglist-for-form ((operator list) &optional arguments)
+  (declare (ignore arguments))
+  (case (first operator)
+    ('cl:lambda (second operator))))
+
+(defgeneric operator-for-display (operator)
+  (:documentation "Return what should be displayed whenever
+  `operator' is displayed as an operator.")
+  (:method (operator)
+    operator))
+
+(defmethod operator-for-display ((operator list))
+  (case (first operator)
+    ('cl:lambda '|Lambda-Expression|)))
+
+(defun display-arglist-to-stream (stream operator arglist
+                                  &optional emphasized-symbols
+                                  highlighted-symbols)
+  "Display the operator and arglist to stream, format as
+  appropriate."
+  ;; FIXME: This is fairly ugly.
+  (labels ((display-symbol (symbol)
+             (with-text-style
+                 (stream
+                  `(nil
+                    ,(cond ((member symbol
+                                    highlighted-symbols)
+                            :bold)
+                           ((member symbol
+                                    emphasized-symbols)
+                            :italic))
+                    nil))
+               (format stream "~A" symbol)))
+           (display-list (list)
+             (if (and (eq (first list) 'quote)
+                      (= (length list) 2))
+                 (progn
+                   (format stream "'")
+                   (display-argument (second list)))
+                 (progn
+                   (format stream "(")
+                   (display-argument (first list))
+                   (dolist (arg (rest list))
+                     (format stream " ")
+                     (display-argument arg))
+                   (format stream ")"))))
+           (display-argument (arg)
+             (if (and (listp arg)
+                      (not (null arg)))
+                 (display-list arg)
+                 (display-symbol arg))))
+    (display-argument (cons (operator-for-display operator)
+                            arglist))))
+
+(defun show-arglist-silent (operator &optional
                             current-arg-indices
                             preceding-arg arguments)
-  "Display the arglist for `symbol' in the minibuffer, do not
-complain if `symbol' is not bound to a function.
+  "Display the arglist for `operator' in the minibuffer, do not
+complain if `operator' is not bound to, or is not, a function.
 
 `Current-arg-index' and `preceding-arg' are used to add extra
 information to the arglist display. `Arguments' should be either
 nil or a list of provided arguments in the form housing symbol.
 
 Returns NIL if an arglist cannot be displayed."
-  (when (fboundp symbol)
-    (multiple-value-bind (arglist emphasized-symbols highlighted-symbols)
-        (analyze-arglist
-         (arglist-for-form symbol arguments)
-         current-arg-indices
-         preceding-arg
-         arguments)
-      ;; FIXME: This is fairly ugly.
-      (esa:with-minibuffer-stream (minibuffer)
-        (labels ((display-symbol (symbol)
-                   (with-text-style
-                       (minibuffer
-                        `(nil
-                          ,(cond ((member symbol
-                                         highlighted-symbols)
-                                 :bold)
-                                ((member symbol
-                                         emphasized-symbols)
-                                 :italic))
-                          nil))
-                     (format minibuffer "~A" symbol)))
-                 (display-list (list)
-                   (if (and (eq (first list) 'quote)
-                            (= (length list) 2))
-                       (progn
-                         (format minibuffer "'")
-                         (display-argument (second list)))
-                       (progn
-                         (format minibuffer "(")
-                         (display-argument (first list))
-                         (dolist (arg (rest list))
-                           (format minibuffer " ")
-                           (display-argument arg))
-                         (format minibuffer ")"))))
-                 (display-argument (arg)
-                   (if (and (listp arg)
-                            (not (null arg)))
-                       (display-list arg)
-                       (display-symbol arg))))
-          (display-argument (cons symbol arglist)))))))
+  (multiple-value-bind (arglist emphasized-symbols highlighted-symbols)
+      (analyze-arglist
+       (arglist-for-form operator arguments)
+       current-arg-indices
+       preceding-arg
+       arguments)
+    (esa:with-minibuffer-stream (minibuffer)
+      (display-arglist-to-stream minibuffer operator
+                                 arglist emphasized-symbols
+                                 highlighted-symbols))))
 
 (defun show-arglist (symbol name)
   (unless (show-arglist-silent symbol)
@@ -795,30 +819,74 @@
                                                :no-error t))))
     (values preceding-arg-obj argument-indices)))
 
+(defun valid-operator-p (operator)
+  "Check whether or not `operator' is a valid
+  operator. `Operator' is considered a valid operator if it is a
+  symbol bound to a function."
+  (and (symbolp operator)
+       (fboundp operator)))
+
+(defmacro with-code-insight (mark syntax (&key operator preceding-operand
+                                               form preceding-operand-indices
+                                               operands)
+                             &body body)
+  "Evaluate `body' with the provided symbols lexically bound to
+  interesting details about the code at `mark'. If `mark' is not
+  within a form, everything will be bound to nil."
+  (let ((operator-sym (or operator (gensym)))
+        (preceding-operand-sym (or preceding-operand (gensym)))
+        (operands-sym (or operands (gensym)))
+        (form-sym (or form (gensym)))
+        (operand-indices-sym (or preceding-operand-indices (gensym)))
+        ;; My kingdom for with-gensyms!
+        (mark-value-sym (gensym))
+        (syntax-value-sym (gensym)))
+    `(let* ((,mark-value-sym ,mark)
+            (,syntax-value-sym ,syntax)
+            (,form-sym
+             ;; Find a form with a valid (fboundp) operator.
+             (let ((immediate-form
+                    (or (form-before ,syntax-value-sym (offset ,mark-value-sym))
+                        (form-around ,syntax-value-sym (offset ,mark-value-sym)))))
+               ;; Recurse upwards until we find a form with a valid
+               ;; operator. This could be improved a lot, as we could
+               ;; inspect the lambda list of the found operator and
+               ;; check if the position of mark makes sense with
+               ;; regard to the structure of the lambda list. If we
+               ;; cannot find a form with a valid operator, just
+               ;; return the form `mark' is in.
+               (labels ((recurse (form)
+                          (if (valid-operator-p (form-operator
+                                                 form
+                                                 ,syntax-value-sym))
+                              form
+                              (when (and form (parent form))
+                                (recurse (parent form))))))
+                 (or (recurse (when immediate-form (parent immediate-form)))
+                     (when immediate-form (parent immediate-form))))))
+            ;; If we cannot find a form, there's no point in looking
+            ;; up any of this stuff.
+            (,operator-sym (when ,form-sym (form-operator ,form-sym ,syntax-value-sym)))
+            (,operands-sym (when ,form-sym (form-operands ,form-sym ,syntax-value-sym))))
+       (multiple-value-bind (,preceding-operand-sym ,operand-indices-sym)
+           (when ,form-sym (find-operand-info ,mark-value-sym ,syntax-value-sym ,form-sym))
+         , at body))))
+
  ;; This is a generic function in order to facilitate different lambda
  ;; list types for different form types (I'm not yet sure when this
  ;; would be useful).
-(defgeneric show-arglist-for-form (mark syntax form)
+(defgeneric show-arglist-for-form (mark syntax)
    (:documentation "Display the argument list for the operator of
  `form'. The list need not be complete. If an argument list cannot
  be retrieved for the operator, nothing will be displayed."))
 
-(defmethod show-arglist-for-form (mark syntax form)
-  (let* ((operator-symbol (form-operator form syntax)))
-    ;; The user may have provided an invalid function name as the
-    ;; operator - that should not result in an error.
-    (if (ignore-errors (fboundp operator-symbol))
-        (let* ((form-operands (form-operands form syntax)))
-          (multiple-value-bind (preceding-operand preceding-operand-indices)
-              (find-operand-info mark syntax form)
-            (show-arglist-silent operator-symbol
-                                 preceding-operand-indices
-                                 preceding-operand
-                                 form-operands)))
-        ;; If the symbol is not bound to a function, we move up
-        ;; a level and try that lists operator.
-        (when (parent form)
-          (show-arglist-for-form mark syntax (parent form))))))
+(defmethod show-arglist-for-form (mark syntax)
+  (with-code-insight mark syntax (:operator operator
+                                            :preceding-operand preceding-operand
+                                            :preceding-operand-indices preceding-operand-indices
+                                            :operands operands)
+    ;; The operator is not something usable (it might be a lambda form).
+    (show-arglist-silent operator preceding-operand-indices preceding-operand operands)))
 
 (defparameter *swine-find-definition-stack* '())
 
--- /project/clim-desktop/cvsroot/clim-desktop/swine-cmds.lisp	2006/05/20 17:30:30	1.15
+++ /project/clim-desktop/cvsroot/clim-desktop/swine-cmds.lisp	2006/05/28 12:26:08	1.16
@@ -221,12 +221,9 @@
     ;; the parse tree our insertion of a space character may have
     ;; done.
     (update-syntax (buffer syntax) syntax)
-    ;; Try to find the argument before point, if that is not possibly,
+    ;; Try to find the argument before point, if that is not possible,
     ;; find the form that point is in.
-    (let ((immediate-form (or (form-before syntax (offset mark))
-                              (form-around syntax (offset mark)))))
-      (when immediate-form
-        (show-arglist-for-form mark syntax (parent immediate-form))))
+    (show-arglist-for-form mark syntax)
     (forward-object mark)
     (clear-completions)))
 




More information about the Clim-desktop-cvs mailing list