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