Hello,

Here is update, I just did a little code refactoring.
diff --git a/input.lisp b/input.lisp
index 9b3dcd9..34808a8 100644
--- a/input.lisp
+++ b/input.lisp
@@ -26,6 +26,7 @@
 
 (export '(*input-history-ignore-duplicates*
           *input-map*
+	  *input-completion-type*
 	  completing-read
 	  input-delete-region
 	  input-goto-char
@@ -377,19 +378,82 @@ functions are passed this structure as their first argument."
 
 ;;; "interactive" input functions
 
-(defun input-find-completions (str completions)
-  (if (or (functionp completions)
-          (and (symbolp completions)
-               (fboundp completions)))
-      (funcall completions str)
-      (remove-if-not (lambda (elt)
+(defun fuzzy-match (short full)
+  (declare (optimize (speed 3) (safety 0) (space 0))
+	   (simple-string short full))
+  (labels ((word-separator-p (c)
+	     (or (eq c #\-) (eq c #\Space)))
+	   (%distance (short s0 s full f0 f)
+	     (let ((d 0) (gap f0) (i s0))
+	       (declare (fixnum s0 s f0 f d gap i))
+	       (loop for j from f0 to f
+		     for cf = (aref full j)
+		     for cs = (aref short i) do
+		    (if (eq cf cs)
+			(setf d (+ d (- j gap))
+			      gap (1+ j)
+			      i (1+ i))
+			(incf d))
+		    (when (eq i s)
+		      (return-from %distance (+ d (- f j 1)))))
+	       d))
+	   (distance (short full)
+	     (let ((chunks NIL) (s0 0) (s 0) (f0 0) (f 0))
+	       (declare (fixnum s0 s f0 f)
+			(dynamic-extent chunks))
+	       (loop for i from 0 to (1- (length full))
+		     for c = (aref full i) do
+		    (if (word-separator-p c)
+			(progn 
+			  (push (list s0 s f0 f) chunks)
+			  (when (and (< s (length short))
+				     (word-separator-p (aref short s)))
+			    (incf s))
+			  (setf s0 s f0 (1+ i) f (1+ i)))
+			(progn 
+			  (when (and (< s (length short))
+				     (eq c (aref short s)))
+			    (incf s))
+			  (incf f))))
+	       (push (list s0 s f0 f) chunks)
+	       (when (eq s (length short))
+		 (loop for (s0 s f0 f) in chunks
+		       for factor from (length chunks) downto 1
+		       sum (* factor (%distance short s0 s full f0 f)))))))
+    (let ((d (distance short full)))
+      (when d (cons full d)))))
+
+(defun input-find-completions/fuzzy (str completions)
+  (let* ((str (string-downcase str))
+	 (completions (mapcar 'string-downcase completions))
+	 (matches (remove-if-not
+		   'identity
+		   (loop for candidate in completions 
+		         collect (fuzzy-match str candidate)))))
+    (mapcar 'car (sort matches '< :key 'cdr))))
+
+(defun input-find-completions/prefix (str completions)
+  (remove-if-not (lambda (elt)
                        (when (listp elt)
                          (setf elt (car elt)))
                        (and (<= (length str) (length elt))
                             (string= str elt
                                      :end1 (length str)
                                      :end2 (length str))))
-                     completions)))
+		 completions))
+
+(defvar *input-completion-type* :prefix)
+
+(defun input-find-completions (str completions)
+  (if (or (functionp completions)
+          (and (symbolp completions)
+               (fboundp completions)))
+      (funcall completions str)
+      (let* ((method-name (format nil "input-find-completions/~A" *input-completion-type*))
+	     (method (find-symbol (string-upcase method-name) :stumpwm)))
+	(if method 
+	    (funcall method str completions)
+	    (message "Invalid *input-completion-type* (:~A)" *input-completion-type*)))))
 
 (defun input-complete (input direction)
   ;; reset the completion list if this is the first time they're
_______________________________________________
Stumpwm-devel mailing list
Stumpwm-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/stumpwm-devel

Reply via email to