diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-13 10:08:57 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-11-13 10:08:57 -0800 |
commit | c603cd6cef43100aa83a62e15f96fd54c9fb987e (patch) | |
tree | d8631b1964a0200d170a996314f6e023686ff8de /081print.mu | |
parent | 05d3592047a76db4cc8d77102508c21ca1b86e7b (diff) | |
download | mu-c603cd6cef43100aa83a62e15f96fd54c9fb987e.tar.gz |
2430 - make room for more transforms
Diffstat (limited to '081print.mu')
-rw-r--r-- | 081print.mu | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/081print.mu b/081print.mu new file mode 100644 index 00000000..c3d08180 --- /dev/null +++ b/081print.mu @@ -0,0 +1,684 @@ +# Wrappers around print primitives that take a 'screen' object and are thus +# easier to test. + +container screen [ + num-rows:number + num-columns:number + cursor-row:number + cursor-column:number + data:address:array:screen-cell +] + +container screen-cell [ + contents:character + color:number +] + +recipe new-fake-screen [ + local-scope + result:address:screen <- new screen:type + width:address:number <- get-address *result, num-columns:offset + *width <- next-ingredient + height:address:number <- get-address *result, num-rows:offset + *height <- next-ingredient + row:address:number <- get-address *result, cursor-row:offset + *row <- copy 0 + column:address:number <- get-address *result, cursor-column:offset + *column <- copy 0 + bufsize:number <- multiply *width, *height + buf:address:address:array:screen-cell <- get-address *result, data:offset + *buf <- new screen-cell:type, bufsize + clear-screen result + reply result +] + +recipe clear-screen [ + local-scope + sc:address:screen <- next-ingredient + # if x exists + { + break-unless sc + # clear fake screen + buf:address:array:screen-cell <- get *sc, data:offset + max:number <- length *buf + i:number <- copy 0 + { + done?:boolean <- greater-or-equal i, max + break-if done? + curr:address:screen-cell <- index-address *buf, i + curr-content:address:character <- get-address *curr, contents:offset + *curr-content <- copy 0/empty + curr-color:address:number <- get-address *curr, color:offset + *curr-color <- copy 7/white + i <- add i, 1 + loop + } + # reset cursor + x:address:number <- get-address *sc, cursor-row:offset + *x <- copy 0 + x <- get-address *sc, cursor-column:offset + *x <- copy 0 + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + clear-display + reply sc/same-as-ingredient:0 +] + +recipe sync-screen [ + local-scope + sc:address:screen <- next-ingredient + { + break-if sc + sync-display + } + # do nothing for fake screens +] + +recipe fake-screen-is-empty? [ + local-scope + sc:address:screen <- next-ingredient + reply-unless sc, 1/true + buf:address:array:screen-cell <- get *sc, data:offset + i:number <- copy 0 + len:number <- length *buf + { + done?:boolean <- greater-or-equal i, len + break-if done? + curr:screen-cell <- index *buf, i + curr-contents:character <- get curr, contents:offset + i <- add i, 1 + loop-unless curr-contents + # not 0 + reply 0/false + } + reply 1/true +] + +recipe print-character [ + local-scope + sc:address:screen <- next-ingredient + c:character <- next-ingredient + color:number, color-found?:boolean <- next-ingredient + { + # default color to white + break-if color-found? + color <- copy 7/white + } + bg-color:number, bg-color-found?:boolean <- next-ingredient + { + # default bg-color to black + break-if bg-color-found? + bg-color <- copy 0/black + } + trace 90, [print-character], c + { + # if x exists + # (handle special cases exactly like in the real screen) + break-unless sc + width:number <- get *sc, num-columns:offset + height:number <- get *sc, num-rows:offset + # if cursor is out of bounds, silently exit + row:address:number <- get-address *sc, cursor-row:offset + legal?:boolean <- greater-or-equal *row, 0 + reply-unless legal?, sc + legal? <- lesser-than *row, height + reply-unless legal?, sc + column:address:number <- get-address *sc, cursor-column:offset + legal? <- greater-or-equal *column, 0 + reply-unless legal?, sc + legal? <- lesser-than *column, width + reply-unless legal?, sc + # special-case: newline + { + newline?:boolean <- equal c, 10/newline + break-unless newline? + { + # unless cursor is already at bottom + bottom:number <- subtract height, 1 + at-bottom?:boolean <- greater-or-equal *row, bottom + break-if at-bottom? + # move it to the next row + *column <- copy 0 + *row <- add *row, 1 + } + reply sc/same-as-ingredient:0 + } + # save character in fake screen + index:number <- multiply *row, width + index <- add index, *column + buf:address:array:screen-cell <- get *sc, data:offset + len:number <- length *buf + # special-case: backspace + { + backspace?:boolean <- equal c, 8 + break-unless backspace? + { + # unless cursor is already at left margin + at-left?:boolean <- lesser-or-equal *column, 0 + break-if at-left? + # clear previous location + *column <- subtract *column, 1 + index <- subtract index, 1 + cursor:address:screen-cell <- index-address *buf, index + cursor-contents:address:character <- get-address *cursor, contents:offset + *cursor-contents <- copy 32/space + cursor-color:address:number <- get-address *cursor, color:offset + *cursor-color <- copy 7/white + } + reply sc/same-as-ingredient:0 + } + cursor:address:screen-cell <- index-address *buf, index + cursor-contents:address:character <- get-address *cursor, contents:offset + *cursor-contents <- copy c + cursor-color:address:number <- get-address *cursor, color:offset + *cursor-color <- copy color + # increment column unless it's already all the way to the right + { + right:number <- subtract width, 1 + at-right?:boolean <- greater-or-equal *column, right + break-if at-right? + *column <- add *column, 1 + } + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + print-character-to-display c, color, bg-color + reply sc/same-as-ingredient:0 +] + +scenario print-character-at-top-left [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell + ] + memory-should-contain [ + 3 <- 6 # width*height + 4 <- 97 # 'a' + 5 <- 7 # white + 6 <- 0 + ] +] + +scenario print-character-color [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97/a, 1/red + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell + ] + memory-should-contain [ + 3 <- 6 # width*height + 4 <- 97 # 'a' + 5 <- 1 # red + 6 <- 0 + ] +] + +scenario print-backspace-character [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell + ] + memory-should-contain [ + 2 <- 0 # cursor column + 4 <- 6 # width*height + 5 <- 32 # space, not 'a' + 6 <- 7 # white + 7 <- 0 + ] +] + +scenario print-extra-backspace-character [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 1:address:screen <- print-character 1:address:screen, 8 # backspace + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell + ] + memory-should-contain [ + 2 <- 0 # cursor column + 4 <- 6 # width*height + 5 <- 32 # space, not 'a' + 6 <- 7 # white + 7 <- 0 + ] +] + +scenario print-at-right-margin [ + run [ + 1:address:screen <- new-fake-screen 2/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 98 # 'b' + 1:address:screen <- print-character 1:address:screen, 99 # 'c' + 2:number <- get *1:address:screen, cursor-column:offset + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell + ] + memory-should-contain [ + 2 <- 1 # cursor column + 4 <- 4 # width*height + 5 <- 97 # 'a' + 6 <- 7 # white + 7 <- 99 # 'c' over 'b' + 8 <- 7 # white + 9 <- 0 + ] +] + +scenario print-newline-character [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 10/newline + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset + 4:address:array:screen-cell <- get *1:address:screen, data:offset + 5:array:screen-cell <- copy *4:address:array:screen-cell + ] + memory-should-contain [ + 2 <- 1 # cursor row + 3 <- 0 # cursor column + 5 <- 6 # width*height + 6 <- 97 # 'a' + 7 <- 7 # white + 8 <- 0 + ] +] + +scenario print-newline-at-bottom-line [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 10/newline + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset + ] + memory-should-contain [ + 2 <- 1 # cursor row + 3 <- 0 # cursor column + ] +] + +scenario print-at-bottom-right [ + run [ + 1:address:screen <- new-fake-screen 2/width, 2/height + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + 1:address:screen <- print-character 1:address:screen, 98 # 'b' + 1:address:screen <- print-character 1:address:screen, 99 # 'c' + 1:address:screen <- print-character 1:address:screen, 10/newline + 1:address:screen <- print-character 1:address:screen, 100 # 'd' + 2:number <- get *1:address:screen, cursor-row:offset + 3:number <- get *1:address:screen, cursor-column:offset + 4:address:array:screen-cell <- get *1:address:screen, data:offset + 5:array:screen-cell <- copy *4:address:array:screen-cell + ] + memory-should-contain [ + 2 <- 1 # cursor row + 3 <- 1 # cursor column + 5 <- 4 # width*height + 6 <- 0 # unused + 7 <- 7 # white + 8 <- 0 # unused + 9 <- 7 # white + 10 <- 97 # 'a' + 11 <- 7 # white + 12 <- 100 # 'd' over 'b' and 'c' and newline + 13 <- 7 # white + 14 <- 0 + ] +] + +recipe clear-line [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, clear line in fake screen + { + break-unless sc + width:number <- get *sc, num-columns:offset + column:address:number <- get-address *sc, cursor-column:offset + original-column:number <- copy *column + # space over the entire line + { + right:number <- subtract width, 1 + done?:boolean <- greater-or-equal *column, right + break-if done? + print-character sc, [ ] # implicitly updates 'column' + loop + } + # now back to where the cursor was + *column <- copy original-column + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + clear-line-on-display + reply sc/same-as-ingredient:0 +] + +recipe cursor-position [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, lookup cursor in fake screen + { + break-unless sc + row:number <- get *sc, cursor-row:offset + column:number <- get *sc, cursor-column:offset + reply row, column, sc/same-as-ingredient:0 + } + row, column <- cursor-position-on-display + reply row, column, sc/same-as-ingredient:0 +] + +recipe move-cursor [ + local-scope + sc:address:screen <- next-ingredient + new-row:number <- next-ingredient + new-column:number <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + row:address:number <- get-address *sc, cursor-row:offset + *row <- copy new-row + column:address:number <- get-address *sc, cursor-column:offset + *column <- copy new-column + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + move-cursor-on-display new-row, new-column + reply sc/same-as-ingredient:0 +] + +scenario clear-line-erases-printed-characters [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + # print a character + 1:address:screen <- print-character 1:address:screen, 97 # 'a' + # move cursor to start of line + 1:address:screen <- move-cursor 1:address:screen, 0/row, 0/column + # clear line + 1:address:screen <- clear-line 1:address:screen + 2:address:array:screen-cell <- get *1:address:screen, data:offset + 3:array:screen-cell <- copy *2:address:array:screen-cell + ] + # screen should be blank + memory-should-contain [ + 3 <- 6 # width*height + 4 <- 0 + 5 <- 7 + 6 <- 0 + 7 <- 7 + 8 <- 0 + 9 <- 7 + 10 <- 0 + 11 <- 7 + 12 <- 0 + 13 <- 7 + 14 <- 0 + 15 <- 7 + ] +] + +recipe cursor-down [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + { + # increment row unless it's already all the way down + height:number <- get *sc, num-rows:offset + row:address:number <- get-address *sc, cursor-row:offset + max:number <- subtract height, 1 + at-bottom?:boolean <- greater-or-equal *row, max + break-if at-bottom? + *row <- add *row, 1 + } + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + move-cursor-down-on-display + reply sc/same-as-ingredient:0 +] + +recipe cursor-up [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + { + # decrement row unless it's already all the way up + row:address:number <- get-address *sc, cursor-row:offset + at-top?:boolean <- lesser-or-equal *row, 0 + break-if at-top? + *row <- subtract *row, 1 + } + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + move-cursor-up-on-display + reply sc/same-as-ingredient:0 +] + +recipe cursor-right [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + { + # increment column unless it's already all the way to the right + width:number <- get *sc, num-columns:offset + column:address:number <- get-address *sc, cursor-column:offset + max:number <- subtract width, 1 + at-bottom?:boolean <- greater-or-equal *column, max + break-if at-bottom? + *column <- add *column, 1 + } + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + move-cursor-right-on-display + reply sc/same-as-ingredient:0 +] + +recipe cursor-left [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + { + # decrement column unless it's already all the way to the left + column:address:number <- get-address *sc, cursor-column:offset + at-top?:boolean <- lesser-or-equal *column, 0 + break-if at-top? + *column <- subtract *column, 1 + } + reply sc/same-as-ingredient:0 + } + # otherwise, real screen + move-cursor-left-on-display + reply sc/same-as-ingredient:0 +] + +recipe cursor-to-start-of-line [ + local-scope + sc:address:screen <- next-ingredient + row:number, _, sc <- cursor-position sc + column:number <- copy 0 + sc <- move-cursor sc, row, column + reply sc/same-as-ingredient:0 +] + +recipe cursor-to-next-line [ + local-scope + screen:address:screen <- next-ingredient + screen <- cursor-down screen + screen <- cursor-to-start-of-line screen + reply screen/same-as-ingredient:0 +] + +recipe screen-width [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + width:number <- get *sc, num-columns:offset + reply width + } + # otherwise, real screen + width:number <- display-width + reply width +] + +recipe screen-height [ + local-scope + sc:address:screen <- next-ingredient + # if x exists, move cursor in fake screen + { + break-unless sc + height:number <- get *sc, num-rows:offset + reply height + } + # otherwise, real screen + height:number <- display-height + reply height +] + +recipe hide-cursor [ + local-scope + screen:address:screen <- next-ingredient + # if x exists (not real display), do nothing + { + break-unless screen + reply screen + } + # otherwise, real screen + hide-cursor-on-display + reply screen +] + +recipe show-cursor [ + local-scope + screen:address:screen <- next-ingredient + # if x exists (not real display), do nothing + { + break-unless screen + reply screen + } + # otherwise, real screen + show-cursor-on-display + reply screen +] + +recipe hide-screen [ + local-scope + screen:address:screen <- next-ingredient + # if x exists (not real display), do nothing + # todo: help test this + { + break-unless screen + reply screen + } + # otherwise, real screen + hide-display + reply screen +] + +recipe show-screen [ + local-scope + screen:address:screen <- next-ingredient + # if x exists (not real display), do nothing + # todo: help test this + { + break-unless screen + reply screen + } + # otherwise, real screen + show-display + reply screen +] + +recipe print-string [ + local-scope + screen:address:screen <- next-ingredient + s:address:array:character <- next-ingredient + color:number, color-found?:boolean <- next-ingredient + { + # default color to white + break-if color-found? + color <- copy 7/white + } + bg-color:number, bg-color-found?:boolean <- next-ingredient + { + # default bg-color to black + break-if bg-color-found? + bg-color <- copy 0/black + } + len:number <- length *s + i:number <- copy 0 + { + done?:boolean <- greater-or-equal i, len + break-if done? + c:character <- index *s, i + print-character screen, c, color, bg-color + i <- add i, 1 + loop + } + reply screen/same-as-ingredient:0 +] + +scenario print-string-stops-at-right-margin [ + run [ + 1:address:screen <- new-fake-screen 3/width, 2/height + 2:address:array:character <- new [abcd] + 1:address:screen <- print-string 1:address:screen, 2:address:array:character + 3:address:array:screen-cell <- get *1:address:screen, data:offset + 4:array:screen-cell <- copy *3:address:array:screen-cell + ] + memory-should-contain [ + 4 <- 6 # width*height + 5 <- 97 # 'a' + 6 <- 7 # white + 7 <- 98 # 'b' + 8 <- 7 # white + 9 <- 100 # 'd' overwrites 'c' + 10 <- 7 # white + 11 <- 0 # unused + ] +] + +recipe print-integer [ + local-scope + screen:address:screen <- next-ingredient + n:number <- next-ingredient + color:number, color-found?:boolean <- next-ingredient + { + # default color to white + break-if color-found? + color <- copy 7/white + } + bg-color:number, bg-color-found?:boolean <- next-ingredient + { + # default bg-color to black + break-if bg-color-found? + bg-color <- copy 0/black + } + # todo: other bases besides decimal + s:address:array:character <- integer-to-decimal-string n + print-string screen, s, color, bg-color + reply screen/same-as-ingredient:0 +] |