duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit e1549c08a2cd75d6837bb3f1cd8a32aef7f11cf5
parent eb8f7b80f4634073e0edc15b53c082c0ad7c2f25
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Mon,  6 Feb 2023 22:18:59 -0500

text/ged: add visual mode

Also, rename text/ed's "convenience layer" to avoid clashes with "i" and "j".

Diffstat:
Mfs/doc/text/ed.txt | 50+++++++++++++++++++++++++++++++-------------------
Mfs/doc/text/ged.txt | 21++++++++++++++++-----
Mfs/tests/text/ed.fs | 18+++++++++---------
Mfs/text/ed.fs | 26+++++++++++++++++---------
Mfs/text/ged.fs | 22++++++++++++++++++----
5 files changed, 91 insertions(+), 46 deletions(-)

diff --git a/fs/doc/text/ed.txt b/fs/doc/text/ed.txt @@ -22,6 +22,16 @@ Layer. Because these shortcut can clash with other words in the system, it is recommended to load the text editor in its own context. +## Mark API + +A Mark's purpose is to remember a particular position. For now, it's not used +much. There is a global "mark" structbind to a single Mark. + +Fields: + +lpos Line position (index) +cpos Character position + ## Line API The Line structure describes a line in the Ed buffer. It is a linked list. The @@ -142,22 +152,27 @@ Words: :insertline ( self -- ) Insert a new empty line before selection. +:mark! ( self -- ) + Set "mark" structbind to buffer's current position. + ## Convenience layer The convenience layer is a collection of words with short names that makes interacting with the API above easier. Its choice of name is broadly inspired by UNIX's "vi" program. -The "input" words ("a" and "i") work in a peculiar way because they consume the -rest of the input line. For example, let's say that you type this: +The "input" words ("I", "o", "O") work in a peculiar way because they consume +the rest of the input line. For example, let's say that you type this: - foo bar i Hello there + foo bar I Hello there -"foo", "bar" and "i" will be interpreted normally, but "Hello there" will be +"foo", "bar" and "I" will be interpreted normally, but "Hello there" will be copied without going through the interpreter. The content is then sent to the buffer with :puts. The LF character is not sent (otherwise, every insert operation would result in a new line being inserted). +"I" is used instead of "i" to avoid shadowing the iterator loop variable. + ### API Values: @@ -174,7 +189,7 @@ s ( -- ) Print "stats", that is, the current line with :cprint followed by another line with "current lineno" / "line count". -i ( "...\n" -- ) +I ( "...\n" -- ) Insert typed line before the current one and select it. o ( "...\n" -- ) @@ -189,36 +204,33 @@ f ( "...\n" -- ) n ( -- ) Repeat the last find -d ( n -- ) - Delete "n" lines starting from the current one. +dl ( n -- ) + Delete "n" lines starting from current pos. + +dc ( n -- ) + Delete "n" characters starting from current pos. g ( lineno -- ) Select line number "lineno" -h ( n -- ) +c- ( n -- ) Go "n" characters to the left. -H ( -- ) +bol ( -- ) Go to the beginning of the line. -l ( n -- ) +c+ ( n -- ) Go "n" characters to the right. -L ( -- ) +eol ( -- ) Go to the end of the line. -j ( n -- ) +l- ( n -- ) Go "n" lines up. -k ( n -- ) +l+ ( n -- ) Go "n" lines down. -{ ( -- ) - Go one "page" up. - -} ( -- ) - Go one "page" down. - eof ( -- ) Go to the last line of the buffer. diff --git a/fs/doc/text/ged.txt b/fs/doc/text/ged.txt @@ -18,17 +18,28 @@ enters the grid keybindings loop. Keybindings are rudimentary, but you have the ":" binding allowing you to quickly enter fancier commands (example "i hello"). -## Keybindings +## Visual mode -Some key bindings map directly to their the text/ed convenience word of the same -name, with the same behavior. Those are: +Pressing "v" toggles the visual mode. When toggled on, current position is +marked and when moving selection afterwards, the range between the mark and the +selection is shown visually. - h j k l H L i f n o O +For now, it doesn't do anything else, but soon enough it will be very powerful. -Others have this behavior: +## Keybindings q Quit +h Go left +j Go down +k Go up +l Go right +i Insert +o Insert line after +O Insert line before +f Find +n Find next z zoom. Reframe the editor so that selection is in the middle of the screen. +v Toggle visual mode ] move 1 page down [ move 1 page up : enter a single line of command that will be interpreted as forth diff --git a/fs/tests/text/ed.fs b/fs/tests/text/ed.fs @@ -10,21 +10,21 @@ edbuf :linecnt 1 #eq edbuf :linecnt 1 #eq f" /tests/txtfile" edload 1 g -5 capture l +5 capture c+ S" with some text\n ^\n1 / 17" #s= -7 capture j +7 capture l+ S" be\n ^\n8 / 17" #s= -5 capture k +5 capture l- S" (oh well maybe grow)\n ^\n3 / 17" #s= -capture L +capture eol S" (oh well maybe grow)\n ^\n3 / 17" #s= -capture H +capture bol S" (oh well maybe grow)\n^\n3 / 17" #s= -4 l 5 capture dc +4 c+ 5 capture dc S" (oh maybe grow)\n ^\n3 / 17" #s= 2 capture dl S" tests that process text\n ^\n3 / 15" #s= -L capture i abc +eol capture I abc S" tests that process textabc\n ^\n3 / 15" #s= capture o appended line S" appended line\n ^\n4 / 16" #s= @@ -34,8 +34,8 @@ S" inserted line\n ^\n4 / 17" #s= S" with some text\n ^\n0 / 16" #s= 0 g capture O at the beginning of the buf S" at the beginning of the buf\n ^\n0 / 17" #s= -17 j edbuf lpos 16 #eq -1 j edbuf lpos 16 #eq +17 l+ edbuf lpos 16 #eq +1 l+ edbuf lpos 16 #eq \ Now let's save this to a BlobFile 2 const TOTSEC diff --git a/fs/text/ed.fs b/fs/text/ed.fs @@ -5,6 +5,12 @@ : nspcs ( n -- ) for spc> next ; +struct[ Mark + sfield lpos + sfield cpos +]struct +here Mark SZ allot0 structbind Mark mark + struct[ Line sfield _next sfield cnt @@ -129,6 +135,8 @@ extends IO struct[ Edbuf V1 sel llitern ( delpoint tgt ) tuck swap ( tgt tgt prev ) ! ( tgt ) ?dup not if V1 lines llend then r> _sel! ; + + : :mark! ( self -- ) dup lpos to mark lpos cpos to mark cpos ; ]struct Edbuf :new structbind Edbuf edbuf @@ -142,20 +150,20 @@ Edbuf :new structbind Edbuf edbuf : ?s print? if s then ; : g ( n -- ) edbuf :go ?s ; -: h ( n -- ) edbuf :goleft ?s ; -: H ( -- ) $10000 h ; -: l ( n -- ) edbuf :goright ?s ; -: L ( -- ) $10000 l ; -: j ( n -- ) edbuf :godown ?s ; -: k ( n -- ) edbuf :goup ?s ; +: c- ( n -- ) edbuf :goleft ?s ; +: bol ( -- ) $10000 c- ; +: c+ ( n -- ) edbuf :goright ?s ; +: eol ( -- ) $10000 c+ ; +: l+ ( n -- ) edbuf :godown ?s ; +: l- ( n -- ) edbuf :goup ?s ; : p ( -- ) pagesz edbuf :print ; : dc ( n -- ) edbuf :delchars ?s ; : dl ( n -- ) edbuf :dellines ?s ; -: i console :readline edbuf :puts ?s ; +: I console :readline edbuf :puts ?s ; : f console :readline edbuf :find ?s ; : n edbuf :findnext ?s ; -: o edbuf :appendline i ; -: O edbuf :insertline i ; +: o edbuf :appendline I ; +: O edbuf :insertline I ; : edload ( -- ) 0 file :seek edbuf :empty edbuf :self file :spit edbuf _sel$$ ; diff --git a/fs/text/ged.fs b/fs/text/ged.fs @@ -4,6 +4,9 @@ require /sys/grid.fs ?f<< /lib/wordtbl.fs grid LINES 1- const _height +grid COLS grid LINES * 1- const _maxpos +0 value visualmode +0 value _top : _spitline ( pos line -- ) swap grid :spiton @@ -11,12 +14,21 @@ grid LINES 1- const _height dup if swap Line ptr over grid :write else nip then ( n ) grid COLS -^ ?dup if nspcs then grid :spitoff ; +: _scrpos ( pos -- pos ) _top grid COLS * - max0 _maxpos min ; + +: _clrhighlight ( -- ) 0 _maxpos 1+ for2 0 i grid :highlight next ; + +: _highlight ( -- ) + _clrhighlight + mark lpos grid COLS * mark cpos + _scrpos + edbuf lpos grid COLS * edbuf cpos + _scrpos + ?swap for2 1 i grid :highlight next ; + : _spitpage ( fromline -- ) 0 swap _height for ( lineno line ) dup if over grid COLS * over _spitline else over grid :clrline then dup if llnext then swap 1+ swap next 2drop ; -0 value _top : _top! ( lineno -- ) dup to _top edbuf lines Line :itern nip _spitpage ; @@ -25,7 +37,8 @@ grid LINES 1- const _height _height 1- - max0 _top over <= if _top! else drop then then ; : _refresh ( -- ) - _reframe edbuf lpos _top - grid COLS * edbuf cpos + grid :pos! ; + _reframe edbuf lpos _top - grid COLS * edbuf cpos + grid :pos! + visualmode if _highlight then ; : _statusclr _height grid :clrline ; : _statusline _statusclr _height grid COLS * grid :pos! ; @@ -34,7 +47,7 @@ grid LINES 1- const _height : _rdln[] rdln :range 1- ; : _pagerefresh _top _top! ; -S" qhjklHLifnoOz[]:" const KEYS +S" qhjklHLifnoOzv[]:" const KEYS KEYS c@ wordtbl handlers :w _statusline quit ; :w 1 edbuf :goleft ; @@ -49,10 +62,11 @@ KEYS c@ wordtbl handlers :w _typeline if edbuf :appendline _rdln[] edbuf :write then _pagerefresh ; :w _typeline if edbuf :insertline _rdln[] edbuf :write then _pagerefresh ; :w edbuf lpos _height >> - max0 _top! ; +:w visualmode not to visualmode edbuf :mark! _pagerefresh _clrhighlight ; :w pagesz edbuf :goup ; :w pagesz edbuf :godown ; :w _typeline _statusline if rdln :interpret then _pagerefresh ; -: ged 0 to _top begin +: ged 0 to _top 0 to visualmode begin _refresh key KEYS c@+ [c]? ( idx ) dup 0>= if handlers swap wexec else drop then again ;