#!/usr/bin/env retro ================================================================ _ _ _ _ | |_ __ _| | ____ ___ _(_)_ __(_) crc's new listener for | __/ _` | |/ / _` \ \ /\ / / | '__| | RetroForth | || (_| | < (_| |\ V V /| | | | | \__\__,_|_|\_\__,_| \_/\_/ |_|_| |_| ** UNDER DEVELOPMENT ** ================================================================ # Background The current generation of RetroForth did not start off as a traditional, interactive Forth. A minimal (and lightly expanded) REPL simply called the listener has existed, but it is not a user friendly system. Takawiri is a new listener. I've been slowly working on it, with a goal of growing it into something useful. At present it is functional, but many pieces remain. (See the end of this document for a partial list). # The Interface Takawiri presents a fullscreen interface. This has a large area for the display (the "text output buffer", or TOB) with a set of introspection views on the right. At the bottom is the text input area. +-----------------------------------------+----------------+ | Text Output Buffer | Introspection | | | | | | | | +----------------+ | | Stack Display | | | | | | | | +----------------+ | | String Preview | | | | | | | | +----------------+ | | Watched Vars | | | | | | | +-----------------------------------------+----------------+ | input area | +----------------------------------------------------------+ # Startup & Dependencies Takawiri requires RetroForth 2024.9 or newer, with the ioctl device enabled. It also requires a terminal with 100 or more columns and at least 27 rows. I do the initial configuration, and check these, reporting any errors and exiting if necessary. ~~~ @Version #202409 lt? [ 'Requires_RetroForth_2024.9_or_newer s:put nl bye ] if ~~~ Setup the local terminal dimensions. This uses the `ioctl:` words added in RetroForth 2024.9. ~~~ ioctl:term-size (rows,cols) 'LT:W const 'LT:H const LT:W #100 lt? [ 'Terminal_too_narrow! s:put nl bye ] if LT:H #27 lt? [ 'Terminal_too_short! s:put nl bye ] if ~~~ Setup the text output buffer dimensions. The width is currently fixed at 80 columns; the height is set based on the terminal height. ~~~ #80 'TOB:W const (:-n) LT:H #2 - 'TOB:H const (:-n) ~~~ Load dependencies from the library. ~~~ { 'konilo 'termina 'tob } &library:load a:for-each ~~~ # Configure UI Colors ~~~ :dss:label (:-) fg:red ; :dss:value (:-) fg:yellow ; :dss:sep (:-) fg:cyan ; :dss:prompt (:-) bg:blue fg:white ; ~~~ # Utilities I intend for takawiri to provide a variety of useful tools to aid in using RetroForth interactively. ~~~ :,stack (:s-) d:lookup d:stack fetch s:put nl ; ~~~ # UI First are words to display the text output buffer. ~~~ :bar:right (:-) dss:sep TOB:H n:inc [ I n:inc TOB:W #2 n:add vt:row,col $| c:put ] indexed-times vt:reset ; :bar:bottom (:-) dss:sep TOB:H n:inc #1 vt:row,col TOB:W n:inc [ $= c:put ] times $+ c:put vt:reset ; :display:tob (:-) tob:display bar:right bar:bottom ; ~~~ Draw the section separators. ~~~ :length (:-n) LT:W TOB:W #4 n:add n:sub ; :--- (:n-) [ $- c:put ] times sp ; :sections (:-) dss:sep #3 [ I n:inc #6 n:mul TOB:W #4 n:add vt:row,col length --- ] indexed-times vt:reset ; ~~~ ~~~ 'Items d:create #0 comma #32 allot :tos? (:nm-nmf) over n:zero? ; :dss (:-) [ depth #5 n:min !Items &Items fetch-next &store-next times drop &Items a:reverse [ ] a:for-each #0 &Items [ over n:inc #6 n:add #84 vt:row,col dss:label tos? [ 'TOS:___ s:put ] [ '_______ s:put ] choose vt:reset n:put n:inc ] a:for-each drop ] gc ; ~~~ ## String Preview This is the start of code to display temporary strings on the data stack. The plan is to have it show below the stack values, in a format like: The data will match up to the values in the stack disp. Note: this won't be useful until after the alternate `s:evaluate` is done. ~~~ {{ :string? (v-vf) dup STRINGS gt? ; :display over n:inc #12 n:add #84 vt:row,col fg:red tos? [ 'TOS:___ s:put ] [ '_______ s:put ] choose vt:reset s:put ; :not-string over n:inc #12 n:add #84 vt:row,col fg:blue '_______n/a s:put drop vt:reset ; ---reveal--- :strings (:-) #0 &Items [ string? &display ¬-string choose n:inc ] a:for-each drop ; }} ~~~ ~~~ :layout:stat,col (:-n) #84 ; :layout:stat (:sn-) layout:stat,col vt:row,col dss:label s:put dss:value ; :stats (:-) 'HERE:__ #1 layout:stat here n:put 'FREE:__ #2 layout:stat FREE n:put 'DEPTH:_ #3 layout:stat depth n:put 'ROW:___ #4 layout:stat @TY n:put 'COL:___ #5 layout:stat @TX n:put vt:reset ; :prompt (:-) dss:prompt LT:H #1 vt:row,col LT:W [ sp ] times LT:H #1 vt:row,col '>>_ s:put ; ~~~ ~~~ :quit (:-) ioctl:set-lbreak vt:reset bye ; :bye (:-) quit ; ~~~ # Watchlist The watchlist will allow monitoring a small number of addresses in the right panel of the interface. A use case might be to do something like: &Base 'Base watch &Compiler 'Compiler watch ~~~ 'Watchlist d:create #5 , #-1 , #-1 , #-1 , #-1 , #-1 , 'WatchlistLabels d:create #5 , #-1 , #-1 , #-1 , #-1 , #-1 , :watchlist:find (:a-n) dup &Watchlist a:contains? [ drop #-1 ] -if; &Watchlist swap a:index ; :watchlist:make-label (:s-s) dup s:length #8 gt? [ #8 s:left ] if dup s:length #8 lt? [ dup s:length #8 swap n:sub [ '_ s:append ] times ] if s:keep ; :watch (:as-) watchlist:make-label #-1 watchlist:find &Watchlist &WatchlistLabels 'abcde 'adcbec reorder a:store a:store ; :unwatch (:a-) watchlist:find dup n:positive? &drop -if [ &Watchlist #-1 'abc 'acab reorder a:store ] [ &WatchlistLabels #-1 'abc 'acab reorder a:store ] bi ; :watchlist (:-) #19 #5 [ dup #84 vt:row,col dss:label &WatchlistLabels over #19 n:sub a:fetch dup #-1 -eq? [ s:put sp ] [ drop '_________ s:put ] choose dss:value &Watchlist over #19 n:sub a:fetch dup n:positive? [ fetch ] [ drop #0 ] choose n:put n:inc vt:reset ] times drop ; ~~~ ~~~ :ui (:-) &err:notfound unhook ioctl:set-cbreak &banner tob:with [ vt:reset vt:clear vt:home display:tob sections stats dss strings watchlist prompt s:get-word vt:reset [ dup s:put sp interpret ] tob:with ] forever ; ui ~~~ ================================================================ Things needed: - termios device & words (or add termios to unix device?) - colors for interface elements - refactor & document everything - line editing ================================================================