readline.scm 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. ;;;; readline.scm --- support functions for command-line editing
  2. ;;;;
  3. ;;;; Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
  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. (define-module (ice-9 readline)
  24. :use-module (ice-9 session)
  25. :use-module (ice-9 regex)
  26. :no-backtrace)
  27. ;;; Dynamically link the glue code for accessing the readline library,
  28. ;;; but only when it isn't already present.
  29. (if (not (feature? 'readline))
  30. (dynamic-call "scm_init_readline" (dynamic-link "libguilereadline.so")))
  31. (if (not (feature? 'readline))
  32. (scm-error 'misc-error
  33. #f
  34. "readline is not provided in this Guile installation"
  35. '()
  36. '()))
  37. ;;; MDJ 980513 <djurfeldt@nada.kth.se>:
  38. ;;; There should probably be low-level support instead of this code.
  39. (define prompt "")
  40. (define prompt2 "")
  41. (define input-port (current-input-port))
  42. (define output-port (current-output-port))
  43. (define read-hook #f)
  44. (define (make-readline-port)
  45. (let ((read-string "")
  46. (string-index -1))
  47. (letrec ((get-character
  48. (lambda ()
  49. (cond
  50. ((eof-object? read-string)
  51. read-string)
  52. ((>= string-index (string-length read-string))
  53. (begin
  54. (set! string-index -1)
  55. #\nl))
  56. ((= string-index -1)
  57. (begin
  58. (set! read-string
  59. (%readline (if (string? prompt)
  60. prompt
  61. (prompt))
  62. input-port
  63. output-port
  64. read-hook))
  65. (set! string-index 0)
  66. (if (not (eof-object? read-string))
  67. (begin
  68. (or (string=? read-string "")
  69. (begin
  70. (add-history read-string)
  71. (set! prompt prompt2)))
  72. (get-character))
  73. read-string)))
  74. (else
  75. (let ((res (string-ref read-string string-index)))
  76. (set! string-index (+ 1 string-index))
  77. res))))))
  78. (make-soft-port
  79. (vector write-char display #f get-character #f)
  80. "rw"))))
  81. ;;; We only create one readline port. There's no point in having
  82. ;;; more, since they would all share the tty and history ---
  83. ;;; everything except the prompt. And don't forget the
  84. ;;; compile/load/run phase distinctions. Also, the readline library
  85. ;;; isn't reentrant.
  86. (define the-readline-port #f)
  87. (define history-variable "GUILE_HISTORY")
  88. (define history-file (string-append (getenv "HOME") "/.guile_history"))
  89. (define-public readline-port
  90. (let ((do (lambda (r/w)
  91. (if (memq 'history-file (readline-options-interface))
  92. (r/w (or (getenv history-variable)
  93. history-file))))))
  94. (lambda ()
  95. (if (not the-readline-port)
  96. (begin
  97. (do read-history)
  98. (set! the-readline-port (make-readline-port))
  99. (add-hook! exit-hook (lambda () (do write-history)))))
  100. the-readline-port)))
  101. ;;; The user might try to use readline in his programs. It then
  102. ;;; becomes very uncomfortable that the current-input-port is the
  103. ;;; readline port...
  104. ;;;
  105. ;;; Here, we detect this situation and replace it with the
  106. ;;; underlying port.
  107. ;;;
  108. ;;; %readline is the low-level readline procedure.
  109. (define-public (readline . args)
  110. (let ((prompt prompt)
  111. (inp input-port))
  112. (cond ((not (null? args))
  113. (set! prompt (car args))
  114. (set! args (cdr args))
  115. (cond ((not (null? args))
  116. (set! inp (car args))
  117. (set! args (cdr args))))))
  118. (apply %readline
  119. prompt
  120. (if (eq? inp the-readline-port)
  121. input-port
  122. inp)
  123. args)))
  124. (define-public (set-readline-prompt! p . rest)
  125. (set! prompt p)
  126. (if (not (null? rest))
  127. (set! prompt2 (car rest))))
  128. (define-public (set-readline-input-port! p)
  129. (set! input-port p))
  130. (define-public (set-readline-output-port! p)
  131. (set! output-port p))
  132. (define-public (set-readline-read-hook! h)
  133. (set! read-hook h))
  134. (if (feature? 'regex)
  135. (begin
  136. (define-public apropos-completion-function
  137. (let ((completions '()))
  138. (lambda (text cont?)
  139. (if (not cont?)
  140. (set! completions
  141. (map symbol->string
  142. (apropos-internal
  143. (string-append "^" (regexp-quote text))))))
  144. (if (null? completions)
  145. #f
  146. (let ((retval (car completions)))
  147. (begin (set! completions (cdr completions))
  148. retval))))))
  149. (set! *readline-completion-function* apropos-completion-function)
  150. ))
  151. (define-public (activate-readline)
  152. (if (and (isatty? (current-input-port))
  153. (not (and (module-defined? the-root-module
  154. 'use-emacs-interface)
  155. use-emacs-interface)))
  156. (let ((read-hook (lambda () (run-hook before-read-hook))))
  157. (set-current-input-port (readline-port))
  158. (set! repl-reader
  159. (lambda (prompt)
  160. (dynamic-wind
  161. (lambda ()
  162. (set-readline-prompt! prompt "... ")
  163. (set-readline-read-hook! read-hook))
  164. (lambda () (read))
  165. (lambda ()
  166. (set-readline-prompt! "" "")
  167. (set-readline-read-hook! #f)))))
  168. (set! (using-readline?) #t))))