-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathhistory.fs
548 lines (457 loc) · 16.6 KB
/
history.fs
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
\ command line edit and history support 16oct94py
\ Authors: Bernd Paysan, Anton Ertl, Jens Wilke
\ Copyright (C) 1995,2000,2003,2004,2005,2006,2007,2008,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024 Free Software Foundation, Inc.
\ This file is part of Gforth.
\ Gforth is free software; you can redistribute it and/or
\ modify it under the terms of the GNU 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 General Public License for more details.
\ You should have received a copy of the GNU General Public License
\ along with this program. If not, see http://www.gnu.org/licenses/.
require user-object.fs
require mkdir.fs
edit-out next-task - class-o !
kernel-editor cell- @ 2 cells - 2@ \ extend edit-out class
umethod paste! ( addr u -- )
umethod paste@ ( -- addr u )
umethod grow-tib ( max span addr pos1 more -- max span addr pos1 flag )
umethod edit-error
umethod ekeys
cell uvar edit-curpos
cell uvar screenw
cell uvar setstring$ \ additional string at cursor for IME
Variable paste$ \ global paste buffer
align , , here
' (ins) , ' (ins-string) , ' (edit-control) ,
' noop , ' noop , ' noop , ' std-ctrlkeys , ' false , \ kernel stuff
' noop , ' noop , ' 0> , ' bell , ' noop , \ extended stuff
, here 0 , 0 , 0 , 0 , 0 , 0 ,
Constant edit-terminal
edit-terminal cell- @ Constant edit-terminal-c
edit-terminal edit-out !
\ command line editing 16oct94py
: >edit-rest ( span addr pos1 -- span addr pos1 addr2 len )
\ get rest of the string
over fourth third chars /string ;
: bindkey ( xt key -- )
dup bl u>= abort" Ctrl codes only!"
cells ctrlkeys + ! ;
: ebindkey ( xt key -- )
dup keycode-limit keycode-start within abort" Ekeys only!"
keycode-start - cells ekeys + ! ;
: ctrl-i ( "<char>" -- c )
char toupper $40 xor ;
' ctrl-i
:noname
ctrl-i postpone Literal ;
interpret/compile: ctrl ( "<char>" -- ctrl-code )
\ history support 16oct94py
0 Value history \ history file fid
:noname ( -- ) defers 'image 0 to history ; is 'image
2Variable forward^
2Variable backward^
2Variable end^
Variable vt100-modifier \ shift, ctrl, alt
?: -scan ( addr u char -- addr' u' )
>r BEGIN dup WHILE 1- 2dup + c@ r@ = UNTIL THEN
rdrop ;
: force-open ( addr len -- fid )
2dup r/w open-file
IF
drop
2dup '/' -scan $1FF mkdir-parents drop
r/w create-file throw
ELSE
nip nip
THEN ;
: history-file ( -- addr u )
s" GFORTHHIST" getenv dup 0= IF
2drop s" XDG_DATA_HOME" getenv dup 0= IF
2drop s" ~/.local/share" THEN
[: type ." /gforth/history" ;] $tmp
THEN ;
\ moving in history file 16oct94py
: edit-curpos-off edit-curpos off edit-linew off cols screenw ! ;
: clear-line ( max span addr pos1 -- max addr )
drop nip ;
: xretype ( max span addr pos1 -- max span addr pos1 f )
edit-update false ;
: hist-pos ( -- ud )
history ?dup-IF file-position drop ELSE backward^ 2@ THEN ;
: hist-setpos ( ud -- )
history ?dup-IF reposition-file drop ELSE 2drop THEN ;
: get-line ( addr len -- len' flag )
swap history ?dup-IF read-line throw
ELSE 2drop 0 false THEN ;
: next-line ( max span addr pos1 -- max span addr pos2 false )
clear-line
forward^ 2@ 2dup hist-setpos backward^ 2!
2dup get-line drop
hist-pos forward^ 2!
tuck xretype ;
: find-prev-line ( max addr -- max span addr pos2 )
backward^ 2@ forward^ 2!
over 2 + negate s>d backward^ 2@ d+ #0. dmax 2dup hist-setpos
BEGIN
backward^ 2! 2dup get-line WHILE
hist-pos 2dup forward^ 2@ d< WHILE
rot drop
REPEAT 2drop THEN tuck ;
: prev-line ( max span addr pos1 -- max span addr pos2 false )
clear-line find-prev-line xretype ;
\ Create lfpad #lf c,
$10 buffer: lastline#
$10 buffer: thisline#
: lastline<> ( addr u -- flag )
false thisline# dup $10 erase hashkey2
thisline# $10 lastline# over str= 0= dup IF
thisline# lastline# $10 move
THEN ;
: write-history ( addr u -- )
2dup -trailing nip IF
2dup lastline<> IF
end^ 2@ hist-setpos
history
?dup-IF write-line drop
history flush-file drop \ don't worry about errors
ELSE 2drop THEN
hist-pos 2dup backward^ 2! end^ 2!
EXIT
ELSE
hist-pos 2dup backward^ 2! end^ 2!
THEN
THEN
2drop ;
: (enter) ( max span addr pos1 -- max span addr pos2 true )
>r 2dup swap write-history r> (ret) ;
: extract-word ( addr len -- addr' len' )
dup >r
BEGIN 1- dup 0>= WHILE 2dup + c@ bl = UNTIL THEN 1+
tuck + r> rot - ;
Create prefix-found 0 , 0 ,
0 value alphabetic-tab
: word-lex ( nfa1 nfa2 -- -1/0/1 )
dup 0=
IF
2drop 1 EXIT
THEN
name>string 2>r name>string
vt100-modifier @ IF 2r> 2swap 2>r THEN
dup r@ = alphabetic-tab or
IF
rdrop r> over capscompare 0<= EXIT
THEN
r> < nip rdrop ;
: search-voc ( addr len nfa1 nfa2 -- addr len nfa3 )
>r
BEGIN
dup
WHILE
>r dup r@ name>string nip <=
IF
2dup r@ name>string drop over capscompare 0=
IF
r> dup r@ word-lex
IF
dup prefix-found @ word-lex
0>=
IF
rdrop dup >r
THEN
THEN
>r
THEN
THEN
r> name>link
REPEAT
drop r> ;
: prefix-off ( -- ) 0 0 prefix-found 2! ;
: prefix-string ( addr len nfa -- addr' len' )
dup prefix-found ! ?dup-IF
name>string rot /string rot drop
dup 1+ prefix-found cell+ !
ELSE
2drop s" " prefix-off
THEN ;
Defer search-prefix
: simple-search-prefix ( addr1 len1 -- addr2 len2 )
0 ['] search-order >body $@ cell MEM-DO
I cell- 2@ <>
IF I @ wordlist-id @ swap search-voc THEN
LOOP
prefix-string ;
' simple-search-prefix is search-prefix
: tib-full? ( max span addr pos addr' len' -- max span addr pos addr' len' flag )
5 pick over 4 pick + u< ;
: kill-prefix ( key -- key )
dup #tab <> over [ k-tab k-shift-mask or ]L <> and IF prefix-off THEN ;
\ UTF-8 support
require utf-8.fs
synonym setstring-color info-color
\ retype an edited line: this is generic, every word should use edit-update
\ and nothing else to redraw the edited string
: xedit-startpos ( -- )
\ correction for line=screenw, no wraparound then!
edit-curpos @ dup screenw @ mod 0= over 0> and \ flag, true=-1
dup >r + screenw @ /mod negate swap r> - negate swap at-deltaxy ;
: get-hw ( addr u -- lines rest )
screenw @ x-lines+rest setstring$ $@ screenw @ +x-lines+rest ;
: hw>width ( lines rest -- width ) swap screenw @ * + ;
: get-width+ ( addr u -- width )
get-hw hw>width ;
: get-width+all ( span addr pos -- width )
2dup get-hw 2>r >r swap r> safe/string
2r> 2swap screenw @ +x-lines+rest
hw>width ;
: .resizeline ( span addr pos -- span addr pos )
>r 2dup r@ get-width+all
dup >r edit-linew @ u< IF
xedit-startpos
edit-linew @ spaces edit-linew @ edit-curpos !
ELSE
r@ 1+ screenw @ / 0> IF
xedit-startpos 0 edit-curpos ! .unstatus THEN
THEN
r> edit-linew ! r> ;
: .all ( span addr pos -- span addr pos )
xedit-startpos 2dup type setstring$ $@
dup IF setstring-color type input-color ELSE 2drop THEN
>edit-rest type edit-linew @ edit-curpos ! ;
: .all-rest ( span addr pos -- span addr pos )
xedit-startpos 2dup get-width+ edit-curpos !
2dup type ;
: .rest ( span addr pos -- span addr pos )
dup fourth = IF
2dup get-width+ edit-curpos ! EXIT THEN
.all-rest ;
: xedit-update ( span addr pos1 -- span addr pos1 )
\ word to update the editor display
.resizeline .all
edit-linew @ 1+ screenw @ / 0> IF
2>r 2>r .status 2r> 2r> .all-rest
ELSE .rest THEN ;
: xhide ( max span addr pos1 -- max span addr pos1 f )
over 0 tuck default-color edit-update .unstatus 2drop drop false ;
\ In the following, addr max is the buffer, addr span is the current
\ string in the buffer, and pos1 is the cursor position in the buffer.
: xgrow-tib { max span addr pos1 more -- max span addr pos1 flag }
max span more + u>= IF max span addr pos1 true EXIT THEN
addr tib = IF
span #tib !
span more + max#tib @ 2* umax expand-tib
max#tib @ span tib pos1 true EXIT THEN
max span addr pos1 false ;
: (xins) ( max span addr pos1 xc -- max span addr pos2 )
dup >r xc-size grow-tib 0= IF rdrop edit-error EXIT THEN
>edit-rest over r@ xc-size + swap move
2dup chars + r@ swap r@ xc-size xc!+? 2drop drop
r> xc-size >r rot r@ chars + -rot r> chars + ;
: xback ( max span addr pos1 -- max span addr pos2 f )
dup IF
vt100-modifier @ IF
BEGIN 2dup + 1- c@ bl = over 0> and WHILE
over + xchar- over - REPEAT
BEGIN 2dup + 1- c@ bl <> over 0> and WHILE
over + xchar- over - REPEAT
ELSE
over + xchar- over -
THEN
0 max edit-update
ELSE edit-error THEN 0 ;
: xforw ( max span addr pos1 -- max span addr pos2 f )
third over <> IF
vt100-modifier @ IF
BEGIN third over u> >r 2dup + c@ bl = r> and WHILE
over + xchar+ over - REPEAT
BEGIN third over u> >r 2dup + c@ bl <> r> and WHILE
over + xchar+ over - REPEAT
ELSE
over + xchar+ over -
THEN
edit-update
ELSE edit-error THEN 0 ;
: (xdel) ( max span addr pos1 -- max span addr pos2 )
over + dup xchar- tuck - >r over -
>edit-rest over r@ + -rot move
rot r> - -rot ;
: xdel ( max span addr pos1 -- max span addr pos2 )
(xdel) edit-update ;
: ?xdel ( max span addr pos1 -- max span addr pos2 0 )
vt100-modifier @ IF
BEGIN dup WHILE
2dup 1- + c@ bl u<= WHILE (xdel) REPEAT THEN
BEGIN dup WHILE
2dup 1- + c@ bl u> WHILE (xdel) REPEAT THEN
edit-update
ELSE dup IF xdel THEN THEN 0 ;
: <xdel> ( max span addr pos1 -- max span addr pos2 0 )
vt100-modifier @ IF ?xdel EXIT THEN \ emacs binds Alt-Del to Alt-Backspace
third over <>
IF xforw drop xdel ELSE edit-error THEN 0 ;
: xeof third over or 0= IF -56 throw ELSE <xdel> THEN ;
: xfirst-pos ( max span addr pos1 -- max span addr 0 0 )
drop 0 xretype ;
: xend-pos ( max span addr pos1 -- max span addr span 0 )
drop over xretype ;
: xpaste! ( addr u -- )
paste$ $! ;
: xclear-rest ( max span addr pos -- max pos addr pos false )
>edit-rest paste! rot drop tuck xretype ;
: xclear-first ( max span addr pos -- max pos addr pos false )
2dup paste! >r
2dup swap r@ /string third swap move
swap r> - swap 0 xretype ;
: xins-string ( max span addr pos addr1 u1 -- max span' addr pos' )
2>r r@ grow-tib 0= IF edit-error 2rdrop EXIT THEN
>edit-rest 2r@ 2swap r@ + insert
r@ + rot r> + -rot rdrop ;
: (xenter) ( max span addr pos1 -- max span addr span true )
setstring$ $@ xins-string setstring$ $free
drop 2dup swap write-history
over edit-update edit-curpos-off true ;
: xeof' ( max span addr pos1 -- max span addr pos2 flag )
third over or 0= IF -56 throw ELSE (xenter) THEN ;
: xkill-expand ( max span addr pos1 -- max span addr pos2 )
prefix-found cell+ @ ?dup-IF dup
>r - >edit-rest over r@ + -rot move
rot r> - -rot THEN ;
?: insert ( string length buffer size -- )
rot over min dup >r - ( left over )
over dup r@ + rot move r> move ;
: (xtab-expand) ( max span addr pos1 -- max span addr pos2 0 )
xkill-expand 2dup extract-word dup 0= IF nip EXIT THEN
search-prefix tuck 2>r prefix-found @ 0<> - grow-tib
0= IF edit-error 2rdrop prefix-off 0 EXIT THEN
>edit-rest r@ + 2r> dup >r 2swap insert
r@ + rot r> + -rot
prefix-found @ IF bl (xins) THEN edit-update 0 ;
: xtab-expand ( max span addr pos1 -- max span addr pos2 0 )
key? IF #tab (xins) 0 EXIT THEN
(xtab-expand) ;
: xpaste@ ( -- addr u )
paste$ $@ ;
: xpaste ( max span addr pos -- max span' addr pos' false )
paste@ xins-string edit-update 0 ;
: xtranspose ( max span addr pos -- max span' addr pos' false )
dup IF
third over = IF over + xchar- over - THEN
2dup + xchar- xc@ >r (xdel)
over + xchar+ over - r> (xins)
THEN 0 ;
Variable setcur# \ relative to the end, in utf8 charactes
Variable setsel# \ size of selection relative to the end
: xback-chars ( addr len +n -- addr len' )
0 +DO x\string- dup 0<= ?LEAVE LOOP ;
: xchars>chars ( addr len +n -- len' )
>r tuck r> 0 +DO +x/string dup 0<= ?LEAVE LOOP nip - ;
: setcur ( max span addr pos1 -- max span addr pos2 )
drop over setcur# @ 0<= IF
setsel# @ setcur# @ - xback-chars
ELSE 2dup setcur# @ xchars>chars nip THEN ;
: setsel ( max span addr pos1 -- max span addr pos2 0 )
setstring$ $@ xins-string
setcur >r 2dup swap r@ safe/string
2dup 2dup setsel# @ xchars>chars nip tuck setstring$ $!
delete
swap setstring$ $@len - swap r> xretype ;
: xreformat ( max span addr pos1 -- max span addr pos1 0 )
.unstatus xedit-startpos input-color
edit-linew @ screenw @ /mod cols dup screenw ! * +
dup spaces dup edit-curpos ! edit-linew !
.resizeline .all 2>r 2>r .status 2r> 2r> .rest false ;
Create xchar-altkeys ( -- )
$80 0 [DO] ' false , [LOOP]
: altbindkey ( xt key -- )
dup $80 u>= abort" Alt+ASCII only!"
cells altkeys + ! ;
: xchar-altkey ( max span addr pos1 -- max span addr pos2 flag )
8 vt100-modifier ! false ;
: xdelw ( max span addr pos1 -- max span addr pos2 flag )
dup >r xforw drop >edit-rest r> -rot 2>r
tuck - >r 2dup + r@ paste! \ set paste$
rot r> - -rot \ update span
2r> 2over + swap move
edit-update false ;
: xfgcolor ( max span addr pos1 -- max span addr pos2 flag )
xreformat ;
: xbgcolor ( max span addr pos1 -- max span addr pos2 flag )
ekey-rgb rgb>mode xreformat ;
Create xchar-ctrlkeys ( -- )
' false , ' xfirst-pos , ' xback , ' false ,
' xeof , ' xend-pos , ' xforw , ' false ,
' ?xdel , ' xtab-expand , ' (xenter) , ' xclear-rest ,
' xreformat , ' (xenter) , ' next-line , ' false ,
' prev-line , ' false , ' false , ' setsel ,
' xtranspose , ' xclear-first , ' xpaste , ' false ,
' <xdel> , ' xpaste , ' xhide , ' xchar-altkey ,
' false , ' false , ' false , ' false ,
Create std-ekeys
' xback , ' xforw , ' prev-line , ' next-line ,
' xfirst-pos , ' xend-pos , ' prev-line , ' next-line ,
' false , ' <xdel> , ' (xenter) , ' false ,
' false , ' false , ' false , ' false ,
' false , ' false , ' false , ' false ,
' false , ' false , ' false , ' xreformat ,
' xhide , ' false , ' prev-line , ' next-line ,
' ?xdel , ' xtab-expand , ' setsel , ' xfgcolor ,
' xbgcolor , ' xeof' ,
: xchar-edit-ctrl ( max span addr pos1 ekey -- max span addr pos2 flag )
dup mask-shift# rshift 7 and vt100-modifier !
dup 1 mask-shift# lshift 1- and swap keycode-start u>= IF
cells ekeys + perform EXIT THEN
dup $80 $20 vt100-modifier @ 2 and select
u>= IF drop false EXIT THEN
cells altkeys ctrlkeys vt100-modifier @ 2 and select
+ perform ;
: xins ( max span addr pos1 char -- max span addr pos2 )
vt100-modifier @ 8 and IF
2 mask-shift# lshift or xchar-edit-ctrl drop
ELSE (xins) THEN ;
: xchar-history ( -- )
edit-terminal edit-out ! ;
: xeveryline ( -- )
edit-curpos-off key? drop \ set terminal into raw mode
term-rgb? 1 and IF s\" \e]10;?\a" type THEN
term-rgb? 2 and IF s\" \e]11;?\a" type THEN
0 to term-rgb? ;
xchar-history
' xins IS insert-char
' xins-string IS insert-string
' kill-prefix IS everychar
' xeveryline IS everyline
' xedit-update IS edit-update
' xpaste! IS paste!
' xpaste@ IS paste@
' xgrow-tib IS grow-tib
' xchar-ctrlkeys IS ctrlkeys
' xchar-altkeys IS altkeys
' bell IS edit-error
' std-ekeys IS ekeys
' xchar-edit-ctrl IS edit-control
' xback 'b' altbindkey
' xdelw 'd' altbindkey
' xforw 'f' altbindkey
\ initializing history
: get-history ( addr len -- )
['] force-open catch-nobt
?dup-if
\ !! >stderr
\ history-file type ." : " .error cr
drop 2drop 0 to history
else
to history
history file-size throw
2dup forward^ 2! 2dup backward^ 2! end^ 2!
endif
;
: history-cold ( -- )
history-file get-history xchar-history edit-curpos-off ;
:noname ( -- )
defers bootmessage
history-cold
; is bootmessage
history-cold