temporarily disable elisp exception tests
[bpt/guile.git] / guile-readline / ice-9 / readline.scm
CommitLineData
74c88f53
RB
1;;;; readline.scm --- support functions for command-line editing
2;;;;
475772ea
MW
3;;;; Copyright (C) 1997, 1999, 2000, 2001, 2002, 2006, 2009, 2010, 2011,
4;;;; 2013, 2014 Free Software Foundation, Inc.
74c88f53
RB
5;;;;
6;;;; This program is free software; you can redistribute it and/or modify
7;;;; it under the terms of the GNU General Public License as published by
b82a8b48 8;;;; the Free Software Foundation; either version 3, or (at your option)
74c88f53
RB
9;;;; any later version.
10;;;;
11;;;; This program is distributed in the hope that it will be useful,
12;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;;; GNU General Public License for more details.
15;;;;
16;;;; You should have received a copy of the GNU General Public License
17;;;; along with this software; see the file COPYING. If not, write to
92205699
MV
18;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19;;;; Boston, MA 02110-1301 USA
74c88f53
RB
20;;;;
21;;;; Contributed by Daniel Risacher <risacher@worldnet.att.net>.
22;;;; Extensions based upon code by
23;;;; Andrew Archibald <aarchiba@undergrad.math.uwaterloo.ca>.
24
25\f
26
27(define-module (ice-9 readline)
f84c500d
NJ
28 #:use-module (ice-9 session)
29 #:use-module (ice-9 regex)
30 #:use-module (ice-9 buffered-input)
31 #:no-backtrace
32 #:export (filename-completion-function
33 add-history
34 read-history
35 write-history
36 clear-history))
74c88f53
RB
37
38\f
39
40;;; Dynamically link the glue code for accessing the readline library,
41;;; but only when it isn't already present.
42
43(if (not (provided? 'readline))
545d776e 44 (load-extension "guile-readline" "scm_init_readline"))
74c88f53
RB
45
46(if (not (provided? 'readline))
47 (scm-error 'misc-error
48 #f
49 "readline is not provided in this Guile installation"
50 '()
51 '()))
52
53\f
54
55;;; Run-time options
56
57(export
58 readline-options
59 readline-enable
60 readline-disable)
61(export-syntax
62 readline-set!)
63
64(define-option-interface
65 (readline-options-interface
66 (readline-options readline-enable readline-disable)
67 (readline-set!)))
68
69\f
70
71;;; MDJ 980513 <djurfeldt@nada.kth.se>:
72;;; There should probably be low-level support instead of this code.
73
74;;; Dirk:FIXME:: If the-readline-port, input-port or output-port are closed,
75;;; guile will enter an endless loop or crash.
76
15b06ca9
AW
77(define-once new-input-prompt "")
78(define-once continuation-prompt "")
79(define-once input-port (current-input-port))
80(define-once output-port (current-output-port))
81(define-once read-hook #f)
74c88f53
RB
82
83(define (make-readline-port)
8b755a75
NJ
84 (let ((history-buffer #f))
85 (make-line-buffered-input-port (lambda (continuation?)
86 ;; When starting a new read, add
87 ;; the previously read expression
88 ;; to the history.
89 (if (and (not continuation?)
90 history-buffer)
91 (begin
92 (add-history history-buffer)
93 (set! history-buffer #f)))
94 ;; Set up prompts and read a line.
95 (let* ((prompt (if continuation?
96 continuation-prompt
97 new-input-prompt))
98 (str (%readline (if (string? prompt)
99 prompt
100 (prompt))
101 input-port
102 output-port
103 read-hook)))
104 (or (eof-object? str)
105 (string=? str "")
106 (set! history-buffer
107 (if history-buffer
108 (string-append history-buffer
b27ad2f3 109 "\n"
8b755a75
NJ
110 str)
111 str)))
112 str)))))
74c88f53
RB
113
114;;; We only create one readline port. There's no point in having
115;;; more, since they would all share the tty and history ---
116;;; everything except the prompt. And don't forget the
117;;; compile/load/run phase distinctions. Also, the readline library
118;;; isn't reentrant.
15b06ca9 119(define-once the-readline-port #f)
74c88f53 120
15b06ca9 121(define-once history-variable "GUILE_HISTORY")
3a3316e2
DM
122(define-once history-file
123 (string-append (or (getenv "HOME") ".") "/.guile_history"))
74c88f53
RB
124
125(define-public readline-port
126 (let ((do (lambda (r/w)
127 (if (memq 'history-file (readline-options-interface))
128 (r/w (or (getenv history-variable)
129 history-file))))))
130 (lambda ()
131 (if (not the-readline-port)
132 (begin
133 (do read-history)
134 (set! the-readline-port (make-readline-port))
135 (add-hook! exit-hook (lambda ()
136 (do write-history)
137 (clear-history)))))
138 the-readline-port)))
139
140;;; The user might try to use readline in his programs. It then
141;;; becomes very uncomfortable that the current-input-port is the
142;;; readline port...
143;;;
144;;; Here, we detect this situation and replace it with the
145;;; underlying port.
146;;;
147;;; %readline is the low-level readline procedure.
148
149(define-public (readline . args)
3bff1789 150 (let ((prompt new-input-prompt)
74c88f53
RB
151 (inp input-port))
152 (cond ((not (null? args))
153 (set! prompt (car args))
154 (set! args (cdr args))
155 (cond ((not (null? args))
156 (set! inp (car args))
157 (set! args (cdr args))))))
158 (apply %readline
159 prompt
160 (if (eq? inp the-readline-port)
161 input-port
162 inp)
163 args)))
164
165(define-public (set-readline-prompt! p . rest)
3bff1789 166 (set! new-input-prompt p)
74c88f53 167 (if (not (null? rest))
3bff1789 168 (set! continuation-prompt (car rest))))
74c88f53
RB
169
170(define-public (set-readline-input-port! p)
171 (cond ((or (not (file-port? p)) (not (input-port? p)))
172 (scm-error 'wrong-type-arg "set-readline-input-port!"
173 "Not a file input port: ~S" (list p) #f))
174 ((port-closed? p)
175 (scm-error 'misc-error "set-readline-input-port!"
176 "Port not open: ~S" (list p) #f))
177 (else
178 (set! input-port p))))
179
180(define-public (set-readline-output-port! p)
181 (cond ((or (not (file-port? p)) (not (output-port? p)))
182 (scm-error 'wrong-type-arg "set-readline-input-port!"
183 "Not a file output port: ~S" (list p) #f))
184 ((port-closed? p)
185 (scm-error 'misc-error "set-readline-output-port!"
186 "Port not open: ~S" (list p) #f))
187 (else
188 (set! output-port p))))
189
190(define-public (set-readline-read-hook! h)
191 (set! read-hook h))
192
64e5d08d
AW
193(define-public apropos-completion-function
194 (let ((completions '()))
195 (lambda (text cont?)
196 (if (not cont?)
197 (set! completions
198 (map symbol->string
199 (apropos-internal
200 (string-append "^" (regexp-quote text))))))
201 (if (null? completions)
202 #f
203 (let ((retval (car completions)))
204 (begin (set! completions (cdr completions))
205 retval))))))
206
74c88f53 207(if (provided? 'regex)
64e5d08d 208 (set! *readline-completion-function* apropos-completion-function))
74c88f53
RB
209
210(define-public (with-readline-completion-function completer thunk)
211 "With @var{completer} as readline completion function, call @var{thunk}."
212 (let ((old-completer *readline-completion-function*))
213 (dynamic-wind
214 (lambda ()
215 (set! *readline-completion-function* completer))
216 thunk
217 (lambda ()
218 (set! *readline-completion-function* old-completer)))))
219
15b06ca9 220(define-once readline-repl-reader
1924145d
AW
221 (let ((boot-9-repl-reader repl-reader))
222 (lambda* (repl-prompt #:optional (reader (fluid-ref current-reader)))
223 (let ((port (current-input-port)))
224 (if (eq? port (readline-port))
225 (let ((outer-new-input-prompt new-input-prompt)
226 (outer-continuation-prompt continuation-prompt)
227 (outer-read-hook read-hook))
228 (dynamic-wind
229 (lambda ()
230 (set-buffered-input-continuation?! port #f)
231 (set-readline-prompt! repl-prompt "... ")
232 (set-readline-read-hook! (lambda ()
233 (run-hook before-read-hook))))
234 (lambda () ((or reader read) port))
235 (lambda ()
236 (set-readline-prompt! outer-new-input-prompt
237 outer-continuation-prompt)
238 (set-readline-read-hook! outer-read-hook))))
239 (boot-9-repl-reader repl-prompt reader))))))
240
74c88f53 241(define-public (activate-readline)
adb825b6 242 (if (isatty? (current-input-port))
1924145d
AW
243 (begin
244 (set-current-input-port (readline-port))
245 (set! repl-reader readline-repl-reader)
246 (set! (using-readline?) #t))))
1b09b607
KR
247
248(define-public (make-completion-function strings)
249 "Construct and return a completion function for a list of strings.
250The returned function is suitable for passing to
251@code{with-readline-completion-function. The argument @var{strings}
252should be a list of strings, where each string is one of the possible
253completions."
254 (letrec ((strs '())
255 (regexp #f)
256 (completer (lambda (text continue?)
257 (if continue?
258 (if (null? strs)
259 #f
260 (let ((str (car strs)))
261 (set! strs (cdr strs))
262 (if (string-match regexp str)
263 str
264 (completer text #t))))
265 (begin
266 (set! strs strings)
267 (set! regexp
268 (string-append "^" (regexp-quote text)))
269 (completer text #t))))))
270 completer))