Index: slime.el
===================================================================
RCS file: /project/slime/cvsroot/slime/slime.el,v
retrieving revision 1.673
diff -u -r1.673 slime.el
--- slime.el	20 Oct 2006 11:07:57 -0000	1.673
+++ slime.el	20 Oct 2006 14:42:02 -0000
@@ -273,7 +273,18 @@
   :group 'slime-mode
   :type 'boolean)
 
+(defcustom slime-fuzzy-completion-limit 300
+  "Only return and present this many symbols from swank."
+  :group 'slime-mode
+  :type 'integer)
+
+(defcustom slime-fuzzy-completion-time-limit-in-msec 1500
+  "Limit the time spent (given in msec) in swank while gathering comletitions.
+(NOTE: currently it's rounded up the nearest second)"
+  :group 'slime-mode
+  :type 'integer)
+
 (defcustom slime-space-information-p t
   "Have the SPC key offer arglist information."
   :type 'boolean

@@ -6187,7 +6200,9 @@
     (slime-eval `(swank:fuzzy-completions ,prefix 
                                           ,(or default-package
                                                (slime-find-buffer-package)
-                                               (slime-current-package))))))
+                                               (slime-current-package))
+                  :limit ,slime-fuzzy-completion-limit
+                  :time-limit-in-msec ,slime-fuzzy-completion-time-limit-in-msec))))
 
 (defun slime-fuzzy-selected (prefix completion)
   "Tell the connected Lisp that the user selected completion
@@ -6398,6 +6413,8 @@
   (with-current-buffer (slime-get-fuzzy-buffer)
     (slime-fuzzy-dehighlight-current-completion)
     (let ((point (next-single-char-property-change (point) 'completion)))
+      (when (= point (point-max))
+        (setf point (previous-single-char-property-change (point-max) 'completion nil slime-fuzzy-first)))
       (set-window-point (get-buffer-window (current-buffer)) point)
       (goto-char point))
     (slime-fuzzy-highlight-current-completion)))
Index: swank.lisp
===================================================================
RCS file: /project/slime/cvsroot/slime/swank.lisp,v
retrieving revision 1.409
diff -u -r1.409 swank.lisp
--- swank.lisp	20 Oct 2006 00:14:07 -0000	1.409
+++ swank.lisp	20 Oct 2006 14:42:06 -0000
@@ -1128,7 +1128,18 @@
           (*print-readably* nil)
           (*print-pretty* nil)
           (*package* *swank-io-package*))
-      (prin1-to-string object))))
+      (with-output-to-string (*standard-output*)
+        (prin1-for-emacs object)))))
+
+(defun prin1-for-emacs (object)
+  (typecase object
+    (string (prin1 object))
+    (vector (write-char #\[)
+            (loop for el :across object do
+                  (prin1-for-emacs el)
+                  (write-char #\ ))
+            (write-char #\]))
+    (t (prin1 object))))
 
 (defun force-user-output ()
   (force-output (connection.user-io *emacs-connection*))
@@ -3321,7 +3332,7 @@
            
 ;;;; Fuzzy completion
 
-(defslimefun fuzzy-completions (string default-package-name &optional limit)
+(defslimefun fuzzy-completions (string default-package-name &key limit time-limit-in-msec)
   "Return an (optionally limited to LIMIT best results) list of
 fuzzy completions for a symbol designator STRING.  The list will
 be sorted by score, most likely match first.
@@ -3347,7 +3358,9 @@
   FOO      - Symbols accessible in the buffer package.
   PKG:FOO  - Symbols external in package PKG.
   PKG::FOO - Symbols accessible in package PKG."
-  (fuzzy-completion-set string default-package-name limit))
+  (coerce (fuzzy-completion-set string default-package-name
+                                :limit limit :time-limit-in-msec time-limit-in-msec)
+          'list))
 
 (defun convert-fuzzy-completion-result (result converter
                                         internal-p package-name)
@@ -3396,66 +3409,91 @@
                                      )))
                   collect flag)))))
 
-(defun fuzzy-completion-set (string default-package-name &optional limit)
+(defun fuzzy-completion-set (string default-package-name &key limit time-limit-in-msec)
   "Prepares list of completion obajects, sorted by SCORE, of fuzzy
 completions of STRING in DEFAULT-PACKAGE-NAME.  If LIMIT is set,
 only the top LIMIT results will be returned."
+  (declare (optimize (speed 3))
+           (type (or null (integer 0 #.(1- most-positive-fixnum))) limit time-limit-in-msec))
   (multiple-value-bind (name package-name package internal-p)
       (parse-completion-arguments string default-package-name)
     (let* ((symbols (and package
                          (fuzzy-find-matching-symbols name
                                                       package
                                                       (and (not internal-p)
-                                                           package-name))))
+                                                           package-name)
+                                                      :time-limit-in-msec time-limit-in-msec)))
            (packs (and (not package-name)
                        (fuzzy-find-matching-packages name)))
            (converter (output-case-converter name))
-           (results
-            (sort (mapcar #'(lambda (result)
-                              (convert-fuzzy-completion-result
-                               result converter internal-p package-name))
-                          (nconc symbols packs))
-                  #'> :key #'second)))
-      (when (and limit 
-                 (> limit 0) 
+           (results (concatenate 'vector symbols packs)))
+      (loop for idx :upfrom 0
+            while (< idx (length results))
+            for el = (aref results idx)
+            do (setf (aref results idx) (convert-fuzzy-completion-result
+                                         el converter internal-p package-name)))
+      (setf results (sort results #'> :key #'second))
+      (when (and limit
+                 (> limit 0)
                  (< limit (length results)))
-        (setf (cdr (nthcdr (1- limit) results)) nil))
+        (if (array-has-fill-pointer-p results)
+            (setf (fill-pointer results) limit)
+            (setf results (make-array limit :displaced-to results))))
       results)))
 
-(defun fuzzy-find-matching-symbols (string package external)
+(defun fuzzy-find-matching-symbols (string package external &key time-limit-in-msec)
   "Return a list of symbols in PACKAGE matching STRING using the
 fuzzy completion algorithm.  If EXTERNAL is true, only external
 symbols are returned."
-  (let ((completions '())
+  (let ((completions (make-array 256 :adjustable t :fill-pointer 0))
+        (time-limit (if time-limit-in-msec
+                        (ceiling (/ time-limit-in-msec 1000))
+                        0))
+        (utime-at-start (get-universal-time))
+        (count 0)
         (converter (output-case-converter string)))
+    (declare (type (integer 0 #.(1- most-positive-fixnum)) count time-limit)
+             (type function converter)
+             (optimize (speed 3)))
     (flet ((symbol-match (symbol)
              (and (or (not external)
                       (symbol-external-p symbol package))
                   (compute-highest-scoring-completion 
                    string (funcall converter (symbol-name symbol))))))
-      (do-symbols (symbol package)
-        (if (string= "" string)
-            (when (or (and external (symbol-external-p symbol package))
-                      (not external))
-              (push (list symbol 0.0 (list (list 0 ""))) completions))
-            (multiple-value-bind (result score) (symbol-match symbol)
-              (when result
-                (push (list symbol score result) completions))))))
-    (remove-duplicates completions :key #'first)))
+      (block loop
+        (do-symbols (symbol package)
+          (incf count)
+          (when (and (not (zerop time-limit))
+                     (mod count 256) ; ease up on calling get-universal-time like crazy
+                     (< time-limit-in-msec (- (get-universal-time) utime-at-start)))
+            (return-from loop))
+          (if (string= "" string)
+              (when (or (and external (symbol-external-p symbol package))
+                        (not external))
+                (vector-push-extend (list symbol 0.0 (list (list 0 ""))) completions))
+              (multiple-value-bind (result score) (symbol-match symbol)
+                (when result
+                  (vector-push-extend (list symbol score result) completions)))))))
+    (remove-duplicates completions :key #'first :test #'eq)))
 
 (defun fuzzy-find-matching-packages (name)
   "Return a list of package names matching NAME using the fuzzy
 completion algorithm."
-  (let ((converter (output-case-converter name)))
+  (let ((converter (output-case-converter name))
+        (completions (make-array 32 :adjustable t :fill-pointer 0)))
+    (declare (optimize (speed 3))
+             (type function converter))  
     (loop for package in (list-all-packages)
           for package-name = (concatenate 'string 
                                           (funcall converter
                                                    (package-name package)) 
                                           ":")
           for (result score) = (multiple-value-list
-                                (compute-highest-scoring-completion
-                                 name package-name))
-          if result collect (list package-name score result))))
+                                   (compute-highest-scoring-completion
+                                    name package-name))
+          when result do
+          (vector-push-extend (list package-name score result) completions))
+    completions))
 
 (defslimefun fuzzy-completion-selected (original-string completion)
   "This function is called by Slime when a fuzzy completion is
