From b2eff9f97e02fe6f5f55133002c16116aac13ed4 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Fri, 23 Jun 2017 19:47:09 -0700 Subject: 3942 No, my conclusion in the previous commit was wrong. When you print a character on the right margin, the cursor coordinates always wrap around to the left margin on the next row. It's just that if you're at the bottom of the screen, scrolling gives the impression that the row didn't change. --- 081print.mu | 108 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 20 deletions(-) (limited to '081print.mu') 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 -- cgit 1.4.1-2-gfad0