add block-editor
to the library
FossilOrigin-Name: e7489651739c0ea870c3fddd687ef44cc20d73686b01a35091147f075420297b
This commit is contained in:
parent
5ed4511bb9
commit
a5e61c80ad
3 changed files with 241 additions and 11 deletions
|
@ -56,5 +56,6 @@
|
|||
the device handlers
|
||||
- support loading extensions at runtime via `library:load`
|
||||
(searches ./library/ and ~/.config/retroforth/library/)
|
||||
- library contents: block-editor x11
|
||||
|
||||
================================================================
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
This is a port of the RetroForth/ilo block editor to
|
||||
RetroForth/nga. Much of this will be the same as the original
|
||||
implementation, but there are some differences.
|
||||
This is a port of the Konilo block editor to RetroForth. Much of
|
||||
this will be the same as the original implementation, but there
|
||||
are a few small differences.
|
||||
|
||||
Retro/nga provides three words for interfacing with a block
|
||||
RetroForth provides three words for interfacing with a block
|
||||
store:
|
||||
|
||||
block:set-file (s-)
|
||||
|
@ -19,13 +19,13 @@ This begins by using these to implement the `block:load` and
|
|||
:block:save block:write ;
|
||||
~~~
|
||||
|
||||
In Retro/ilo, the memory is constrained to 65,536 cells, with a
|
||||
In Konilo, the memory is constrained to 65,536 cells, with a
|
||||
defined memory map. Since Retro/nga does not do this, the block
|
||||
buffer is allocated inline.
|
||||
|
||||
Additionally, under Retro/ilo, the cell preceeding the block
|
||||
buffer is used as a count. I allocate two extra cells and patch
|
||||
the block buffer starting address manually.
|
||||
Additionally, under Konilo, the cell preceeding the block buffer
|
||||
is used as a count. I allocate two extra cells and patch the
|
||||
block buffer starting address manually.
|
||||
|
||||
~~~
|
||||
'block:buffer d:create #1026 allot
|
||||
|
@ -130,9 +130,8 @@ blocks.
|
|||
|
||||
To run the code in the block buffer, execute `run`.
|
||||
|
||||
This makes use of `s:evaluate` from Retro/ilo, where strings
|
||||
are arrays. In the future, Retro/nga will have native support
|
||||
for strings-as-arrays, and then this can be simplified.
|
||||
This makes use of `s:evaluate` from Konilo, where strings are
|
||||
arrays.
|
||||
|
||||
~~~
|
||||
{{
|
||||
|
|
230
library/block-editor.retro
Normal file
230
library/block-editor.retro
Normal file
|
@ -0,0 +1,230 @@
|
|||
This is a port of the Konilo block editor to RetroForth. Much of
|
||||
this will be the same as the original implementation, but there
|
||||
are a few small differences.
|
||||
|
||||
RetroForth provides three words for interfacing with a block
|
||||
store:
|
||||
|
||||
block:set-file (s-)
|
||||
block:read (na-)
|
||||
block:write (na-)
|
||||
|
||||
This begins by using these to implement the `block:load` and
|
||||
`block:save`. The initial block store is set to `ilo.blocks`.
|
||||
|
||||
~~~
|
||||
'ilo.blocks block:set-file
|
||||
|
||||
:block:load block:read ;
|
||||
:block:save block:write ;
|
||||
~~~
|
||||
|
||||
In Konilo, the memory is constrained to 65,536 cells, with a
|
||||
defined memory map. Since Retro/nga does not do this, the block
|
||||
buffer is allocated inline.
|
||||
|
||||
Additionally, under Konilo, the cell preceeding the block buffer
|
||||
is used as a count. I allocate two extra cells and patch the
|
||||
block buffer starting address manually.
|
||||
|
||||
~~~
|
||||
'block:buffer d:create #1026 allot
|
||||
&block:buffer n:inc @Dictionary d:xt store
|
||||
~~~
|
||||
|
||||
Variables to track the current block and the number of blocks
|
||||
are provided. Alter the `Blocks` count to match your actual
|
||||
data store limits.
|
||||
|
||||
~~~
|
||||
'Block var
|
||||
#128 'Blocks var-n
|
||||
~~~
|
||||
|
||||
`e:line` displays a line from the block buffer.
|
||||
|
||||
~~~
|
||||
:e:line (n-)
|
||||
#64 n:mul block:buffer n:add
|
||||
#64 [ fetch-next c:put ] times drop nl ;
|
||||
~~~
|
||||
|
||||
|
||||
:e:for-each-line (q-)
|
||||
#16 [ block:buffer I #64 n:mul #64 s:middle swap &call sip ]
|
||||
indexed-times drop ;
|
||||
|
||||
~~~
|
||||
{{
|
||||
:sep sp sp sp #6 [ '+----5---- s:put ] times '+--- s:put nl ;
|
||||
:l/n I dup #10 lt? &sp if n:put sp ;
|
||||
:line l/n I e:line ;
|
||||
:lines #16 &line indexed-times ;
|
||||
:block# 'Editing_# s:put @Block n:put
|
||||
'_of_ s:put @Blocks n:dec n:put nl ;
|
||||
---reveal---
|
||||
:list* nl #16 [ I e:line ] indexed-times ;
|
||||
:list# nl lines ;
|
||||
:list nl sep lines sep block# ;
|
||||
}}
|
||||
~~~
|
||||
|
||||
The next several words are for navigating through and saving
|
||||
blocks.
|
||||
|
||||
+------+----+----------------------------------------------+
|
||||
| Word | | Description |
|
||||
+======+====+==============================================+
|
||||
| set | n- | Set the current block to 'n' |
|
||||
| load | | (Re)load the current block |
|
||||
| next | | Load the next block |
|
||||
| prev | | Load the previous block |
|
||||
| new | | Erase the contents of the block buffer |
|
||||
| edit | n- | Set the current block to 'n', load & list it |
|
||||
+------+----+----------------------------------------------+
|
||||
|
||||
~~~
|
||||
&list 'e:Display var-n
|
||||
{{
|
||||
:constrain @Block #0 @Blocks n:dec n:limit !Block ;
|
||||
---reveal---
|
||||
:set &Block store constrain ;
|
||||
:save &Block fetch block:buffer block:save ;
|
||||
:load &Block fetch block:buffer block:load ;
|
||||
:next &Block v:inc constrain load ;
|
||||
:prev &Block v:dec constrain load ;
|
||||
:new block:buffer #1024 [ #32 swap store-next ] times drop ;
|
||||
:edit set load @e:Display call ;
|
||||
}}
|
||||
~~~
|
||||
|
||||
~~~
|
||||
:e:to-line #64 n:mul block:buffer n:add ;
|
||||
:e:erase/line
|
||||
e:to-line #32 swap #64 [ dup-pair store n:inc ] times
|
||||
drop-pair ;
|
||||
:e:replace &e:to-line dip [ over store n:inc ] s:for-each drop ;
|
||||
:e:replace-at [ &e:to-line dip n:add ] dip
|
||||
[ over store n:inc ] s:for-each drop ;
|
||||
|
||||
:e:insert dup e:erase/line s:get e:replace ;
|
||||
:e:insert-at s:get e:replace-at ;
|
||||
|
||||
:0 #0 e:insert ;
|
||||
:1 #1 e:insert ;
|
||||
:2 #2 e:insert ;
|
||||
:3 #3 e:insert ;
|
||||
:4 #4 e:insert ;
|
||||
:5 #5 e:insert ;
|
||||
:6 #6 e:insert ;
|
||||
:7 #7 e:insert ;
|
||||
:8 #8 e:insert ;
|
||||
:9 #9 e:insert ;
|
||||
:10 #10 e:insert ;
|
||||
:11 #11 e:insert ;
|
||||
:12 #12 e:insert ;
|
||||
:13 #13 e:insert ;
|
||||
:14 #14 e:insert ;
|
||||
:15 #15 e:insert ;
|
||||
~~~
|
||||
|
||||
To run the code in the block buffer, execute `run`.
|
||||
|
||||
This makes use of `s:evaluate` from Konilo, where strings are
|
||||
arrays.
|
||||
|
||||
~~~
|
||||
{{
|
||||
'max-length var
|
||||
'source var
|
||||
'index var
|
||||
'token d:create #65 allot
|
||||
|
||||
:eoi? &index &max-length &fetch bi@ gt? ;
|
||||
:eow? &token fetch &token n:add fetch
|
||||
[ #32 eq? ] [ #0 eq? ] bi or ;
|
||||
:set-input
|
||||
#0 &index store
|
||||
[ &source store ] [ a:length &max-length store ] bi ;
|
||||
:get-char
|
||||
&source fetch &index fetch a:fetch
|
||||
&token v:inc &index v:inc
|
||||
&token fetch &token n:add store ;
|
||||
:parse-word
|
||||
#0 &token store
|
||||
[ get-char eow? eoi? or ] until
|
||||
&token dup v:dec ;
|
||||
:count-words #1 swap [ #32 eq? &n:inc if ] a:for-each ;
|
||||
:valid? dup a:length n:-zero? ;
|
||||
:s:evaluate
|
||||
&set-input &count-words bi
|
||||
[ parse-word valid? [ a:to-string interpret ] &drop choose ] times ;
|
||||
---reveal---
|
||||
:run &block:buffer n:dec #1024 over store s:evaluate ;
|
||||
}}
|
||||
~~~
|
||||
|
||||
+-------+-----+--------------------------------------------+
|
||||
| Word | | Description |
|
||||
+=======+=====+============================================+
|
||||
| use | n- | Load and run the code in block "n" |
|
||||
| using | fl- | Load and run the code in blocks "f" to "l" |
|
||||
+-------+-----+--------------------------------------------+
|
||||
|
||||
~~~
|
||||
:use (block) set load run ;
|
||||
|
||||
:using (first,last)
|
||||
over n:sub swap set load run [ next run ] times ;
|
||||
~~~
|
||||
|
||||
|
||||
`titles` iterates through the blocks, displaying the title
|
||||
(first line) of any block that does not start with a blank
|
||||
space.
|
||||
|
||||
~~~
|
||||
{{
|
||||
:setup #64 block:buffer n:dec store ;
|
||||
:has-description? block:buffer fetch #32 -eq? ;
|
||||
:display [ I n:put tab #0 e:line ] if ;
|
||||
:describe I set load has-description? display ;
|
||||
:save &Block fetch ;
|
||||
:restore &Block store load ;
|
||||
---reveal---
|
||||
:titles save setup @Blocks &describe indexed-times restore ;
|
||||
}}
|
||||
~~~
|
||||
|
||||
`needs` takes a string with a block identifier and loads/runs
|
||||
code in any block matching this. Example:
|
||||
|
||||
'(doubles) needs
|
||||
|
||||
Would load any blocks containing "(doubles)" as the initial
|
||||
token in their index line. Tokens after the first one are
|
||||
ignored. So the above would match:
|
||||
|
||||
(doubles) (constants)
|
||||
(doubles) (variables)
|
||||
|
||||
but not:
|
||||
|
||||
(singles) (constants)
|
||||
|
||||
~~~
|
||||
{{
|
||||
'Hash var
|
||||
:reset #64 block:buffer n:dec store ;
|
||||
:actual block:buffer n:dec dup #32 a:index a:left a:to-string ;
|
||||
:code? block:buffer fetch $( eq? ;
|
||||
---reveal---
|
||||
:needs (s-)
|
||||
@Hash [ @Block swap
|
||||
s:hash !Hash
|
||||
@Blocks [ I set load reset code?
|
||||
[ actual s:hash @Hash eq?
|
||||
&run if ] if ] indexed-times
|
||||
!Block load ] dip !Hash ;
|
||||
}}
|
||||
~~~
|
Loading…
Reference in a new issue