File: Iedline.scm

package info (click to toggle)
scm 5f4-3
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 5,320 kB
  • sloc: ansic: 58,822; lisp: 17,257; makefile: 1,241; sh: 555; asm: 288
file content (111 lines) | stat: -rwxr-xr-x 4,073 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
;;;; "Iedline.scm" SCM interface to readline library
;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Lesser General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public
;; License along with this program.  If not, see
;; <http://www.gnu.org/licenses/>.

;; Author: Radey Shouman

;; Change both current-input-port and current-output-port to
;; allow line editing of input.
;; All output goes through a soft port in order to detect prompt
;; lines, i.e. lines unterminated by a newline.

(define (make-edited-line-port)
  (let  ; The prompt string we receive.
       ((prompt "")
	; Hack to make readline overwrite the prompt we manually write.
	; Notice that #\cr is being wrapped in #\soh and #\stx, respectively
	; RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE (defined in
	; <readline/readline.h>), to signal to readline that #\cr is
	; invisible.
	(prompt-hack (string #\soh #\cr #\stx))
	; Concatenation of "prompt-hack" and "prompt", this is the actual
	; prompt we send to readline.
	(prompt-real "")
	(outp (default-output-port))
	(inp (default-input-port))
	(strp (call-with-input-string "" identity)))
    (make-soft-port
     (vector (lambda (c)
	       (write-char c outp))
	     (lambda (s)
	       ; Reverse-engineered assumption: string-write to this port will
	       ; only be done in the following cases:
	       ;
	       ;   - Empty string.
	       ;
	       ;   - Printing repl results, in which case the string will
	       ;     always come linefeed-terminated.
	       ;
	       ;   - Prompt printing, which will never be linefeed-terminated.
	       ;     The prompt string is immediately printed (manually),
	       ;     later, when GNU readline is called, a carriage return
	       ;     prepended to the same prompt string will cause it to
	       ;     write its prompt on top of the one we printed ourselves
	       ;     (therefore only one instance of the prompt string is
	       ;     actually visible to the interactive user).  Presumably
	       ;     this is the result of kluging optional readline support
	       ;     on top of an existing prompting mechanism.
	       ;
	       ; -- astian
	       (display s outp)
	       (or (zero? (string-length s))
		   (eq? #\newline (string-ref s (- (string-length s) 1)))
		   (begin
		     (or (string=? s prompt)
			 (begin
			   (set! prompt s)
			   (set! prompt-real (string-append prompt-hack prompt))))
		     (force-output outp))))
	     (lambda ()
	       (force-output outp))
	     (lambda ()
	       (let tail ((c (read-char strp)))
		 (if (char? c) c
		     (let ((str (read-edited-line prompt-real)))
		       (if (string? str)
			   (let ((n (string-length str)))
			     (add-history str)
			     (vector-set-length! str (+ 1 n))
			     (string-set! str n #\newline)
			     (set! strp (call-with-input-string
					 str identity))
			     (tail (read-char strp)))
			   str)))))
	     #f)
     open_both)))

(define line-editing
  (let ((edit-port #f)
	(oiport #f)
	(ooport #f))
    (lambda arg
      (define past edit-port)
      (cond ((null? arg))
	    ((and (car arg) (not edit-port))
	     (set! edit-port (make-edited-line-port))
	     (set! oiport (set-current-input-port edit-port))
	     (set! ooport (set-current-output-port edit-port)))
	    (edit-port
	     (set-current-input-port oiport)
	     (set-current-output-port ooport)
	     (set! edit-port #f)))
      past)))

(and
 (if (provided? 'unix) (isatty? (current-input-port)) #t)
 (eq? (current-input-port) (default-input-port))
 (not (getenv "EMACS"))
 (line-editing #t))