* tests/syntax.test ("duplicate formals"): New category, move
[bpt/guile.git] / guile-readline / readline.scm
CommitLineData
b18c7b77
MV
1;;;; readline.scm --- support functions for command-line editing
2;;;;
ebfa2cd5 3;;;; Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
b18c7b77
MV
4;;;;
5;;;; This program is free software; you can redistribute it and/or modify
6;;;; it under the terms of the GNU General Public License as published by
7;;;; the Free Software Foundation; either version 2, or (at your option)
8;;;; any later version.
9;;;;
10;;;; This program is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;;;; GNU General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU General Public License
16;;;; along with this software; see the file COPYING. If not, write to
17;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18;;;; Boston, MA 02111-1307 USA
19;;;;
20;;;; Contributed by Daniel Risacher <risacher@worldnet.att.net>.
21;;;; Extensions based upon code by
22;;;; Andrew Archibald <aarchiba@undergrad.math.uwaterloo.ca>.
23
e9bab9df
DH
24\f
25
b18c7b77
MV
26(define-module (ice-9 readline)
27 :use-module (ice-9 session)
c8fac0c3
MD
28 :use-module (ice-9 regex)
29 :no-backtrace)
b18c7b77 30
e9bab9df
DH
31\f
32
acb0207f
MV
33;;; Dynamically link the glue code for accessing the readline library,
34;;; but only when it isn't already present.
b18c7b77 35
acb0207f
MV
36(if (not (feature? 'readline))
37 (dynamic-call "scm_init_readline" (dynamic-link "libguilereadline.so")))
b18c7b77 38
c8fac0c3
MD
39(if (not (feature? 'readline))
40 (scm-error 'misc-error
41 #f
42 "readline is not provided in this Guile installation"
43 '()
44 '()))
45
e9bab9df
DH
46\f
47
48;;; Run-time options
49
50(export
51 readline-options
52 readline-enable
53 readline-disable)
54(export-syntax
55 readline-set!)
56
57(define-option-interface
58 (readline-options-interface
59 (readline-options readline-enable readline-disable)
60 (readline-set!)))
61
62\f
63
b18c7b77
MV
64;;; MDJ 980513 <djurfeldt@nada.kth.se>:
65;;; There should probably be low-level support instead of this code.
66
e9bab9df
DH
67;;; Dirk:FIXME:: If the-readline-port, input-port or output-port are closed,
68;;; guile will enter an endless loop or crash.
69
b18c7b77
MV
70(define prompt "")
71(define prompt2 "")
72(define input-port (current-input-port))
73(define output-port (current-output-port))
74(define read-hook #f)
75
76(define (make-readline-port)
77 (let ((read-string "")
78 (string-index -1))
79 (letrec ((get-character
80 (lambda ()
81 (cond
82 ((eof-object? read-string)
83 read-string)
84 ((>= string-index (string-length read-string))
85 (begin
86 (set! string-index -1)
87 #\nl))
88 ((= string-index -1)
89 (begin
90 (set! read-string
91 (%readline (if (string? prompt)
92 prompt
93 (prompt))
94 input-port
95 output-port
96 read-hook))
97 (set! string-index 0)
98 (if (not (eof-object? read-string))
99 (begin
100 (or (string=? read-string "")
539fdb77 101 (add-history read-string))
b18c7b77
MV
102 (get-character))
103 read-string)))
104 (else
105 (let ((res (string-ref read-string string-index)))
106 (set! string-index (+ 1 string-index))
539fdb77
MV
107 (set! prompt prompt2)
108 res))))))
b18c7b77 109 (make-soft-port
6c29a390
NJ
110 (vector #f #f #f get-character #f)
111 "r"))))
b18c7b77
MV
112
113;;; We only create one readline port. There's no point in having
114;;; more, since they would all share the tty and history ---
115;;; everything except the prompt. And don't forget the
116;;; compile/load/run phase distinctions. Also, the readline library
117;;; isn't reentrant.
118(define the-readline-port #f)
119
120(define history-variable "GUILE_HISTORY")
121(define history-file (string-append (getenv "HOME") "/.guile_history"))
122
123(define-public readline-port
124 (let ((do (lambda (r/w)
125 (if (memq 'history-file (readline-options-interface))
126 (r/w (or (getenv history-variable)
127 history-file))))))
128 (lambda ()
129 (if (not the-readline-port)
130 (begin
131 (do read-history)
132 (set! the-readline-port (make-readline-port))
133 (add-hook! exit-hook (lambda () (do write-history)))))
134 the-readline-port)))
135
136;;; The user might try to use readline in his programs. It then
137;;; becomes very uncomfortable that the current-input-port is the
138;;; readline port...
139;;;
140;;; Here, we detect this situation and replace it with the
141;;; underlying port.
142;;;
143;;; %readline is the low-level readline procedure.
144
145(define-public (readline . args)
146 (let ((prompt prompt)
147 (inp input-port))
148 (cond ((not (null? args))
149 (set! prompt (car args))
150 (set! args (cdr args))
151 (cond ((not (null? args))
152 (set! inp (car args))
153 (set! args (cdr args))))))
154 (apply %readline
155 prompt
156 (if (eq? inp the-readline-port)
157 input-port
158 inp)
159 args)))
160
161(define-public (set-readline-prompt! p . rest)
162 (set! prompt p)
163 (if (not (null? rest))
164 (set! prompt2 (car rest))))
165
166(define-public (set-readline-input-port! p)
c4a9b7bb
DH
167 (cond ((or (not (file-port? p)) (not (input-port? p)))
168 (scm-error 'wrong-type-arg "set-readline-input-port!"
169 "Not a file input port: ~S" (list p) #f))
170 ((port-closed? p)
171 (scm-error 'misc-error "set-readline-input-port!"
172 "Port not open: ~S" (list p) #f))
173 (else
174 (set! input-port p))))
b18c7b77
MV
175
176(define-public (set-readline-output-port! p)
c4a9b7bb
DH
177 (cond ((or (not (file-port? p)) (not (output-port? p)))
178 (scm-error 'wrong-type-arg "set-readline-input-port!"
179 "Not a file output port: ~S" (list p) #f))
180 ((port-closed? p)
181 (scm-error 'misc-error "set-readline-output-port!"
182 "Port not open: ~S" (list p) #f))
183 (else
184 (set! output-port p))))
b18c7b77
MV
185
186(define-public (set-readline-read-hook! h)
187 (set! read-hook h))
188
ebfa2cd5
MD
189(if (feature? 'regex)
190 (begin
191 (define-public apropos-completion-function
192 (let ((completions '()))
193 (lambda (text cont?)
194 (if (not cont?)
195 (set! completions
196 (map symbol->string
197 (apropos-internal
198 (string-append "^" (regexp-quote text))))))
199 (if (null? completions)
200 #f
201 (let ((retval (car completions)))
202 (begin (set! completions (cdr completions))
203 retval))))))
204
205 (set! *readline-completion-function* apropos-completion-function)
206 ))
b18c7b77
MV
207
208(define-public (activate-readline)
209 (if (and (isatty? (current-input-port))
6b098fec
DH
210 (not (and (module-defined? the-root-module 'use-emacs-interface)
211 (module-ref the-root-module 'use-emacs-interface))))
b18c7b77
MV
212 (let ((read-hook (lambda () (run-hook before-read-hook))))
213 (set-current-input-port (readline-port))
214 (set! repl-reader
215 (lambda (prompt)
216 (dynamic-wind
217 (lambda ()
218 (set-readline-prompt! prompt "... ")
219 (set-readline-read-hook! read-hook))
220 (lambda () (read))
221 (lambda ()
222 (set-readline-prompt! "" "")
6373eb6f
MD
223 (set-readline-read-hook! #f)))))
224 (set! (using-readline?) #t))))