# 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 right wraps it to the next line, # scrolling if necessary. The details are subtle: # # a) Rows can take unbounded values. When printing, large values for the row # saturate to the bottom row (because scrolling). # # 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). # Because scrolling. container screen [ num-rows:num num-columns:num 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 ] container screen-cell [ contents:char color:num ] def new-fake-screen w:num, h:num -> result:&:screen [ local-scope load-inputs result <- new screen:type non-zero-width?:bool <- greater-than w, 0 assert non-zero-width?, [screen can't have zero width] non-zero-height?:bool <- greater-than h, 0 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, false/pending-scroll?, 0/top-idx result <- clear-screen result ] def clear-screen screen:&:screen -> screen:&:screen [ local-scope load-inputs #? stash [clear-screen] { break-if screen # real screen clear-display return } # fake screen buf:&:@:screen-cell <- get *screen, data:offset max:num <- length *buf i:num <- copy 0 { done?:bool <- greater-or-equal i, max break-if done? curr:screen-cell <- merge 0/empty, 7/white *buf <- put-index *buf, i, curr i <- add i, 1 loop } # reset cursor *screen <- put *screen, cursor-row:offset, 0 *screen <- put *screen, cursor-column:offset, 0 *screen <- put *screen, top-idx:offset, 0 ] def fake-screen-is-empty? screen:&:screen -> result:bool [ local-scope load-inputs #? stash [fake-screen-is-empty?] return-unless screen, true # do nothing for real screens buf:&:@:screen-cell <- get *screen, data:offset i:num <- copy 0 len:num <- length *buf { done?:bool <- greater-or-equal i, len break-if done? curr:screen-cell <- index *buf, i curr-contents:char <- get curr, contents:offset i <- add i, 1 loop-unless curr-contents # not 0 return false } return true ] def print screen:&:screen, c:char -> screen:&:screen [ local-scope load-inputs color:num, color-found?:bool <- next-input { # default color to white break-if color-found? color <- copy 7/white } bg-color:num, bg-color-found?:bool <- next-input { # default bg-color to black break-if bg-color-found? bg-color <- copy 0/black } c2:num <- character-to-code c trace 90, [print-character], c2 { # real screen break-if screen print-character-to-display c, color, bg-color return } # fake screen # (handle special cases exactly like in the real screen) width:num <- get *screen, num-columns:offset height:num <- get *screen, num-rows:offset capacity:num <- multiply width, height row:num <- get *screen, cursor-row:offset column
#!/bin/sh
set -e
set -v
rm -rf mu.cc core.mu mu_bin* *_list .build
rm -rf termbox/*.o termbox/libtermbox.a
rm -rf .until .quit
test $# -gt 0 && exit 0 # convenience: 'clean top-level' to leave subsidiary tools alone
rm -rf ../../tools/enumerate ../../tools/tangle ../../tools/*_list cleave/cleave cleave/cleave.dSYM ../../*/*.dSYM