[plt-scheme] readline completion [patch]

From: Dimitris Vyzovitis (vyzo at media.mit.edu)
Date: Sat Mar 24 03:41:30 EDT 2007

Custom readline completion is currently broken - it self loops on set!...
The attached patch fixes it, and while at it:
1) adds word break characters
2) provides a default completion that uses the current namespace to
 generate matching symbols (as opposed to the useless file completion default)

Btw, is there a reason why there isn't a default byte<->string conversion
in the core?
Something like:
bytes->string and string->bytes functions, current-bytes-conversion
parameter.
ffi conversions could benefit from this as well (default-_string-type ...)


-- vyzo
-------------- next part --------------
Index: collects/readline/mzrl.ss
===================================================================
--- collects/readline/mzrl.ss	(revision 5816)
+++ collects/readline/mzrl.ss	(working copy)
@@ -1,9 +1,12 @@
 (module mzrl mzscheme
 
 (require (lib "foreign.ss")) (unsafe!)
+(require (only (lib "string.ss" "srfi" "13") string-prefix?)
+         (only (lib "list.ss" "srfi" "1") filter-map))
 (provide readline readline-bytes
          add-history add-history-bytes
-         set-completion-function!)
+         set-completion-function!
+         default-completion default-word-break)
 
 ;; libtermcap maybe needed
 (define libtermcap  (with-handlers ([exn:fail? void]) (ffi-lib "libtermcap")))
@@ -43,26 +46,44 @@
   (get-ffi-obj "add_history" libreadline (_fun _bytes -> _void)))
 
 ;; Simple completion: use this with a (string -> list-of string) function that
-;; returns the completions for a given string.  (should clean up bytes/string)
+;; returns the completions for a given string.
 (define set-completion-function!
   (case-lambda
-    [(func) (set-completion-function! _string)]
-    [(func type)
+    [(func) (set-completion-function! func default-word-break)]
+    [(func wbreak)
      (if func
-       (set-ffi-obj! "rl_completion_entry_function" libreadline
-                     (_fun type _int -> _pointer)
-                     (completion-function func))
+       (begin
+         (set-ffi-obj! "rl_completion_entry_function" libreadline
+                       (_fun _bytes _int -> _pointer)
+                       (completion-function func))
+         (set-ffi-obj! "rl_basic_word_break_characters" libreadline
+                       _bytes (string->bytes/utf-8 wbreak)))
        (set-ffi-obj! "rl_completion_entry_function" libreadline _pointer #f))]))
+
+(define (string->raw str)
+  (let ((bs (string->bytes/utf-8 str)))
+    (malloc (add1 (bytes-length bs)) bs 'raw)))
+
 (define (completion-function func)
   (let ([cur '()])
     (define (complete str state)
       (if (zero? state)
-        (begin (set! cur (func str)) (complete str 1))
+        (begin (set! cur (func (bytes->string/utf-8 str))) (complete #f 1))
         (and (pair? cur)
-             (begin0 (malloc (add1 (bytes-length (car cur))) (car cur) 'raw)
+             (begin0 (string->raw (car cur)) 
                (set! cur (cdr cur))))))
     complete))
 
+(define default-word-break " \t\n\"([{'`,")
+
+(define (default-completion text)
+  (filter-map (lambda (sym) 
+                (let ((str (symbol->string sym)))
+                  (and (string-prefix? text str) str)))
+              (namespace-mapped-symbols)))
+
+(set-completion-function! default-completion default-word-break)
+
 (set-ffi-obj! "rl_readline_name" libreadline _bytes #"mzscheme")
 
 ;; need to capture the real input port below

Posted on the users mailing list.