;;;; readline.scm --- support functions for command-line editing
;;;;
-;;;; Copyright (C) 1997, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
+;;;; Copyright (C) 1997, 1999, 2000, 2001, 2002, 2006, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
;;;;
;;;; This program is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
-;;;; the Free Software Foundation; either version 2, or (at your option)
+;;;; the Free Software Foundation; either version 3, or (at your option)
;;;; any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
\f
(define-module (ice-9 readline)
- :use-module (ice-9 session)
- :use-module (ice-9 regex)
- :use-module (ice-9 buffered-input)
- :no-backtrace
- :export (filename-completion-function))
+ #:use-module (ice-9 session)
+ #:use-module (ice-9 regex)
+ #:use-module (ice-9 buffered-input)
+ #:no-backtrace
+ #:export (filename-completion-function
+ add-history
+ read-history
+ write-history
+ clear-history))
\f
;;; but only when it isn't already present.
(if (not (provided? 'readline))
- (load-extension "libguilereadline-v-18" "scm_init_readline"))
+ (load-extension "guile-readline" "scm_init_readline"))
(if (not (provided? 'readline))
(scm-error 'misc-error
;;; Dirk:FIXME:: If the-readline-port, input-port or output-port are closed,
;;; guile will enter an endless loop or crash.
-(define new-input-prompt "")
-(define continuation-prompt "")
-(define input-port (current-input-port))
-(define output-port (current-output-port))
-(define read-hook #f)
+(define-once new-input-prompt "")
+(define-once continuation-prompt "")
+(define-once input-port (current-input-port))
+(define-once output-port (current-output-port))
+(define-once read-hook #f)
(define (make-readline-port)
- (make-line-buffered-input-port (lambda (continuation?)
- (let* ((prompt (if continuation?
- continuation-prompt
- new-input-prompt))
- (str (%readline (if (string? prompt)
- prompt
- (prompt))
- input-port
- output-port
- read-hook)))
- (or (eof-object? str)
- (string=? str "")
- (add-history str))
- str))))
+ (let ((history-buffer #f))
+ (make-line-buffered-input-port (lambda (continuation?)
+ ;; When starting a new read, add
+ ;; the previously read expression
+ ;; to the history.
+ (if (and (not continuation?)
+ history-buffer)
+ (begin
+ (add-history history-buffer)
+ (set! history-buffer #f)))
+ ;; Set up prompts and read a line.
+ (let* ((prompt (if continuation?
+ continuation-prompt
+ new-input-prompt))
+ (str (%readline (if (string? prompt)
+ prompt
+ (prompt))
+ input-port
+ output-port
+ read-hook)))
+ (or (eof-object? str)
+ (string=? str "")
+ (set! history-buffer
+ (if history-buffer
+ (string-append history-buffer
+ " "
+ str)
+ str)))
+ str)))))
;;; We only create one readline port. There's no point in having
;;; more, since they would all share the tty and history ---
;;; everything except the prompt. And don't forget the
;;; compile/load/run phase distinctions. Also, the readline library
;;; isn't reentrant.
-(define the-readline-port #f)
+(define-once the-readline-port #f)
-(define history-variable "GUILE_HISTORY")
-(define history-file (string-append (getenv "HOME") "/.guile_history"))
+(define-once history-variable "GUILE_HISTORY")
+(define-once history-file (string-append (getenv "HOME") "/.guile_history"))
(define-public readline-port
(let ((do (lambda (r/w)
(define-public (set-readline-read-hook! h)
(set! read-hook h))
+(define-public apropos-completion-function
+ (let ((completions '()))
+ (lambda (text cont?)
+ (if (not cont?)
+ (set! completions
+ (map symbol->string
+ (apropos-internal
+ (string-append "^" (regexp-quote text))))))
+ (if (null? completions)
+ #f
+ (let ((retval (car completions)))
+ (begin (set! completions (cdr completions))
+ retval))))))
+
(if (provided? 'regex)
- (begin
- (define-public apropos-completion-function
- (let ((completions '()))
- (lambda (text cont?)
- (if (not cont?)
- (set! completions
- (map symbol->string
- (apropos-internal
- (string-append "^" (regexp-quote text))))))
- (if (null? completions)
- #f
- (let ((retval (car completions)))
- (begin (set! completions (cdr completions))
- retval))))))
-
- (set! *readline-completion-function* apropos-completion-function)
- ))
+ (set! *readline-completion-function* apropos-completion-function))
(define-public (with-readline-completion-function completer thunk)
"With @var{completer} as readline completion function, call @var{thunk}."
(lambda ()
(set! *readline-completion-function* old-completer)))))
+(define-once readline-repl-reader
+ (let ((boot-9-repl-reader repl-reader))
+ (lambda* (repl-prompt #:optional (reader (fluid-ref current-reader)))
+ (let ((port (current-input-port)))
+ (if (eq? port (readline-port))
+ (let ((outer-new-input-prompt new-input-prompt)
+ (outer-continuation-prompt continuation-prompt)
+ (outer-read-hook read-hook))
+ (dynamic-wind
+ (lambda ()
+ (set-buffered-input-continuation?! port #f)
+ (set-readline-prompt! repl-prompt "... ")
+ (set-readline-read-hook! (lambda ()
+ (run-hook before-read-hook))))
+ (lambda () ((or reader read) port))
+ (lambda ()
+ (set-readline-prompt! outer-new-input-prompt
+ outer-continuation-prompt)
+ (set-readline-read-hook! outer-read-hook))))
+ (boot-9-repl-reader repl-prompt reader))))))
+
(define-public (activate-readline)
- (if (and (isatty? (current-input-port))
- (not (let ((guile-user-module (resolve-module '(guile-user))))
- (and (module-defined? guile-user-module 'use-emacs-interface)
- (module-ref guile-user-module 'use-emacs-interface)))))
- (let ((repl-read-hook (lambda () (run-hook before-read-hook))))
- (set-current-input-port (readline-port))
- (set! repl-reader
- (lambda (repl-prompt)
- (let ((outer-new-input-prompt new-input-prompt)
- (outer-continuation-prompt continuation-prompt)
- (outer-read-hook read-hook))
- (dynamic-wind
- (lambda ()
- (set-buffered-input-continuation?! (readline-port) #f)
- (set-readline-prompt! repl-prompt "... ")
- (set-readline-read-hook! repl-read-hook))
- (lambda () ((or (fluid-ref current-reader) read)))
- (lambda ()
- (set-readline-prompt! outer-new-input-prompt outer-continuation-prompt)
- (set-readline-read-hook! outer-read-hook))))))
- (set! (using-readline?) #t))))
+ (if (isatty? (current-input-port))
+ (begin
+ (set-current-input-port (readline-port))
+ (set! repl-reader readline-repl-reader)
+ (set! (using-readline?) #t))))
(define-public (make-completion-function strings)
"Construct and return a completion function for a list of strings.