line editor now waits for complete sexps

This commit is contained in:
Alex Shinn 2011-03-28 23:04:45 +09:00
parent 3b14c5ae7b
commit 6cd9654701
3 changed files with 51 additions and 32 deletions

View file

@ -1,17 +1,8 @@
;;;; repl.scm - friendlier repl with line editing and signal handling ;;;; repl.scm - friendlier repl with line editing and signal handling
;; ;;
;; Copyright (c) 2010 Alex Shinn. All rights reserved. ;; Copyright (c) 2011 Alex Shinn. All rights reserved.
;; BSD-style license: http://synthcode.com/license.txt ;; BSD-style license: http://synthcode.com/license.txt
(define-syntax handle-exceptions
(syntax-rules ()
((handle-exceptions exn handle-expr expr)
(call-with-current-continuation
(lambda (return)
(with-exception-handler
(lambda (exn) (return handle-expr))
(lambda () expr)))))))
(define (with-signal-handler sig handler thunk) (define (with-signal-handler sig handler thunk)
(let ((old-handler #f)) (let ((old-handler #f))
(dynamic-wind (dynamic-wind
@ -19,32 +10,39 @@
thunk thunk
(lambda () (set-signal-action! sig old-handler))))) (lambda () (set-signal-action! sig old-handler)))))
(define (buffer-complete-sexp? buf)
(guard (exn (else #f))
(call-with-input-string (buffer->string buf) read)
#t))
(define (run-repl module env . o) (define (run-repl module env . o)
(let ((history (make-history))) (let ((history (make-history)))
(let lp ((module module) (env env)) (let lp ((module module) (env env))
(let ((line (let ((line
(edit-line (edit-line
(string-append (if module (symbol->string module) "") "> ") (string-append (if module (symbol->string module) "") "> ")
'history: history))) 'history: history
'complete?: buffer-complete-sexp?)))
(cond (cond
((or (not line) (eof-object? line))) ((or (not line) (eof-object? line)))
((equal? line "") (lp module env)) ((equal? line "") (lp module env))
(else (else
(history-commit! history line) (history-commit! history line)
(handle-exceptions (guard
exn (exn
(print-exception exn (current-error-port)) (else (print-exception exn (current-error-port))))
(let* ((expr (call-with-input-string line read/ss)) (let* ((expr (call-with-input-string line read/ss))
(thread (make-thread (thread
(lambda () (make-thread
(handle-exceptions (lambda ()
exn (guard
(print-exception exn (current-error-port)) (exn
(let ((res (eval expr env))) (else (print-exception exn (current-error-port))))
(cond (let ((res (eval expr env)))
((not (eq? res (if #f #f))) (cond
(write/ss res) ((not (eq? res (if #f #f)))
(newline))))))))) (write/ss res)
(newline)))))))))
(with-signal-handler (with-signal-handler
signal/interrupt signal/interrupt
(lambda (n) (lambda (n)

View file

@ -1,5 +1,6 @@
(define-module (chibi term edit-line) (define-module (chibi term edit-line)
(export edit-line edit-line-repl make-history history-insert! history-commit!) (export edit-line edit-line-repl make-history history-insert! history-commit!
buffer->string)
(import-immutable (scheme) (chibi stty) (srfi 9)) (import-immutable (scheme) (chibi stty) (srfi 9))
(include "edit-line.scm")) (include "edit-line.scm"))

View file

@ -1,6 +1,6 @@
;;;; edit-line.scm - pure scheme line editing tool ;;;; edit-line.scm - pure scheme line editor
;; ;;
;; Copyright (c) 2010 Alex Shinn. All rights reserved. ;; Copyright (c) 2011 Alex Shinn. All rights reserved.
;; BSD-style license: http://synthcode.com/license.txt ;; BSD-style license: http://synthcode.com/license.txt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -104,6 +104,13 @@
((< i start)) ((< i start))
(string-set! dst j (string-ref src i))))) (string-set! dst j (string-ref src i)))))
(define (string-index ch x)
(let ((len (string-length x)))
(let lp ((i 0))
(cond ((>= i len) #f)
((eqv? ch (string-ref x i)))
(else (lp (+ i 1)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; buffers ;; buffers
@ -120,7 +127,8 @@
(width buffer-width buffer-width-set!) (width buffer-width buffer-width-set!)
(string buffer-string buffer-string-set!) (string buffer-string buffer-string-set!)
(kill-ring buffer-kill-ring buffer-kill-ring-set!) (kill-ring buffer-kill-ring buffer-kill-ring-set!)
(history buffer-history buffer-history-set!)) (history buffer-history buffer-history-set!)
(complete? buffer-complete? buffer-complete?-set!))
(define default-buffer-size 256) (define default-buffer-size 256)
(define default-buffer-width 80) (define default-buffer-width 80)
@ -159,6 +167,7 @@
(define (buffer-update-position! buf) (define (buffer-update-position! buf)
(let ((pos (buffer-pos buf)) (let ((pos (buffer-pos buf))
(gap (buffer-gap buf)) (gap (buffer-gap buf))
(str (buffer-string buf))
(end (string-length (buffer-string buf))) (end (string-length (buffer-string buf)))
(width (buffer-width buf))) (width (buffer-width buf)))
(let lp ((i 0) (row 0) (col 0)) ;; update row/col (let lp ((i 0) (row 0) (col 0)) ;; update row/col
@ -169,6 +178,8 @@
((>= i end) ((>= i end)
(buffer-max-row-set! (buffer-max-row-set!
buf (if (and (zero? col) (> row 0)) (- row 1) row))) buf (if (and (zero? col) (> row 0)) (- row 1) row)))
((eqv? #\newline (string-ref str i))
(lp (+ i 1) (+ row 1) 0))
((= (+ col 1) width) ((= (+ col 1) width)
(lp (+ i 1) (+ row 1) 0)) (lp (+ i 1) (+ row 1) 0))
(else (else
@ -234,7 +245,10 @@
(cond (cond
((buffer-refresh? buf)) ((buffer-refresh? buf))
((and (= (buffer-gap buf) (string-length (buffer-string buf))) ((and (= (buffer-gap buf) (string-length (buffer-string buf)))
(< (+ (buffer-col buf) len) (buffer-width buf))) (< (+ (buffer-col buf) len) (buffer-width buf))
(if (char? x)
(not (eqv? x #\newline))
(not (string-index #\newline x))))
;; fast path - append to end of buffer w/o wrapping to next line ;; fast path - append to end of buffer w/o wrapping to next line
(display x out) (display x out)
(buffer-col-set! buf (+ (buffer-col buf) len))) (buffer-col-set! buf (+ (buffer-col buf) len)))
@ -344,9 +358,13 @@
(buffer-insert! buf out ch)) (buffer-insert! buf out ch))
(define (command/enter ch buf out return) (define (command/enter ch buf out return)
(command/end-of-line ch buf out return) (cond
(newline out) (((buffer-complete? buf) buf)
(return)) (command/end-of-line ch buf out return)
(newline out)
(return))
(else
(command/self-insert ch buf out return))))
(define (command/beep ch buf out return) (define (command/beep ch buf out return)
(write-char (integer->char 7) out)) (write-char (integer->char 7) out))
@ -442,6 +460,7 @@
(define (make-line-editor . args) (define (make-line-editor . args)
(let* ((prompt (get-key args 'prompt: "> ")) (let* ((prompt (get-key args 'prompt: "> "))
(history (get-key args 'history:)) (history (get-key args 'history:))
(complete? (get-key args 'complete?: (lambda (buf) #t)))
(terminal-width (get-key args 'terminal-width:)) (terminal-width (get-key args 'terminal-width:))
(keymap (get-key args 'keymap: standard-keymap))) (keymap (get-key args 'keymap: standard-keymap)))
(lambda (in out) (lambda (in out)
@ -454,6 +473,7 @@
(buffer-insert! buf out prompt) (buffer-insert! buf out prompt)
(buffer-min-set! buf (string-length prompt)) (buffer-min-set! buf (string-length prompt))
(buffer-history-set! buf history) (buffer-history-set! buf history)
(buffer-complete?-set! buf complete?)
(buffer-refresh buf out) (buffer-refresh buf out)
(flush-output out) (flush-output out)
((if (get-key args 'no-stty?:) (lambda (out f) (f)) with-raw-io) ((if (get-key args 'no-stty?:) (lambda (out f) (f)) with-raw-io)