[climacs-cvs] CVS climacs

thenriksen thenriksen at common-lisp.net
Sun Jul 23 20:31:56 UTC 2006


Update of /project/climacs/cvsroot/climacs
In directory clnet:/tmp/cvs-serv3885

Modified Files:
	lisp-syntax.lisp lisp-syntax-commands.lisp 
Log Message:
Many changes, but CVS makes it too painful to break it up into smaller
patches (/me wishes for more modern VCS). The highlights are:

        * Symbol completion should no longer nuke quoting.

        * Symbol completion is now more intelligent with respect to
          completion of keywords for keyword arguments.

        * Changed some form selection functions to accept offsets as
          well as marks (using the `as-offsets' macro).

        * Realized that this syntax is becoming quite complex, slight
          refactoring is needed.


--- /project/climacs/cvsroot/climacs/lisp-syntax.lisp	2006/07/22 22:12:04	1.96
+++ /project/climacs/cvsroot/climacs/lisp-syntax.lisp	2006/07/23 20:31:56	1.97
@@ -1305,17 +1305,15 @@
 found, return the package specified in the attribute list. If no
 package can be found at all, or the otherwise found packages are
 invalid, return the CLIM-USER package."
-  (let* ((mark-offset (if (numberp mark-or-offset)
-                          mark-or-offset
-                          (offset mark-or-offset)))
-         (designator (rest (find mark-offset (package-list syntax)
-                                 :key #'first
-                                 :test #'>=))))
-    (or (handler-case (find-package designator)
-          (type-error ()
+  (as-offsets ((mark-or-offset offset))
+   (let* ((designator (rest (find offset (package-list syntax)
+                                  :key #'first
+                                  :test #'>=))))
+     (or (handler-case (find-package designator)
+           (type-error ()
              nil))
-        (find-package (option-specified-package syntax))
-        (find-package :clim-user))))
+         (find-package (option-specified-package syntax))
+         (find-package :clim-user)))))
 
 (defmacro with-syntax-package (syntax offset (package-sym) &body
                                body)
@@ -1489,8 +1487,6 @@
   (:method (form syntax) nil))
 
 (defmethod form-operands ((form list-form) syntax)
-  ;; If *anything' goes wrong, just assume that we could not find any
-  ;; operands and return nil.
   (mapcar #'(lambda (operand)
               (if (typep operand 'form)
                   (token-to-object syntax operand :no-error t)))
@@ -1517,60 +1513,64 @@
 ;;;
 ;;; Useful functions for selecting forms based on the mark.
 
-(defun expression-at-mark (mark syntax)
-  "Return the form at `mark'. If `mark' is just after,
+(defun expression-at-mark (mark-or-offset syntax)
+  "Return the form at `mark-or-offset'. If `mark-or-offset' is just after,
 or inside, a top-level-form, or if there are no forms after
-`mark', the form preceding `mark' is returned. Otherwise, the
-form following `mark' is returned."
-  (or (form-around syntax (offset mark))
-      (form-after syntax (offset mark))
-      (form-before syntax (offset mark))))
-
-(defun definition-at-mark (mark syntax)
-  "Return the top-level form at `mark'. If `mark' is just after,
-or inside, a top-level-form, or if there are no forms after
-`mark', the top-level-form preceding `mark' is
-returned. Otherwise, the top-level-form following `mark' is
+`mark-or-offset', the form preceding `mark-or-offset' is
+returned. Otherwise, the form following `mark-or-offset' is
 returned."
-  (form-toplevel (expression-at-mark mark syntax) syntax))
+  (as-offsets ((mark-or-offset offset))
+   (or (form-around syntax offset)
+       (form-after syntax offset)
+       (form-before syntax offset))))
 
-(defun symbol-at-mark (mark syntax)
-  "Return a symbol token at mark. This function will \"unwrap\"
-  quote-forms in order to return the symbol token. If no symbol
-  token can be found, NIL will be returned."
+(defun definition-at-mark (mark-or-offset syntax)
+  "Return the top-level form at `mark-or-offset'. If `mark-or-offset' is just after,
+or inside, a top-level-form, or if there are no forms after
+`mark-or-offset', the top-level-form preceding `mark-or-offset'
+is returned. Otherwise, the top-level-form following
+`mark-or-offset' is returned."
+  (form-toplevel (expression-at-mark mark-or-offset syntax) syntax))
+
+(defun symbol-at-mark (mark-or-offset syntax)
+  "Return a symbol token at `mark-or-offset'. This function will
+  \"unwrap\" quote-forms in order to return the symbol token. If
+  no symbol token can be found, NIL will be returned."
   (labels ((unwrap-form (form)
              (cond ((typep form 'quote-form)
                     (unwrap-form (first-form (children form))))
                    ((typep form 'complete-token-lexeme)
                     form))))
-    (unwrap-form (expression-at-mark mark syntax))))
+    (unwrap-form (expression-at-mark mark-or-offset syntax))))
 
-(defun this-form (mark syntax)
-  "Return a form at mark. This function defines which
+(defun this-form (mark-or-offset syntax)
+  "Return a form at `mark-or-offset'. This function defines which
   forms the COM-FOO-this commands affect."
-  (or (form-around syntax (offset mark))
-      (form-before syntax (offset mark))))
-
-(defun preceding-form (mark syntax)
-  "Return a form at mark."
-  (or (form-before syntax (offset mark))
-      (form-around syntax (offset mark))))
+  (as-offsets ((mark-or-offset offset))
+    (or (form-around syntax offset)
+        (form-before syntax offset))))
+
+(defun preceding-form (mark-or-offset syntax)
+  "Return a form at `mark-or-offset'."
+  (as-offsets ((mark-or-offset offset))
+   (or (form-before syntax offset)
+       (form-around syntax offset))))
 
 (defun text-of-definition-at-mark (mark syntax)
   "Return the text of the definition at mark."
   (let ((definition (definition-at-mark mark syntax)))
     (buffer-substring (buffer mark)
-                      (start-offset definition)                      
+                      (start-offset definition)           
                       (end-offset definition))))
                       
-(defun text-of-expression-at-mark (mark syntax)
-  "Return the text of the expression at mark."
-  (let ((expression (expression-at-mark mark syntax)))
+(defun text-of-expression-at-mark (mark-or-offset syntax)
+  "Return the text of the expression at `mark-or-offset'."
+  (let ((expression (expression-at-mark mark-or-offset syntax)))
     (token-string syntax expression)))
 
-(defun symbol-name-at-mark (mark syntax)
-  "Return the text of the symbol at mark."
-  (let ((token (symbol-at-mark mark syntax)))
+(defun symbol-name-at-mark (mark-or-offset syntax)
+  "Return the text of the symbol at `mark-or-offset'."
+  (let ((token (symbol-at-mark mark-or-offset syntax)))
     (when token (token-string syntax token))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1581,8 +1581,7 @@
   "Replace the symbol at `mark' with `string' and move `mark' to
 after `string'."
   (let ((token (symbol-at-mark mark syntax)))
-    (unless (= (offset mark) (start-offset token))
-      (backward-expression mark syntax 1 nil))
+    (setf (offset mark) (start-offset token))
     (forward-kill-expression mark syntax)
     (insert-sequence mark string)))
 
@@ -1844,15 +1843,15 @@
          (should-highlight (or (= (the fixnum (end-offset parse-symbol)) point-offset)
                                (= (the fixnum (start-offset parse-symbol)) point-offset))))
     (if should-highlight
-	(with-text-face (pane :bold)
-	  (display-parse-tree (car children) syntax pane))
-	(display-parse-tree (car children) syntax pane))
+        (with-text-face (pane :bold)
+          (display-parse-tree (car children) syntax pane))
+        (display-parse-tree (car children) syntax pane))
     (loop for child-list on (cdr children)
        if (and should-highlight (null (cdr child-list))) do
-         (with-text-face (pane :bold)
-           (display-parse-tree (car child-list) syntax pane))
-         else do
-         (display-parse-tree (car child-list) syntax pane))))
+       (with-text-face (pane :bold)
+         (display-parse-tree (car child-list) syntax pane))
+       else do
+       (display-parse-tree (car child-list) syntax pane))))
 
 (defmethod display-parse-tree ((parse-symbol incomplete-list-form) (syntax lisp-syntax) pane)
   (let* ((children (children parse-symbol))
@@ -3559,44 +3558,42 @@
 (defun find-operand-info (mark-or-offset syntax operator-form)
   "Returns two values: The operand preceding `mark-or-offset' and
   the path from `operator-form' to the operand."
-  (let* ((offset (if (numberp mark-or-offset)
-                     mark-or-offset
-                     (offset mark-or-offset)))
-         (preceding-arg-token (form-before syntax offset))
-         (indexing-start-arg
-          (let* ((candidate-before preceding-arg-token)
-                 (candidate-after (when (null candidate-before)
-                                    (let ((after (form-after syntax offset)))
-                                      (when after
-                                        (parent after)))))
-                 (candidate-around (when (null candidate-after)
-                                     (form-around syntax offset)))
-                 (candidate (or candidate-before
-                                candidate-after
-                                candidate-around)))
-            (if (or (and candidate-before
-                         (typep candidate-before 'incomplete-list-form))
-                    (and (null candidate-before)
-                         (typep (or candidate-after candidate-around)
-                                'list-form)))
-                ;; HACK: We should not attempt to find the location of
-                ;; the list form itself, so we create a new parser
-                ;; symbol, attach the list form as a parent and try to
-                ;; find the new symbol. That way we can get a list of
-                ;; argument-indices to the first element of the list
-                ;; form, even if it is empty or incomplete.
-                (let ((obj (make-instance 'parser-symbol)))
-                  (setf (parent obj) candidate)
-                  obj)
-                candidate)))
-         (argument-indices (find-argument-indices-for-operand
-                            syntax
-                            indexing-start-arg
-                            operator-form))
-         (preceding-arg-obj (when preceding-arg-token
-                              (token-to-object syntax preceding-arg-token
-                                               :no-error t))))
-    (values preceding-arg-obj argument-indices)))
+  (as-offsets ((mark-or-offset offset))
+    (let* ((preceding-arg-token (form-before syntax offset))
+           (indexing-start-arg
+            (let* ((candidate-before preceding-arg-token)
+                   (candidate-after (when (null candidate-before)
+                                      (let ((after (form-after syntax offset)))
+                                        (when after
+                                          (parent after)))))
+                   (candidate-around (when (null candidate-after)
+                                       (form-around syntax offset)))
+                   (candidate (or candidate-before
+                                  candidate-after
+                                  candidate-around)))
+              (if (or (and candidate-before
+                           (typep candidate-before 'incomplete-list-form))
+                      (and (null candidate-before)
+                           (typep (or candidate-after candidate-around)
+                                  'list-form)))
+                  ;; HACK: We should not attempt to find the location of
+                  ;; the list form itself, so we create a new parser
+                  ;; symbol, attach the list form as a parent and try to
+                  ;; find the new symbol. That way we can get a list of
+                  ;; argument-indices to the first element of the list
+                  ;; form, even if it is empty or incomplete.
+                  (let ((obj (make-instance 'parser-symbol)))
+                    (setf (parent obj) candidate)
+                    obj)
+                  candidate)))
+           (argument-indices (find-argument-indices-for-operand
+                              syntax
+                              indexing-start-arg
+                              operator-form))
+           (preceding-arg-obj (when preceding-arg-token
+                                (token-to-object syntax preceding-arg-token
+                                                 :no-error t))))
+      (values preceding-arg-obj argument-indices))))
 
 (defun valid-operator-p (operator)
   "Check whether or not `operator' is a valid
@@ -3654,9 +3651,9 @@
     (when (parent form)
       (recurse (parent form)))))
 
-(defmacro with-code-insight (mark syntax (&key operator preceding-operand
-                                               form preceding-operand-indices
-                                               operands)
+(defmacro with-code-insight (mark-or-offset 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
@@ -3669,7 +3666,7 @@
         ;; My kingdom for with-gensyms (or once-only)!
         (mark-value-sym (gensym))
         (syntax-value-sym (gensym)))
-    `(let* ((,mark-value-sym ,mark)
+    `(let* ((,mark-value-sym ,mark-or-offset)
             (,syntax-value-sym ,syntax)
             (,form-sym
              ;; Find a form with a valid (fboundp) operator.
@@ -3683,35 +3680,38 @@
                ;; cannot find a form with a valid operator, just
                ;; return the form `mark' is in.
                (unless (null immediate-form)
-                (labels ((recurse (form)
-                           (unless (null (parent form))
-                             (or (unless (eq (first-form (children (parent form)))
-                                             form)
-                                   (recurse (parent form)))
-                                 (and (valid-operator-p (form-operator
-                                                         form
-                                                         ,syntax-value-sym))
-                                      (indices-match-arglist
-                                       (arglist-for-form
-                                        (form-operator
-                                         form
-                                         ,syntax-value-sym)
-                                        (form-operands
-                                         form
-                                         ,syntax-value-sym))
-                                       (second
-                                        (multiple-value-list
-                                         (find-operand-info ,mark-value-sym ,syntax-value-sym form))))
-                                      (not (direct-arg-p form ,syntax-value-sym))
-                                      form)))))
-                  (or (recurse (parent immediate-form))
-                      (parent immediate-form))))))
+                 (labels ((recurse (form)
+                            (unless (null (parent form))
+                              (or (unless (eq (first-form (children (parent form)))
+                                              form)
+                                    (recurse (parent form)))
+                                  (and (valid-operator-p (form-operator
+                                                          form
+                                                          ,syntax-value-sym))
+                                       (indices-match-arglist
+                                        (arglist-for-form
+                                         (form-operator
+                                          form
+                                          ,syntax-value-sym)
+                                         (form-operands
+                                          form
+                                          ,syntax-value-sym))
+                                        (second
+                                         (multiple-value-list
+                                          (find-operand-info ,mark-value-sym ,syntax-value-sym form))))
+                                       (not (direct-arg-p form ,syntax-value-sym))
+                                       form)))))
+                   (or (recurse (parent 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))))
+       (declare (ignorable ,mark-value-sym ,syntax-value-sym ,form-sym
+                           ,operator-sym ,operands-sym))
        (multiple-value-bind (,preceding-operand-sym ,operand-indices-sym)
            (when ,form-sym (find-operand-info ,mark-value-sym ,syntax-value-sym ,form-sym))
+         (declare (ignorable ,preceding-operand-sym ,operand-indices-sym))
          , at body))))
 
 (defun show-arglist-for-form-at-mark (mark syntax)
@@ -3824,6 +3824,103 @@
 
 (defvar *completion-pane* nil)
 
+(defun relevant-keywords (arglist arg-indices)
+  "Return a list of the keyword arguments that it would make
+  sense to use at the position `arg-indices' relative to the
+  operator that has the argument list `arglist'."
+  (let* ((key-position (position '&key arglist))
+         (cleaned-arglist (remove-if #'arglist-keyword-p
+                                     arglist))
+         (index (first arg-indices))
+         (difference (- (length arglist)
+                        (length cleaned-arglist))))
+    (cond ((and (null key-position)
+                (rest arg-indices)
+                (> (length cleaned-arglist)
+                   index)
+                (listp (elt cleaned-arglist index)))
+           ;; Look in a nested argument list.
+           (relevant-keywords (elt cleaned-arglist index)
+                              (rest arg-indices)))
+          ((and (not (null key-position))
+                (>= (+ index
+                       difference) 
+                    key-position)
+                (not (evenp (- index key-position difference))))
+           (mapcar #'unlisted (subseq cleaned-arglist
+                                      (- key-position
+                                         difference
+                                         -1)))))))
+
+(defun completions-from-keywords (syntax token)
+  "Assume that `token' is a (partial) keyword argument
+keyword. Find out which operator it is applicable to, and return
+a completion list based on the valid keywords, or NIL, if no
+keyword arguments would be valid (for example, if the operator
+doesn't take keyword arguments)."
+  (with-code-insight (start-offset token) syntax
+      (:preceding-operand-indices poi
+                                  :operator operator)
+    (when (valid-operator-p operator)
+      (let* ((relevant-keywords
+              (relevant-keywords (arglist-for-form operator)
+                                 poi))
+             (completions (simple-completions
+                           (get-usable-image syntax)
+                           (token-string syntax token)
+                           +keyword-package+))
+             (relevant-completions
+              (remove-if-not #'(lambda (compl)
+                                 (member compl relevant-keywords
+                                         :test #'(lambda (a b)
+                                                   (string-equal a b
+                                                                 :start1 1))
+                                         :key #'symbol-name))
+                             (mapcar #'string-downcase (first completions)))))
+        (list relevant-completions
+              (longest-completion relevant-completions))))))
+
+;; The following stuff is from Swank.
+
+(defun longest-completion (completions)
+  "Return the longest completion of `completions', which must be a
+list of sequences."

[76 lines skipped]
--- /project/climacs/cvsroot/climacs/lisp-syntax-commands.lisp	2006/07/21 06:15:40	1.9
+++ /project/climacs/cvsroot/climacs/lisp-syntax-commands.lisp	2006/07/23 20:31:56	1.10
@@ -254,11 +254,11 @@
          (buffer (buffer pane))
          (syntax (syntax buffer))
          (mark (point pane))
-	 (name (symbol-name-at-mark mark
-				    syntax)))
-    (when name
+	 (token (symbol-at-mark mark
+                                syntax)))
+    (when token
       (with-syntax-package syntax mark (package)
-        (let ((completion (show-completions syntax name package)))
+        (let ((completion (show-completions syntax token package)))
           (unless (= (length completion) 0)
             (replace-symbol-at-mark mark syntax completion)))))))
 




More information about the Climacs-cvs mailing list