* Reformattings

* Avoid keeping empty history lines
* Avoid keeping repetitive history lines
* Provided (and documented) set-completion-function!
* Change sample use to a conditional `dynamic-require'
* Use raw mallocs instead of eternal for completions

svn: r4434
This commit is contained in:
Eli Barzilay 2006-09-25 23:30:53 +00:00
parent b8586b743d
commit 33f93c0d2e
5 changed files with 79 additions and 74 deletions

View File

@ -10,10 +10,11 @@ Normal use of readline
The _rep.ss_ library installs a readline-based function for the
prompt-and-read part of MzScheme's read-eval-print loop.
I put the following in my ~/.mzschemerc so that MzScheme always starts
with readline support:
You can put the following in your ~/.mzschemerc so that MzScheme starts with
readline support on xterms:
(require (lib "rep.ss" "readline"))
(when (equal? "xterm" (getenv "TERM"))
(dynamic-require '(lib "rep.ss" "readline") #f))
The readline history is stored across invocations in MzScheme's
preferences file, assuming MzScheme exits normally.
@ -24,8 +25,14 @@ Direct bindings for readline hackers
The _readline.ss_ library provides two functions:
> (readline prompt-string) - prints the given prompt string and reads
an S-expression.
> (readline prompt-string)
prints the given prompt string and reads a line
> (add-history s) - adds the given string to the readline history,
which is accessible to the user via the up-arrow key
> (add-history s)
adds the given string to the readline history, which is accessible
to the user via the up-arrow key
> (set-completion-function! proc)
sets readline's `rl_completion_entry_function' function according to
proc, which is expected to be a `string -> (list-of string)'
procedure

View File

@ -3,9 +3,8 @@
(require (lib "foreign.ss")) (unsafe!)
(provide readline add-history set-completion-function!)
; libtermcap maybe needed
(define libtermcap (with-handlers ([exn:fail? void])
(ffi-lib "libtermcap")))
;; libtermcap maybe needed
(define libtermcap (with-handlers ([exn:fail? void]) (ffi-lib "libtermcap")))
(define libreadline (ffi-lib "libreadline"))
(define readline
@ -28,8 +27,7 @@
(if (zero? state)
(begin (set! cur (func str)) (complete str 1))
(and (pair? cur)
(begin0 (malloc (add1 (bytes-length (car cur)))
(car cur) 'eternal)
(begin0 (malloc (add1 (bytes-length (car cur))) (car cur) 'raw)
(set! cur (cdr cur))))))
complete))

View File

@ -1,69 +1,73 @@
(module pread mzscheme
(require "readline.ss"
(lib "file.ss"))
(lib "file.ss"))
(define MAX-HISTORY 100)
(define leftovers null)
(define KEEP-DUPLICATES #f)
(define KEEP-BLANKS #f)
(define leftovers null)
(define counter 1)
(define local-history (get-preference 'mzrl-history (lambda () null)))
(define (do-readline p)
(let ([s (readline p)])
(when (string? s)
(add-history s)
(if (= (length local-history) MAX-HISTORY)
(set! local-history (cdr local-history)))
(set! local-history (append local-history (list s))))
s))
(define local-history
(let ([hist (get-preference 'mzrl-history (lambda () null))])
(for-each add-history hist)
(reverse hist)))
(define (save-history)
(put-preferences '(mzrl-history) (list local-history)))
(put-preferences '(mzrl-history) (list (reverse local-history))))
(define (readline/hist p)
(let ([s (readline p)])
(when (and (string? s)
(or KEEP-BLANKS (not (zero? (string-length s))))
(or KEEP-DUPLICATES
(null? local-history)
(not (equal? s (car local-history)))))
(add-history s)
(set! local-history (cons s local-history))
(let loop ([n MAX-HISTORY] [l local-history])
(cond [(null? l) 'done]
[(zero? n) (set-cdr! l '())]
[else (loop (sub1 n) (cdr l))])))
s))
(exit-handler (let ([old (exit-handler)])
(lambda (v)
(save-history)
(old v))))
(for-each add-history (if (list? local-history) local-history null))
(lambda (v)
(save-history)
(old v))))
(define (prompt-read-using-readline get-prompt)
(if (pair? leftovers)
(begin0
(car leftovers)
(set! leftovers (cdr leftovers)))
(let big-loop ()
(let loop ([s (do-readline (get-prompt 0))][next-pos 1][force? #f])
(if (eof-object? s)
(begin
(save-history)
s)
(with-handlers ([(if force? (lambda (x) #f) exn:fail:read:eof?)
(lambda (exn)
(let ([v (do-readline (get-prompt next-pos))])
(loop (string-append
s
"\n"
(if (eof-object? v)
""
v))
(add1 next-pos)
(eof-object? v))))])
(let ([p (open-input-string (string-append s "\n"))])
(port-count-lines! p)
(let ([rs (let loop ()
(let ([r (parameterize ([read-accept-reader #t])
(read-syntax (string->path (format "repl-~a" counter)) p))])
(if (eof-object? r)
null
(cons r (loop)))))])
(if (null? rs)
(big-loop)
(begin0
(car rs)
(set! counter (add1 counter))
(set! leftovers (cdr rs))))))))))))
(begin0 (car leftovers)
(set! leftovers (cdr leftovers)))
(let big-loop ()
(let loop ([s (readline/hist (get-prompt 0))] [next-pos 1] [force? #f])
(if (eof-object? s)
(begin (save-history) s)
(with-handlers ([(if force? (lambda (x) #f) exn:fail:read:eof?)
(lambda (exn)
(let ([v (readline/hist (get-prompt next-pos))])
(loop (string-append s "\n"
(if (eof-object? v) "" v))
(add1 next-pos)
(eof-object? v))))])
(let ([p (open-input-string (string-append s "\n"))])
(port-count-lines! p)
(let ([rs (let loop ()
(let ([r (parameterize ([read-accept-reader #t])
(read-syntax
(string->path
(format "repl-~a" counter))
p))])
(if (eof-object? r)
null
(cons r (loop)))))])
(if (null? rs)
(big-loop)
(begin0 (car rs)
(set! counter (add1 counter))
(set! leftovers (cdr rs))))))))))))
(provide prompt-read-using-readline))

View File

@ -1,6 +1,4 @@
(module readline mzscheme
(require "mzrl.ss") ;; should load .so form
(provide readline add-history))
(require "mzrl.ss")
(provide readline add-history set-completion-function!))

View File

@ -2,12 +2,10 @@
(module rep mzscheme
(require "pread.ss")
(current-prompt-read
(let ([orig-read (current-prompt-read)]
(current-prompt-read
(let ([orig-read (current-prompt-read)]
[orig-input (current-input-port)])
(lambda ()
(if (eq? (current-input-port) orig-input)
(prompt-read-using-readline (lambda (n) (if (zero? n) "> " " ")))
(orig-read))))))
(prompt-read-using-readline (lambda (n) (if (zero? n) "> " " ")))
(orig-read))))))