author | Claus Gittinger <cg@exept.de> |
Sat, 20 Jun 1998 20:31:05 +0200 | |
changeset 979 | 32f75cd56edc |
parent 977 | 785c3ad4eff1 |
child 985 | 275897f12b52 |
permissions | -rw-r--r-- |
914 | 1 |
TextCollector subclass:#TerminalView |
943 | 2 |
instanceVariableNames:'inStream outStream readerProcess shellPid kbdSequences |
3 |
escapeSequenceTree currentSequence currentTree kbdMap |
|
946 | 4 |
escapeLeadingChars numberOfColumns numberOfLines |
951 | 5 |
shellTerminateAction rangeStartLine rangeEndLine' |
943 | 6 |
classVariableNames:'' |
7 |
poolDictionaries:'' |
|
8 |
category:'Views-TerminalViews' |
|
914 | 9 |
! |
10 |
||
11 |
!TerminalView class methodsFor:'documentation'! |
|
12 |
||
13 |
documentation |
|
14 |
" |
|
916 | 15 |
I provide terminal functionality, by forking a command interpreter |
16 |
and comunicating with it via a pty. |
|
17 |
I am abstract - concrete terminal characteristics are defined |
|
18 |
by concrete subclasses (see VT52TerminalView). |
|
914 | 19 |
|
20 |
[author:] |
|
21 |
Claus Gittinger |
|
915 | 22 |
|
23 |
[start with:] |
|
24 |
VT52TerminalView openShell |
|
919 | 25 |
VT100TerminalView openShell |
914 | 26 |
" |
27 |
! ! |
|
28 |
||
972 | 29 |
!TerminalView class methodsFor:'opening'! |
914 | 30 |
|
928 | 31 |
open |
32 |
self openShell |
|
33 |
||
34 |
" |
|
35 |
VT100TerminalView open |
|
36 |
" |
|
37 |
||
38 |
"Modified: / 10.6.1998 / 15:06:35 / cg" |
|
39 |
"Created: / 10.6.1998 / 15:47:25 / cg" |
|
40 |
! |
|
41 |
||
914 | 42 |
openDummy |
972 | 43 |
"for testing purposes only - opens a dummy tty-view, which simply |
44 |
echoes whatever is typed in" |
|
45 |
||
914 | 46 |
|in vt52| |
47 |
||
48 |
vt52 := self new. |
|
49 |
in := ForwardingStream on:''. |
|
50 |
||
51 |
in fwdStream:vt52. |
|
52 |
vt52 inStream:in. |
|
53 |
vt52 outStream:in. |
|
54 |
vt52 open |
|
55 |
||
56 |
" |
|
57 |
self openDummy |
|
58 |
" |
|
59 |
! |
|
60 |
||
972 | 61 |
openOnInput:inStream output:outStream |
62 |
"open a terminalView on the given streams (which are typically some |
|
63 |
kind of socket). Keys pressed are sent to inStream, text appearing |
|
64 |
from outStream are displayed in the terminal view. |
|
65 |
This can be used to implement things like rlogin |
|
66 |
or telnet views (if connected to a modem, a call-unix can also be |
|
67 |
implemented this way)." |
|
68 |
||
69 |
|in top scr vt52| |
|
70 |
||
71 |
top := StandardSystemView new. |
|
72 |
scr := ScrollableView for:self in:top. |
|
73 |
scr origin:0.0@0.0 corner:1.0@1.0. |
|
74 |
vt52 := scr scrolledView. |
|
75 |
||
76 |
vt52 inStream:inStream. |
|
77 |
vt52 outStream:outStream. |
|
974 | 78 |
vt52 startReaderProcess. |
972 | 79 |
|
80 |
top extent:(scr preferredExtent). |
|
81 |
top label:'shell'. |
|
82 |
top open. |
|
83 |
^ top |
|
974 | 84 |
|
85 |
"Modified: / 20.6.1998 / 17:32:38 / cg" |
|
972 | 86 |
! |
87 |
||
914 | 88 |
openShell |
972 | 89 |
"start a shell on a pseudo-TTY, open a terminalView on it |
90 |
(i.e. this is kind of an xterm)" |
|
91 |
||
914 | 92 |
|in top scr vt52| |
93 |
||
94 |
top := StandardSystemView new. |
|
948 | 95 |
scr := ScrollableView for:self in:top. |
914 | 96 |
scr origin:0.0@0.0 corner:1.0@1.0. |
97 |
vt52 := scr scrolledView. |
|
98 |
||
946 | 99 |
vt52 startShell. |
100 |
vt52 shellTerminateAction:[top destroy]. |
|
101 |
||
940 | 102 |
top extent:(scr preferredExtent). |
103 |
top label:'shell'. |
|
946 | 104 |
top open |
914 | 105 |
|
106 |
" |
|
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
107 |
VT100TerminalView openShell |
914 | 108 |
" |
946 | 109 |
|
948 | 110 |
"Modified: / 12.6.1998 / 21:43:41 / cg" |
914 | 111 |
! ! |
112 |
||
972 | 113 |
!TerminalView class methodsFor:'queries'! |
114 |
||
115 |
isVisualStartable |
|
116 |
"returns whether this application class can be started via #open" |
|
117 |
||
118 |
self == TerminalView ifTrue:[^ false]. |
|
119 |
^ true |
|
120 |
||
121 |
"Created: / 10.6.1998 / 15:48:43 / cg" |
|
122 |
! ! |
|
123 |
||
914 | 124 |
!TerminalView methodsFor:'accessing'! |
125 |
||
126 |
inStream |
|
127 |
"return the value of the instance variable 'inStream' (automatically generated)" |
|
128 |
||
129 |
^ inStream! |
|
130 |
||
131 |
inStream:something |
|
132 |
"set the value of the instance variable 'inStream' (automatically generated)" |
|
133 |
||
134 |
inStream := something.! |
|
135 |
||
136 |
outStream |
|
137 |
"return the value of the instance variable 'outStream' (automatically generated)" |
|
138 |
||
139 |
^ outStream! |
|
140 |
||
141 |
outStream:something |
|
142 |
"set the value of the instance variable 'outStream' (automatically generated)" |
|
143 |
||
946 | 144 |
outStream := something.! |
145 |
||
146 |
shellTerminateAction:aBlock |
|
147 |
"set the block which is evaluated when the shell terminates. |
|
148 |
Can be used to close down the application in this case." |
|
149 |
||
150 |
shellTerminateAction := aBlock. |
|
151 |
||
152 |
"Created: / 12.6.1998 / 17:02:58 / cg" |
|
153 |
! ! |
|
914 | 154 |
|
155 |
!TerminalView methodsFor:'cursor handling'! |
|
156 |
||
157 |
cursorCol:col |
|
158 |
"check of col is a valid cursor position; return a new col-nr if not. |
|
159 |
Here, the linelength is enforced" |
|
160 |
||
926 | 161 |
^ super cursorCol:(col min:numberOfColumns) |
914 | 162 |
|
926 | 163 |
"Modified: / 10.6.1998 / 15:09:34 / cg" |
914 | 164 |
! |
165 |
||
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
166 |
cursorDown:n |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
167 |
cursorLine + n > list size ifTrue:[ |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
168 |
list := list , (Array new:n). |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
169 |
self textChanged. |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
170 |
]. |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
171 |
super cursorDown:n |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
172 |
|
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
173 |
"Modified: / 10.6.1998 / 17:18:41 / cg" |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
174 |
"Created: / 10.6.1998 / 17:18:50 / cg" |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
175 |
! |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
176 |
|
914 | 177 |
cursorLine:l col:col |
178 |
"check of col is a valid cursor position; return a new col-nr if not. |
|
179 |
Here, the linelength is enforced" |
|
180 |
||
926 | 181 |
^ super cursorLine:l col:(col min:numberOfColumns) |
914 | 182 |
|
926 | 183 |
"Modified: / 10.6.1998 / 15:09:38 / cg" |
914 | 184 |
! |
185 |
||
968
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
186 |
cursorMovementAllowed |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
187 |
"return true, if the user may move the cursor around |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
188 |
(via button-click, or cursor-key with selection). |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
189 |
Here false is returned - the cursor is only moved by |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
190 |
cursor positioning escape sequences arriving from the |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
191 |
stream." |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
192 |
|
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
193 |
^ false |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
194 |
|
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
195 |
"Created: / 18.6.1998 / 14:12:02 / cg" |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
196 |
! |
1cb313e6635b
do not allow cursor movement (via buttonPress).
Claus Gittinger <cg@exept.de>
parents:
964
diff
changeset
|
197 |
|
914 | 198 |
validateCursorCol:col inLine:line |
199 |
"check of col is a valid cursor position; return a new col-nr if not. |
|
200 |
Here, the linelength is enforced" |
|
201 |
||
926 | 202 |
^ col min:numberOfColumns |
914 | 203 |
|
926 | 204 |
"Modified: / 10.6.1998 / 15:09:41 / cg" |
914 | 205 |
! ! |
206 |
||
207 |
!TerminalView methodsFor:'event handling'! |
|
208 |
||
951 | 209 |
computeNumberOfLinesShown |
210 |
|prevNLines prevNCols| |
|
211 |
||
212 |
prevNCols := (innerWidth // font width). |
|
213 |
prevNLines := nFullLinesShown. |
|
214 |
||
215 |
super computeNumberOfLinesShown. |
|
216 |
||
217 |
((innerWidth // font width) ~~ prevNCols |
|
218 |
or:[prevNLines ~~ nFullLinesShown]) ifTrue:[ |
|
219 |
self defineWindowSize. |
|
220 |
] |
|
221 |
||
222 |
"Created: / 12.6.1998 / 22:34:39 / cg" |
|
979 | 223 |
"Modified: / 20.6.1998 / 19:45:28 / cg" |
951 | 224 |
! |
225 |
||
943 | 226 |
defineWindowSize |
227 |
inStream notNil ifTrue:[ |
|
964
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
228 |
(OperatingSystem |
943 | 229 |
setWindowSizeOnFileDescriptor:(inStream fileDescriptor) |
230 |
width:(innerWidth // font width) |
|
964
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
231 |
height:(nFullLinesShown)) ifFalse:[ |
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
232 |
"/ Transcript showCR:'VT100: cannot change windowSize'. |
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
233 |
]. |
951 | 234 |
numberOfLines := nFullLinesShown. |
979 | 235 |
"/ Transcript showCR:'VT100: changed len to ', numberOfLines printString. |
943 | 236 |
]. |
237 |
shellPid notNil ifTrue:[ |
|
238 |
OperatingSystem sendSignal:OperatingSystem sigWINCH to:shellPid |
|
239 |
] |
|
240 |
||
241 |
"Created: / 11.6.1998 / 22:51:39 / cg" |
|
979 | 242 |
"Modified: / 20.6.1998 / 20:29:13 / cg" |
943 | 243 |
! |
244 |
||
914 | 245 |
keyPress:aKey x:x y:y |
246 |
|rest rawKey seq| |
|
247 |
||
248 |
inStream isNil ifTrue:[^ self]. |
|
249 |
||
931 | 250 |
"/ Transcript showCR:'----'; show:'key:' ; showCR:aKey printString. |
914 | 251 |
|
252 |
aKey isCharacter ifTrue:[ |
|
253 |
"/ send it down to inStream ... |
|
254 |
inStream nextPut:aKey. |
|
255 |
^ self |
|
256 |
]. |
|
257 |
||
921 | 258 |
aKey == #Tab ifTrue:[ |
931 | 259 |
"/ Transcript show:'->' ; showCR:Character tab storeString. |
921 | 260 |
inStream nextPut:Character tab. |
261 |
^ self |
|
262 |
]. |
|
263 |
||
914 | 264 |
seq := kbdSequences at:aKey ifAbsent:nil. |
265 |
seq notNil ifTrue:[ |
|
931 | 266 |
"/ Transcript show:'->' ; showCR:seq storeString. |
914 | 267 |
inStream nextPutAll:(seq withEscapes). |
268 |
^ self |
|
269 |
]. |
|
270 |
||
271 |
rawKey := device keyboardMap keyAtValue:aKey ifAbsent:aKey. |
|
272 |
seq := kbdSequences at:rawKey ifAbsent:nil. |
|
273 |
seq notNil ifTrue:[ |
|
931 | 274 |
"/ Transcript show:'->' ; showCR:seq storeString. |
914 | 275 |
inStream nextPutAll:(seq withEscapes). |
276 |
^ self |
|
277 |
]. |
|
278 |
||
279 |
(rawKey startsWith:'Ctrl') ifTrue:[ |
|
280 |
rest := rawKey copyFrom:5. |
|
281 |
rest size == 1 ifTrue:[ |
|
282 |
rest := rest at:1. |
|
283 |
(rest >= $a and:[rest <= $z]) ifTrue:[ |
|
931 | 284 |
"/ Transcript show:'->' ; showCR:(Character value:(rest - $a + 1)) storeString. |
914 | 285 |
inStream nextPut:(Character value:(rest - $a + 1)). |
286 |
^ self |
|
287 |
]. |
|
288 |
(rest >= $A and:[rest <= $Z]) ifTrue:[ |
|
931 | 289 |
"/ Transcript show:'->' ; showCR:(Character value:(rest - $a + 1)) storeString. |
914 | 290 |
inStream nextPut:(Character value:(rest - $A + 1)). |
291 |
^ self |
|
292 |
]. |
|
293 |
] |
|
294 |
]. |
|
295 |
||
934 | 296 |
(rawKey startsWith:'Control') ifTrue:[ |
297 |
^ self |
|
298 |
]. |
|
299 |
(rawKey startsWith:'Shift') ifTrue:[ |
|
300 |
^ self |
|
301 |
]. |
|
302 |
(rawKey startsWith:'Alt') ifTrue:[ |
|
303 |
^ self |
|
304 |
]. |
|
305 |
(rawKey startsWith:'Cmd') ifTrue:[ |
|
950 | 306 |
^ super keyPress:aKey x:x y:y |
934 | 307 |
]. |
308 |
||
309 |
Transcript show:'unhandled: '; showCR:rawKey. |
|
914 | 310 |
|
950 | 311 |
"Modified: / 12.6.1998 / 22:16:50 / cg" |
914 | 312 |
! |
313 |
||
314 |
shellTerminated |
|
315 |
self closeDownShell. |
|
946 | 316 |
shellTerminateAction notNil ifTrue:[ |
317 |
shellTerminateAction value |
|
318 |
] ifFalse:[ |
|
319 |
"/ may be removed ... |
|
320 |
self warn:'shell terminated'. |
|
321 |
] |
|
322 |
||
323 |
"Modified: / 12.6.1998 / 17:03:26 / cg" |
|
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
324 |
! |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
325 |
|
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
326 |
sizeChanged:how |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
327 |
super sizeChanged:how. |
943 | 328 |
self defineWindowSize. |
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
329 |
|
943 | 330 |
"Modified: / 11.6.1998 / 22:51:48 / cg" |
914 | 331 |
! ! |
332 |
||
333 |
!TerminalView methodsFor:'functions'! |
|
334 |
||
335 |
doBackspace |
|
336 |
self cursorLeft. |
|
337 |
self replaceCharAtCursor:(Character space). |
|
338 |
self cursorLeft. |
|
339 |
||
931 | 340 |
"Modified: / 10.6.1998 / 17:09:12 / cg" |
914 | 341 |
! |
342 |
||
926 | 343 |
doClearDisplay |
344 |
firstLineShown to:(list size) do:[:l | |
|
345 |
self at:l put:'' |
|
346 |
]. |
|
922 | 347 |
|
926 | 348 |
"Created: / 10.6.1998 / 14:43:06 / cg" |
349 |
"Modified: / 10.6.1998 / 14:58:07 / cg" |
|
350 |
! |
|
351 |
||
352 |
doClearToEnd |
|
353 |
self doClearToEndOfLine. |
|
922 | 354 |
cursorLine+1 to:(list size) do:[:l | |
355 |
self at:l put:'' |
|
356 |
]. |
|
357 |
||
926 | 358 |
"Modified: / 10.6.1998 / 14:45:43 / cg" |
359 |
! |
|
360 |
||
361 |
doClearToEndOfLine |
|
362 |
|l| |
|
363 |
||
364 |
l := self listAt:cursorLine. |
|
931 | 365 |
(l size >= (cursorCol-1)) ifTrue:[ |
951 | 366 |
l notNil ifTrue:[ |
367 |
l := l copyTo:cursorCol-1. |
|
979 | 368 |
self withoutRedrawAt:cursorLine put:l. |
369 |
self invalidateLine:cursorLine |
|
370 |
"/ self at:cursorLine put:l. |
|
951 | 371 |
] |
926 | 372 |
] |
373 |
||
374 |
"Created: / 10.6.1998 / 14:45:01 / cg" |
|
979 | 375 |
"Modified: / 20.6.1998 / 19:10:21 / cg" |
914 | 376 |
! |
377 |
||
926 | 378 |
doCursorDown:n |
979 | 379 |
|wasOn rEnd| |
926 | 380 |
|
979 | 381 |
"/ rangeEndLine == numberOfLines ifTrue:[ |
382 |
"/ ^ super cursorDown:n |
|
383 |
"/ ]. |
|
384 |
cursorLine + 1 - firstLineShown + n <= rangeEndLine ifTrue:[ |
|
951 | 385 |
"/ no special action req'd |
386 |
^ super cursorDown:n |
|
387 |
]. |
|
979 | 388 |
|
951 | 389 |
n timesRepeat:[ |
390 |
wasOn := self hideCursor. |
|
979 | 391 |
rEnd := rangeEndLine+firstLineShown-1. |
392 |
cursorLine == rEnd ifTrue:[ |
|
393 |
self deleteLine:(rangeStartLine+firstLineShown-1). |
|
394 |
self insertLine:'' before:rEnd. |
|
951 | 395 |
] ifFalse:[ |
396 |
super cursorDown |
|
397 |
]. |
|
979 | 398 |
wasOn ifTrue:[self showCursor]. "/ self makeCursorVisibleAndShowCursor:wasOn. |
951 | 399 |
] |
400 |
||
979 | 401 |
"Modified: / 20.6.1998 / 20:29:39 / cg" |
926 | 402 |
! |
403 |
||
914 | 404 |
doCursorHome |
938 | 405 |
self cursorVisibleLine:1 col:1 |
406 |
"/ super cursorHome |
|
407 |
||
408 |
"Modified: / 10.6.1998 / 20:47:31 / cg" |
|
914 | 409 |
! |
410 |
||
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
411 |
doCursorLeft:n |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
412 |
n timesRepeat:[ |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
413 |
super cursorLeft |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
414 |
] |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
415 |
|
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
416 |
"Created: / 11.6.1998 / 22:30:00 / cg" |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
417 |
! |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
418 |
|
914 | 419 |
doCursorNewLine |
931 | 420 |
super cursorDown:1 |
421 |
||
422 |
"Modified: / 10.6.1998 / 16:55:57 / cg" |
|
914 | 423 |
! |
424 |
||
425 |
doCursorReturn |
|
426 |
super cursorToBeginOfLine |
|
427 |
! |
|
428 |
||
926 | 429 |
doCursorRight:n |
430 |
self cursorCol:(cursorCol + n) |
|
431 |
||
432 |
"Created: / 10.6.1998 / 15:10:08 / cg" |
|
433 |
! |
|
434 |
||
951 | 435 |
doCursorUp:n |
979 | 436 |
|wasOn rStart| |
926 | 437 |
|
979 | 438 |
"/ rangeStartLine == 1 ifTrue:[ |
439 |
"/ ^ super cursorUp:n |
|
440 |
"/ ]. |
|
441 |
cursorLine + 1 - firstLineShown - n >= rangeStartLine ifTrue:[ |
|
951 | 442 |
"/ no special action req'd |
443 |
^ super cursorUp:n |
|
444 |
]. |
|
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
445 |
n timesRepeat:[ |
951 | 446 |
wasOn := self hideCursor. |
979 | 447 |
rStart := rangeStartLine+firstLineShown-1. |
448 |
cursorLine == rStart ifTrue:[ |
|
449 |
(rangeEndLine+firstLineShown-1) <= list size ifTrue:[ |
|
450 |
self deleteLine:(rangeEndLine+firstLineShown-1). |
|
451 |
self insertLine:'' before:rStart. |
|
452 |
]. |
|
951 | 453 |
] ifFalse:[ |
454 |
super cursorUp |
|
455 |
]. |
|
456 |
self makeCursorVisibleAndShowCursor:wasOn. |
|
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
457 |
] |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
458 |
|
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
459 |
"Created: / 11.6.1998 / 22:29:46 / cg" |
979 | 460 |
"Modified: / 20.6.1998 / 20:30:34 / cg" |
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
461 |
! |
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
462 |
|
926 | 463 |
doSendInterrupt |
464 |
OperatingSystem sendSignal:(OperatingSystem sigINT) to:shellPid negated. |
|
465 |
||
934 | 466 |
"Modified: / 10.6.1998 / 17:49:49 / cg" |
914 | 467 |
! ! |
468 |
||
469 |
!TerminalView methodsFor:'initialization'! |
|
470 |
||
471 |
closeDownShell |
|
926 | 472 |
|pid| |
473 |
||
474 |
(pid := shellPid) notNil ifTrue:[ |
|
934 | 475 |
"/ Transcript print:'killing shell pid='; showCR:pid. |
476 |
||
926 | 477 |
OperatingSystem terminateProcessGroup:pid. |
478 |
OperatingSystem terminateProcess:pid. |
|
925 | 479 |
Delay waitForSeconds:1. |
480 |
shellPid notNil ifTrue:[ |
|
926 | 481 |
OperatingSystem killProcessGroup:pid. |
482 |
OperatingSystem killProcess:pid. |
|
925 | 483 |
shellPid := nil. |
484 |
]. |
|
926 | 485 |
OperatingSystem closePid:pid. |
914 | 486 |
]. |
487 |
||
488 |
readerProcess notNil ifTrue:[ |
|
489 |
readerProcess terminate. |
|
490 |
readerProcess := nil |
|
491 |
]. |
|
492 |
inStream notNil ifTrue:[ |
|
493 |
inStream close. |
|
494 |
inStream := nil |
|
495 |
]. |
|
496 |
outStream notNil ifTrue:[ |
|
497 |
outStream close. |
|
498 |
outStream := nil |
|
499 |
]. |
|
924 | 500 |
|
934 | 501 |
"Modified: / 10.6.1998 / 17:53:49 / cg" |
914 | 502 |
! |
503 |
||
504 |
destroy |
|
505 |
self closeDownShell. |
|
506 |
super destroy |
|
507 |
! |
|
508 |
||
509 |
escapeSequences:codes |
|
510 |
|tree| |
|
511 |
||
512 |
tree isNil ifTrue:[tree := escapeSequenceTree := IdentityDictionary new]. |
|
513 |
||
514 |
codes do:[:specEntry | |
|
515 |
|sequence function| |
|
516 |
||
517 |
sequence := (specEntry at:1) withEscapes. |
|
518 |
function := specEntry at:2. |
|
519 |
||
520 |
tree := escapeSequenceTree. |
|
521 |
||
522 |
sequence keysAndValuesDo:[:idx :char | |
|
523 |
|followup| |
|
524 |
||
525 |
idx == sequence size ifTrue:[ |
|
526 |
tree at:char put:function |
|
527 |
] ifFalse:[ |
|
528 |
followup := tree at:char ifAbsent:nil. |
|
529 |
followup isNil ifTrue:[ |
|
530 |
tree at:char put:(followup := IdentityDictionary new). |
|
531 |
]. |
|
532 |
tree := followup |
|
533 |
] |
|
534 |
] |
|
535 |
]. |
|
918 | 536 |
escapeLeadingChars := escapeSequenceTree keys asSet. |
537 |
escapeLeadingChars add:(Character cr). |
|
538 |
escapeLeadingChars add:(Character return). |
|
539 |
escapeLeadingChars add:(Character backspace). |
|
540 |
||
541 |
escapeLeadingChars := escapeLeadingChars asArray |
|
542 |
||
543 |
"Modified: / 9.6.1998 / 19:43:12 / cg" |
|
914 | 544 |
! |
545 |
||
546 |
initialize |
|
547 |
super initialize. |
|
548 |
||
549 |
showMatchingParenthesis := false. |
|
550 |
insertMode := false. |
|
936 | 551 |
alwaysAppendAtEnd := false. |
944 | 552 |
collectSize := 100. |
977 | 553 |
st80Mode := false. |
554 |
trimBlankLines := true. |
|
914 | 555 |
|
926 | 556 |
numberOfColumns := 80. |
979 | 557 |
numberOfLines := 24. |
954 | 558 |
rangeStartLine := 1. |
559 |
rangeEndLine := numberOfLines. |
|
926 | 560 |
|
914 | 561 |
self initializeKeyboardSequences. |
562 |
list := OrderedCollection new:24 withAll:''. |
|
563 |
||
564 |
self initializeKeyboardMap. |
|
565 |
||
566 |
" |
|
567 |
VT52TerminalView openShell |
|
926 | 568 |
VT100TerminalView openShell |
914 | 569 |
" |
926 | 570 |
|
979 | 571 |
"Modified: / 20.6.1998 / 20:06:49 / cg" |
914 | 572 |
! |
573 |
||
574 |
initializeKeyboardMap |
|
575 |
|ctrlKeys cmdKeys| |
|
576 |
||
577 |
"/ setup my own keyboardMap, where control-keys are |
|
578 |
"/ not translated. |
|
579 |
kbdMap := device keyboardMap copy. |
|
580 |
||
581 |
ctrlKeys := kbdMap keys select:[:key | key startsWith:'Ctrl']. |
|
582 |
ctrlKeys do:[:key | kbdMap removeKey:key]. |
|
950 | 583 |
|
914 | 584 |
cmdKeys := kbdMap keys select:[:key | key startsWith:'Cmd']. |
950 | 585 |
cmdKeys do:[:key | |
586 |
(#(Copy Paste SaveAs Print) includes:(kbdMap at:key)) ifFalse:[ |
|
587 |
kbdMap removeKey:key |
|
588 |
] |
|
589 |
]. |
|
914 | 590 |
|
591 |
kbdMap removeKey:#Delete ifAbsent:[]. |
|
592 |
kbdMap removeKey:#BackSpace ifAbsent:[]. |
|
593 |
||
594 |
" |
|
595 |
VT52TerminalView openShell |
|
596 |
" |
|
950 | 597 |
|
598 |
"Modified: / 12.6.1998 / 22:18:23 / cg" |
|
914 | 599 |
! |
600 |
||
601 |
initializeKeyboardSequences |
|
602 |
self subclassResponsibility. |
|
603 |
! |
|
604 |
||
605 |
keyboardMap |
|
934 | 606 |
"return my keyboard map. This has control keys removed and |
607 |
those will be passed unchanged to the shell" |
|
608 |
||
914 | 609 |
^ kbdMap |
934 | 610 |
|
611 |
"Modified: / 10.6.1998 / 17:46:59 / cg" |
|
914 | 612 |
! |
613 |
||
614 |
startReaderProcess |
|
934 | 615 |
"Start a reader process, which looks for the commands output, |
616 |
and sends me #peocessInput:n: events whenever something arrives." |
|
617 |
||
914 | 618 |
readerProcess isNil ifTrue:[ |
619 |
readerProcess := [ |
|
620 |
[ |
|
947 | 621 |
self waitUntilVisible. |
622 |
||
940 | 623 |
Stream streamErrorSignal handle:[:ex | |
624 |
Transcript showCR:ex errorString. |
|
625 |
Transcript showCR:OperatingSystem lastErrorString. |
|
626 |
] do:[ |
|
926 | 627 |
[true] whileTrue:[ |
628 |
Object abortSignal handle:[:ex | |
|
629 |
self showCursor. |
|
630 |
] do:[ |
|
948 | 631 |
|buffer n| |
632 |
||
926 | 633 |
outStream readWait. |
945 | 634 |
(self sensor hasKeyPressEventFor:self) ifTrue:[ |
635 |
Processor yield |
|
926 | 636 |
] ifFalse:[ |
945 | 637 |
buffer := String new:1024. |
638 |
n := outStream nextAvailableBytes:1024 into:buffer startingAt:1. |
|
639 |
||
640 |
n > 0 ifTrue:[ |
|
641 |
self pushEvent:#processInput:n: with:buffer with:n. |
|
642 |
] ifFalse:[ |
|
643 |
n == 0 ifTrue:[ |
|
644 |
outStream atEnd ifTrue:[ |
|
645 |
outStream close. outStream := nil. |
|
646 |
inStream close. inStream := nil. |
|
647 |
||
648 |
Processor activeProcess terminate. |
|
649 |
] |
|
926 | 650 |
] |
651 |
] |
|
914 | 652 |
] |
653 |
] |
|
654 |
] |
|
655 |
] |
|
656 |
] valueOnUnwindDo:[ |
|
657 |
readerProcess := nil |
|
658 |
] |
|
659 |
] fork. |
|
660 |
] |
|
661 |
||
662 |
" |
|
934 | 663 |
VT100TerminalView openShell |
914 | 664 |
" |
926 | 665 |
|
948 | 666 |
"Modified: / 12.6.1998 / 20:59:05 / cg" |
914 | 667 |
! |
668 |
||
669 |
startShell |
|
934 | 670 |
"start a shell on a pseudo terminal. |
671 |
Also fork a reader process, to read the shells output and |
|
948 | 672 |
tell me, whenever something arrives" |
934 | 673 |
|
914 | 674 |
|p slaveFD execFdArray blocked exitStatus| |
675 |
||
958
84710fbdfb28
create my view before starting a shell (to pass down windowID).
Claus Gittinger <cg@exept.de>
parents:
957
diff
changeset
|
676 |
self create. "/ need my windowID (to pass down in environment) |
84710fbdfb28
create my view before starting a shell (to pass down windowID).
Claus Gittinger <cg@exept.de>
parents:
957
diff
changeset
|
677 |
|
914 | 678 |
p := ExternalStream makePTYPair. |
679 |
p isNil ifTrue:[ |
|
915 | 680 |
self warn:'cannot open pty'. |
914 | 681 |
^ self. |
682 |
]. |
|
683 |
||
684 |
"/ p at:1 is the master; |
|
685 |
"/ p at:2 is the slave |
|
686 |
inStream := outStream := (p at:1). |
|
687 |
inStream buffered:false. |
|
688 |
||
943 | 689 |
self defineWindowSize. |
690 |
||
914 | 691 |
"/ fork a shell process on the slave-side |
692 |
slaveFD := (p at:2) fileDescriptor. |
|
693 |
||
694 |
execFdArray := Array with:slaveFD with:slaveFD with:slaveFD. |
|
695 |
||
696 |
blocked := OperatingSystem blockInterrupts. |
|
697 |
||
698 |
shellPid := Processor |
|
699 |
monitor:[ |
|
957
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
700 |
|e shell cmd| |
929 | 701 |
|
942
1f4fa3a6faec
send a sigWINCH whenever the views size changes.
Claus Gittinger <cg@exept.de>
parents:
940
diff
changeset
|
702 |
e := Dictionary new. |
957
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
703 |
e at:'TERM' put:(self terminalType). |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
704 |
e at:'LINES' put:(numberOfLines printString). |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
705 |
e at:'COLUMNS' put:(numberOfColumns printString). |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
706 |
drawableId notNil ifTrue:[ |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
707 |
e at:'WINDOWID' put:(drawableId address printString). |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
708 |
]. |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
709 |
|
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
710 |
shell := OperatingSystem getEnvironment:'SHELL'. |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
711 |
shell size == 0 ifTrue:[ |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
712 |
shell := '/bin/sh'. |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
713 |
]. |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
714 |
e at:'SHELL' put:shell. |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
715 |
cmd := shell asFilename baseName. |
929 | 716 |
|
914 | 717 |
OperatingSystem |
957
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
718 |
exec:shell |
8c167c9ea5c0
also pass WINDOWID (if known) and SHELL in environment.
Claus Gittinger <cg@exept.de>
parents:
955
diff
changeset
|
719 |
withArguments:(Array with:cmd) |
929 | 720 |
environment:e |
914 | 721 |
fileDescriptors:execFdArray |
722 |
closeDescriptors:#() |
|
723 |
fork:true |
|
929 | 724 |
newPgrp:true. |
914 | 725 |
] |
726 |
action:[:status | |
|
935 | 727 |
"/ Transcript show:'pid:'; showCR:status pid. |
728 |
"/ Transcript show:'status:'; showCR:status status. |
|
729 |
"/ Transcript show:'code:'; showCR:status code. |
|
730 |
"/ Transcript show:'core:'; showCR:status core. |
|
914 | 731 |
status stillAlive ifFalse:[ |
732 |
exitStatus := status. |
|
733 |
OperatingSystem closePid:shellPid. |
|
734 |
shellPid := nil. |
|
735 |
self pushEvent:#shellTerminated |
|
736 |
]. |
|
737 |
]. |
|
738 |
||
739 |
shellPid isNil ifTrue:[ |
|
740 |
self halt. |
|
741 |
(p at:1) close. |
|
742 |
(p at:2) close. |
|
743 |
]. |
|
744 |
||
745 |
blocked ifFalse:[ |
|
746 |
OperatingSystem unblockInterrupts |
|
747 |
]. |
|
748 |
||
749 |
self startReaderProcess. |
|
750 |
||
751 |
" |
|
934 | 752 |
VT100TerminalView openShell |
914 | 753 |
" |
929 | 754 |
|
958
84710fbdfb28
create my view before starting a shell (to pass down windowID).
Claus Gittinger <cg@exept.de>
parents:
957
diff
changeset
|
755 |
"Modified: / 13.6.1998 / 19:20:54 / cg" |
914 | 756 |
! ! |
757 |
||
758 |
!TerminalView methodsFor:'menu'! |
|
759 |
||
760 |
editMenu |
|
761 |
"return the views middleButtonMenu" |
|
762 |
||
763 |
<resource: #keyboard (#Copy #Paste #Print)> |
|
764 |
<resource: #programMenu> |
|
765 |
||
766 |
|items m sub shortKeys sensor| |
|
767 |
||
768 |
((sensor := self sensor) notNil and:[sensor ctrlDown]) ifTrue:[ |
|
769 |
items := #( |
|
770 |
('Interrupt' doSendInterrupt) |
|
771 |
). |
|
772 |
] ifFalse:[ |
|
773 |
items := #( |
|
774 |
('copy' copySelection Copy ) |
|
775 |
('paste' pasteOrReplace Paste ) |
|
776 |
('-' ) |
|
951 | 777 |
('font ...' changeFont ) |
778 |
('-' ) |
|
914 | 779 |
('save as ...' save SaveAs ) |
780 |
('print' doPrint Print ) |
|
781 |
). |
|
782 |
]. |
|
783 |
||
784 |
m := PopUpMenu itemList:items resources:resources. |
|
785 |
||
786 |
self hasSelection not ifTrue:[ |
|
787 |
m disable:#copySelection. |
|
788 |
]. |
|
789 |
^ m. |
|
790 |
||
951 | 791 |
"Modified: / 12.6.1998 / 22:33:33 / cg" |
914 | 792 |
! ! |
793 |
||
940 | 794 |
!TerminalView methodsFor:'misc'! |
914 | 795 |
|
796 |
removeTrailingBlankLines |
|
797 |
^ self |
|
798 |
! ! |
|
799 |
||
800 |
!TerminalView methodsFor:'processing - input'! |
|
801 |
||
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
802 |
processInput:buffer n:count |
964
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
803 |
self hideCursor. |
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
804 |
1 to:count do:[:i | |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
805 |
self nextPut:(buffer at:i). |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
806 |
]. |
948 | 807 |
|
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
808 |
(self sensor hasEvent:#processInput:n: for:self) ifFalse:[ |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
809 |
self endEntry. |
964
43d6e33a4240
keep cursor off while more input is arriving.
Claus Gittinger <cg@exept.de>
parents:
958
diff
changeset
|
810 |
self showCursor. |
979 | 811 |
"/ self makeCursorVisible. |
933
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
812 |
]. |
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
813 |
|
de456e07697e
much better asynchronous display
Claus Gittinger <cg@exept.de>
parents:
931
diff
changeset
|
814 |
"Created: / 10.6.1998 / 17:26:09 / cg" |
979 | 815 |
"Modified: / 20.6.1998 / 19:18:07 / cg" |
914 | 816 |
! ! |
817 |
||
818 |
!TerminalView methodsFor:'queries'! |
|
819 |
||
820 |
preferredExtent |
|
951 | 821 |
^ (fontWidth * numberOfColumns + (leftMargin * 2)) |
822 |
@ |
|
979 | 823 |
((self heightForLines:numberOfLines) + 8) |
926 | 824 |
|
979 | 825 |
"Modified: / 20.6.1998 / 20:06:57 / cg" |
929 | 826 |
! |
827 |
||
828 |
terminalType |
|
829 |
^ #dump |
|
830 |
||
831 |
"Modified: / 10.6.1998 / 14:47:03 / cg" |
|
832 |
"Created: / 10.6.1998 / 16:22:30 / cg" |
|
914 | 833 |
! ! |
834 |
||
835 |
!TerminalView methodsFor:'selection handling'! |
|
836 |
||
837 |
paste:someText |
|
838 |
"paste - redefined to send the chars to the shell instead |
|
839 |
of pasting into the view" |
|
840 |
||
950 | 841 |
|s nLines| |
842 |
||
843 |
s := someText. |
|
844 |
s isString ifTrue:[ |
|
845 |
s := s asStringCollection |
|
846 |
] ifFalse:[ |
|
847 |
(s isKindOf:StringCollection) ifFalse:[ |
|
848 |
self warn:'selection (' , s class name , ') is not convertable to Text'. |
|
849 |
^ self |
|
850 |
] |
|
851 |
]. |
|
852 |
(nLines := s size) == 0 ifTrue:[^ self]. |
|
853 |
(nLines == 1 and:[(s at:1) size == 0]) ifTrue:[^ self]. |
|
854 |
s keysAndValuesDo:[:idx :line | |
|
855 |
inStream nextPutAll:line. |
|
856 |
idx ~~ nLines ifTrue:[ |
|
857 |
inStream nextPut:(Character return). |
|
858 |
] |
|
859 |
]. |
|
860 |
||
861 |
"Modified: / 12.6.1998 / 22:12:47 / cg" |
|
914 | 862 |
! ! |
863 |
||
864 |
!TerminalView class methodsFor:'documentation'! |
|
865 |
||
866 |
version |
|
979 | 867 |
^ '$Header: /cvs/stx/stx/libwidg2/TerminalView.st,v 1.43 1998-06-20 18:31:05 cg Exp $' |
914 | 868 |
! ! |