Author: Virgil Dupras <email@example.com>
Date: Mon, 26 Jun 2023 07:06:25 -0400
text/pager: stop relying on Pipe filters
I'm getting rid of "chain" (and Pipe probably) and the pager is the only user
of this mechanism. More details in following commits.
3 files changed, 40 insertions(+), 37 deletions(-)
diff --git a/fs/doc/text/pager.txt b/fs/doc/text/pager.txt
@@ -1,36 +1,35 @@
-Prerequisites: sys/io, sys/grid
+Prerequisites: sys/io, sys/grid, sys/loop
Pagers are a way to interactively control an IO stream. For now, there is only
-one page implementation, the "spager" (for Serial Pager), that is, the lowest
-common denominator, paging-wise. It doesn't require a Grid and simply inserts a
-"Next page..." line at regular intervals, waiting for user input before
-continuing. Pressing any key shows the next page, pressing ESC calls "quit"
-(this generally returns to prompt).
+one page implementation in text/pager. It's a "serial pager", that is, the
+lowest common denominator, paging-wise. It doesn't require a Grid and simply
+inserts a "Next page..." line at regular intervals, waiting for user input
+before continuing. Pressing any key shows the next page, pressing ESC calls
+"abort" (this generally returns to prompt).
-The pager is implemented as a set of Pipe filters and can be hooked to any Pipe
-but will generally be hooked to the Console, with its "input" companion on the
-"in" side of it. What this companion does is to reset the pager threshold any
-time a key is requested. This way, the pager will only be activated when there's
-a lot of contents to spit *at once*. It will not be activated for commands with
+The page works through the "page" word. For example:
-For now, the pager counter is global.
+ page console :self file :spit
+This will spit the currently active file to the console while paging. This works
+by temporarily overriding "console writeio" with a line counter.
+The trick is to know when to remove that override: we only want "page" to affect
+the command we're about to run, not to begin paging the console forever.
+To do this, we use the Idle loop (sys/loop). That is, we add a pager removal
+word in the the idle loop, which will be called as soon as we return to
+This means that the pager will not play well with any word that calls the idle
+loop. When that becomes a real problem, we'll think of something...
pagerthreshold Value holding the number of lines the pager accepts before
showing its "Next page..." prompt. Default is 20.
-spagerwrite ( a n hdl -- a n hdl )
- Filters :writebuf so that writes happen line by line (LF-separated). At each
- line, increase the line counter. If it reaches pagerthreshold, print "Next
- page..." and wait for a keypress. If that key is ESC, quits, otherwise, reset
- the line counter and continue.
-spagerread ( n hdl -- n hdl )
- Resets the line counter.
-spager$ ( -- )
- Install Serial pager filters on the Console
+page ( -- )
+ Make the console page until the next idle loop runs.
diff --git a/fs/text/pager.fs b/fs/text/pager.fs
@@ -1,19 +1,24 @@
0 value _cnt
20 value pagerthreshold
+0 value baseio
-: spagerread ( n hdl -- n hdl ) 0 to _cnt ;
+: err abort" pager error" ;
-create _nextpage ," Next Page...\n"
-: spagerwrite ( a n hdl -- a n hdl )
- [ CELLSZ neg [rcnt] ! ] >r ( a n ) \ V1=nextword V2=hdl
- _cnt pagerthreshold = if
- 0 to _cnt
- _nextpage 13 V2 V1 execute 13 <> if abort" pager error" then
- key ESC = if quit then then
- 2dup LF rot> cidx if ( a n idx )
- to1+ _cnt nip 1+ ( a n ) then r> ;
+: _reset baseio if 0 to@! baseio to console writeio then ;
+' _reset loopadd
- ['] spagerread console :addrfilter ['] spagerwrite console :addwfilter ;
+: waitkey 0 to@! baseio key swap to baseio ;
+: _writebuf ( a n hdl -- written-n )
+ drop _cnt pagerthreshold = if
+ 0 to _cnt S" Next Page...\n" baseio IO :puts
+ waitkey ESC = if abort then then
+ 2dup LF rot> cidx if ( a n idx ) to1+ _cnt nip 1+ then ( a n )
+ baseio IO :writebuf ;
+: _flush drop baseio IO :flush ;
+create WriteIO 0 , ' err , ' _writebuf , ' _flush , ' err ,
+: page 0 to _cnt WriteIO to@! console writeio to baseio ;
diff --git a/fs/xcomp/init.fs b/fs/xcomp/init.fs
@@ -5,5 +5,4 @@ f<< /lib/fmt.fs
-\ we don't automatically call spager$ in init because of automated tests,
: init S" Dusk OS\n" stype .free rdln$ stdio$ quit ;