about summary refs log tree commit diff stats
path: root/081print.mu
diff options
context:
space:
mode:
Diffstat (limited to '081print.mu')
-rw-r--r--081print.mu108
1 files changed, 88 insertions, 20 deletions
diff --git a/081print.mu b/081print.mu
index ff6cf5c0..465d228a 100644
--- a/081print.mu
+++ b/081print.mu
@@ -1,5 +1,16 @@
 # Wrappers around print primitives that take a 'screen' object and are thus
 # easier to test.
+#
+# Screen objects are intended to exactly mimic the behavior of traditional
+# terminals. Moving a cursor too far write wraps it to the next line,
+# scrolling if necessary. The details are subtle:
+#
+# a) Rows can take unbounded values, and such values are preserved rather than
+# clamped or wrapped around.
+#
+# b) If you print to a square (row, right) on the right margin, the cursor
+# position depends on whether 'row' is in range. If it is, the new cursor
+# position is (row+1, 0). If it isn't, the new cursor position is (row, 0).
 
 container screen [
   num-rows:num
@@ -7,6 +18,7 @@ container screen [
   cursor-row:num
   cursor-column:num
   data:&:@:screen-cell  # capacity num-rows*num-columns
+  pending-scroll?:bool
   top-idx:num  # index inside data that corresponds to top-left of screen
                # modified on scroll, wrapping around to the top of data
 ]
@@ -16,6 +28,32 @@ container screen-cell [
   color:num
 ]
 
+def main [
+  local-scope
+  open-console
+  clear-screen
+  print 0/screen [a]
+#?   a:char <- copy 97
+#?   i:num <- copy 0
+#?   {
+#?     done?:bool <- greater-or-equal i, 6
+#?     break-if done?
+#?     move-cursor 0/screen i, 2527
+#?     print 0/screen a
+#?     a <- add a, 1
+#?     i <- add i, 1
+#?     loop
+#?   }
+  move-cursor 0/screen 5, 2527
+  a:num b:num <- cursor-position 0/screen
+  print 0/screen [f]
+  c:num d:num <- cursor-position 0/screen
+  wait-for-some-interaction
+  close-console
+  $print a [ ] b 10/newline
+  $print c [ ] d 10/newline
+]
+
 def new-fake-screen w:num, h:num -> result:&:screen [
   local-scope
   load-ingredients
@@ -26,14 +64,14 @@ def new-fake-screen w:num, h:num -> result:&:screen [
   assert non-zero-height?, [screen can't have zero height]
   bufsize:num <- multiply w, h
   data:&:@:screen-cell <- new screen-cell:type, bufsize
-  *result <- merge h/num-rows, w/num-columns, 0/cursor-row, 0/cursor-column, data, 0/top-idx
+  *result <- merge h/num-rows, w/num-columns, 0/cursor-row, 0/cursor-column, data, 0/pending-scroll?, 0/top-idx
   result <- clear-screen result
 ]
 
 def clear-screen screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [clear-screen]
+#?   stash [clear-screen]
   {
     break-if screen
     # real screen
@@ -61,7 +99,7 @@ def clear-screen screen:&:screen -> screen:&:screen [
 def fake-screen-is-empty? screen:&:screen -> result:bool [
   local-scope
   load-ingredients
-  stash [fake-screen-is-empty?]
+#?   stash [fake-screen-is-empty?]
   return-unless screen, 1/true  # do nothing for real screens
   buf:&:@:screen-cell <- get *screen, data:offset
   i:num <- copy 0
@@ -150,9 +188,13 @@ def print screen:&:screen, c:char -> screen:&:screen [
   {
     at-bottom?:bool <- equal row, height
     break-unless at-bottom?
+    $dump-screen
+    $print [scroll1] 10/newline
     scroll-fake-screen screen
     row <- subtract height, 1
     *screen <- put *screen, cursor-row:offset, row
+    *screen <- put *screen, pending-scroll?:offset, 0/false
+    $dump-screen
   }
   # if row is below bottom margin (error), reset to bottom margin
   {
@@ -162,6 +204,17 @@ def print screen:&:screen, c:char -> screen:&:screen [
     *screen <- put *screen, cursor-row:offset, row
   }
   # }
+  # if there's a pending scroll, perform it
+  {
+    pending-scroll?:bool <- get *screen, pending-scroll?:offset
+#?     $print pending-scroll? 10/newline
+    break-unless pending-scroll?
+    $print [scroll2] 10/newline
+    $dump-screen
+    scroll-fake-screen screen
+    *screen <- put *screen, pending-scroll?:offset, 0/false
+    $dump-screen
+  }
 #?   stash [print] row column
 #?     $print [print-character (], row, [, ], column, [): ], c, 10/newline
   # special-case: newline
@@ -195,16 +248,30 @@ def print screen:&:screen, c:char -> screen:&:screen [
   index:num <- data-index row, column, width, height, top-idx
   cursor:screen-cell <- merge c, color
   *buf <- put-index *buf, index, cursor
-  # move cursor to next character
+  # move cursor to next character, wrapping as necessary
+  # however, don't scroll just yet
   # (but don't bother making it valid; we'll do that before the next print)
   column <- add column, 1
+  {
+    past-right?:bool <- greater-or-equal column, width
+    break-unless past-right?
+    column <- copy 0
+    row <- add row, 1
+    past-bottom?:bool <- greater-or-equal row, height
+    break-unless past-bottom?
+    # queue up a scroll
+    $print [pending scroll] 10/newline
+    *screen <- put *screen, pending-scroll?:offset, 1/true
+    row <- subtract row, 1  # update cursor as if scroll already happened
+  }
+  *screen <- put *screen, cursor-row:offset, row
   *screen <- put *screen, cursor-column:offset, column
 ]
 
 def cursor-down-on-fake-screen screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-down]
+#?   stash [cursor-down]
   row:num <- get *screen, cursor-row:offset
   height:num <- get *screen, num-rows:offset
   bottom:num <- subtract height, 1
@@ -223,7 +290,7 @@ def cursor-down-on-fake-screen screen:&:screen -> screen:&:screen [
 def scroll-fake-screen screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [scroll-fake-screen]
+#?   stash [scroll-fake-screen]
   width:num <- get *screen, num-columns:offset
   height:num <- get *screen, num-rows:offset
   buf:&:@:screen-cell <- get *screen, data:offset
@@ -515,7 +582,7 @@ def assert-no-scroll screen:&:screen, old-top-idx:num [
 def clear-line screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [clear-line]
+#?   stash [clear-line]
   space:char <- copy 0/nul
   {
     break-if screen
@@ -545,7 +612,7 @@ def clear-line-until screen:&:screen, right:num/inclusive -> screen:&:screen [
   local-scope
   load-ingredients
   row:num, column:num <- cursor-position screen
-  stash [clear-line-until] row column
+#?   stash [clear-line-until] row column
   height:num <- screen-height screen
   past-bottom?:bool <- greater-or-equal row, height
   return-if past-bottom?
@@ -582,7 +649,7 @@ def cursor-position screen:&:screen -> row:num, column:num [
 def move-cursor screen:&:screen, new-row:num, new-column:num -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [move-cursor]
+#?   stash [move-cursor]
   {
     break-if screen
     # real screen
@@ -592,6 +659,8 @@ def move-cursor screen:&:screen, new-row:num, new-column:num -> screen:&:screen
   # fake screen
   *screen <- put *screen, cursor-row:offset, new-row
   *screen <- put *screen, cursor-column:offset, new-column
+  $print [move cursor ] new-row [ ] new-column 10/newline
+  *screen <- put *screen, pending-scroll?:offset, 0/false
 ]
 
 scenario clear-line-erases-printed-characters [
@@ -628,7 +697,7 @@ scenario clear-line-erases-printed-characters [
 def cursor-down screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-down]
+#?   stash [cursor-down]
   {
     break-if screen
     # real screen
@@ -671,7 +740,7 @@ scenario cursor-down-scrolls [
 def cursor-up screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-up]
+#?   stash [cursor-up]
   {
     break-if screen
     # real screen
@@ -689,7 +758,7 @@ def cursor-up screen:&:screen -> screen:&:screen [
 def cursor-right screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-right]
+#?   stash [cursor-right]
   {
     break-if screen
     # real screen
@@ -709,7 +778,7 @@ def cursor-right screen:&:screen -> screen:&:screen [
 def cursor-left screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-left]
+#?   stash [cursor-left]
   {
     break-if screen
     # real screen
@@ -727,16 +796,15 @@ def cursor-left screen:&:screen -> screen:&:screen [
 def cursor-to-start-of-line screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-to-start-of-line]
+#?   stash [cursor-to-start-of-line]
   row:num <- cursor-position screen
-  column:num <- copy 0
-  screen <- move-cursor screen, row, column
+  screen <- move-cursor screen, row, 0/column
 ]
 
 def cursor-to-next-line screen:&:screen -> screen:&:screen [
   local-scope
   load-ingredients
-  stash [cursor-to-next-line]
+#?   stash [cursor-to-next-line]
   screen <- cursor-down screen
   screen <- cursor-to-start-of-line screen
 ]
@@ -745,14 +813,14 @@ def move-cursor-to-column screen:&:screen, column:num -> screen:&:screen [
   local-scope
   load-ingredients
   row:num, _ <- cursor-position screen
-  stash [move-cursor-to-column] row
+#?   stash [move-cursor-to-column] row
   move-cursor screen, row, column
 ]
 
 def screen-width screen:&:screen -> width:num [
   local-scope
   load-ingredients
-  stash [screen-width]
+#?   stash [screen-width]
   {
     break-unless screen
     # fake screen
@@ -766,7 +834,7 @@ def screen-width screen:&:screen -> width:num [
 def screen-height screen:&:screen -> height:num [
   local-scope
   load-ingredients
-  stash [screen-height]
+#?   stash [screen-height]
   {
     break-unless screen
     # fake screen