about summary refs log blame commit diff stats
path: root/405screen.mu
blob: 531fa5eeee92489bf7b41ab8b6e2d2b54fdb6404 (plain) (tree)
1
2
3
4
5
6
7






                                                                              













                                  
                































                                                                               



                                                                              
































                                                                        
                                        











                                                            
                                    






                            














                                                             
                                                     






































                                                                         







                                                           


















                                                             

                                                      


                   

                                   



                 








                                                                             



   












                                                                                




                                                          





































































































































                                                        






























































                                                                                                                                        
# Wrappers for real screen primitives that can be passed a fake screen.
# There are no tests here, but commented scenarios are painstakingly validated
# against a real terminal emulator. I believe functionality here is broadly
# portable across terminal emulators.
#
# Remember: fake screen co-ordinates are 1-based, just like in real terminal
# emulators.

type screen {
  num-rows: int
  num-cols: int
  data: (handle array screen-cell)
  pending-scroll?: boolean
  top-index: int
  cursor-row: int
  cursor-col: int
  cursor-hide?: boolean
  curr-attributes: screen-cell
}

type screen-cell {
  data: grapheme
  color: int
  background-color: int
  bold?: boolean
  underline?: boolean
  reverse?: boolean
  blink?: boolean
}

fn initialize-screen screen: (addr screen), nrows: int, ncols: int {
  var screen-addr/esi: (addr screen) <- copy screen
  var tmp/eax: int <- copy 0
  var dest/edi: (addr int) <- copy 0
  # screen->num-rows = nrows
  dest <- get screen-addr, num-rows
  tmp <- copy nrows
  copy-to *dest, tmp
  # screen->num-cols = ncols
  dest <- get screen-addr, num-cols
  tmp <- copy ncols
  copy-to *dest, tmp
  # screen->data = new screen-cell[nrows*ncols]
  {
    var data-addr/edi: (addr handle array screen-cell) <- get screen-addr, data
    tmp <- multiply nrows
    populate data-addr, tmp
  }
  # screen->cursor-row = 1
  dest <- get screen-addr, cursor-row
  copy-to *dest, 1
  # screen->cursor-col = 1
  dest <- get screen-addr, cursor-col
  copy-to *dest, 1
  # screen->curr-attributes->background-color = 7  (simulate light background)
  var tmp2/eax: (addr screen-cell) <- get screen-addr, curr-attributes
  dest <- get tmp2, background-color
  copy-to *dest, 7
}

fn screen-size screen: (addr screen) -> nrows/eax: int, ncols/ecx: int {
$screen-size:body: {
  compare screen, 0
  {
    break-if-!=
    nrows, ncols <- real-screen-size
    break $screen-size:body
  }
  {
    break-if-=
    # fake screen
    var screen-addr/esi: (addr screen) <- copy screen
    var tmp/edx: (addr int) <- get screen-addr, num-rows
    nrows <- copy *tmp
    tmp <- get screen-addr, num-cols
    ncols <- copy *tmp
  }
}
}

fn clear-screen screen: (addr screen) {
$clear-screen:body: {
  compare screen, 0
  {
    break-if-!=
    clear-real-screen
    break $clear-screen:body
  }
  {
    break-if-=
    # fake screen
    var space/edi: grapheme <- copy 0x20
    move-cursor screen, 1, 1
    var screen-addr/esi: (addr screen) <- copy screen
    var i/eax: int <- copy 1
    var nrows/ecx: (addr int) <- get screen-addr, num-rows
    {
      compare i, *nrows
      break-if->
      var j/edx: int <- copy 1
      var ncols/ebx: (addr int) <- get screen-addr, num-cols
      {
        compare j, *ncols
        break-if->
        print-grapheme screen, space
        j <- increment
        loop
      }
      i <- increment
      loop
    }
    move-cursor screen, 1, 1
  }
}
}

fn move-cursor screen: (addr screen), row: int, column: int {
$move-cursor:body: {
  compare screen, 0
  {
    break-if-!=
    move-cursor-on-real-screen row, column
    break $move-cursor:body
  }
  {
    break-if-=
    # fake screen
    var screen-addr/esi: (addr screen) <- copy screen
    # row < 0 is ignored
    {
      compare row, 0
      break-if-< $move-cursor:body
    }
    # row = 0 is treated same as 1
    {
      compare row, 0
      break-if-!=
      copy-to row, 1
    }
    # row > num-rows saturates to num-rows
    {
      var nrows-addr/eax: (addr int) <- get screen-addr, num-rows
      var nrows/eax: int <- copy *nrows-addr
      compare row, nrows
      break-if-<=
      copy-to row, nrows
    }
    # column < 0 is ignored
    {
      compare column, 0
      break-if-< $move-cursor:body
    }
    # column = 0 is treated same as 1
    {
      compare column, 0
      break-if-!=
      copy-to column, 1
    }
    # column > num-cols saturates to num-cols+1 (so wrapping to next row)
    {
      var ncols-addr/eax: (addr int) <- get screen-addr, num-cols
      var ncols/eax: int <- copy *ncols-addr
      compare column, ncols
      break-if-<=
      copy-to column, ncols
      increment column
    }
    # screen->cursor-row = row
    var dest/edi: (addr int) <- get screen-addr, cursor-row
    var src/eax: int <- copy row
    copy-to *dest, src
    # screen->cursor-col = column
    dest <- get screen-addr, cursor-col
    src <- copy column
    copy-to *dest, src
  }
}
}

fn print-string screen: (addr screen), s: (addr array byte) {
$print-string:body: {
  compare screen, 0
  {
    break-if-!=
    print-string-to-real-screen s
    break $print-string:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn print-grapheme screen: (addr screen), c: grapheme {
$print-grapheme:body: {
  compare screen, 0
  {
    break-if-!=
    print-grapheme-to-real-screen c
    break $print-grapheme:body
  }
  {
    break-if-=
    # fake screen
    var screen-addr/esi: (addr screen) <- copy screen
    var idx/ecx: int <- current-screen-cell-index screen-addr
    var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
    var data/eax: (addr array screen-cell) <- lookup *data-ah
    var offset/ecx: (offset screen-cell) <- compute-offset data, idx
    var cell/eax: (addr screen-cell) <- index data, offset
    var dest/eax: (addr grapheme) <- get cell, data
    var c2/ecx: grapheme <- copy c
    copy-to *dest, c2
  }
}
}

fn current-screen-cell-index screen-on-stack: (addr screen) -> result/ecx: int {
  var screen/esi: (addr screen) <- copy screen-on-stack
  var num-cols-addr/eax: (addr int) <- get screen, num-cols
  var num-cols/eax: int <- copy *num-cols-addr
  var cursor-row-addr/ecx: (addr int) <- get screen, cursor-row
  result <- copy *cursor-row-addr
  result <- subtract 1
  result <- multiply num-cols
  var cursor-col-addr/eax: (addr int) <- get screen, cursor-col
  result <- add *cursor-col-addr
  result <- subtract 1
}

fn print-code-point screen: (addr screen), c: code-point {
  var g/eax: grapheme <- to-grapheme c
  print-grapheme screen, g
}

fn print-int32-hex screen: (addr screen), n: int {
$print-int32-hex:body: {
  compare screen, 0
  {
    break-if-!=
    print-int32-hex-to-real-screen n
    break $print-int32-hex:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn reset-formatting screen: (addr screen) {
$reset-formatting:body: {
  compare screen, 0
  {
    break-if-!=
    reset-formatting-on-real-screen
    break $reset-formatting:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn start-color screen: (addr screen), fg: int, bg: int {
$start-color:body: {
  compare screen, 0
  {
    break-if-!=
    start-color-on-real-screen fg, bg
    break $start-color:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn start-bold screen: (addr screen) {
$start-bold:body: {
  compare screen, 0
  {
    break-if-!=
    start-bold-on-real-screen
    break $start-bold:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn start-underline screen: (addr screen) {
$start-underline:body: {
  compare screen, 0
  {
    break-if-!=
    start-underline-on-real-screen
    break $start-underline:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn start-reverse-video screen: (addr screen) {
$start-reverse-video:body: {
  compare screen, 0
  {
    break-if-!=
    start-reverse-video-on-real-screen
    break $start-reverse-video:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn start-blinking screen: (addr screen) {
$start-blinking:body: {
  compare screen, 0
  {
    break-if-!=
    start-blinking-on-real-screen
    break $start-blinking:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn hide-cursor screen: (addr screen) {
$hide-cursor:body: {
  compare screen, 0
  {
    break-if-!=
    hide-cursor-on-real-screen
    break $hide-cursor:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

fn show-cursor screen: (addr screen) {
$show-cursor:body: {
  compare screen, 0
  {
    break-if-!=
    show-cursor-on-real-screen
    break $show-cursor:body
  }
  {
    break-if-=
    # fake screen
  }
}
}

# validate data on screen regardless of attributes (color, bold, etc.)
# Mu doesn't have multi-line strings, so we provide functions for rows or portions of rows.

fn check-screen-row screen: (addr screen), row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-from screen: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte) {
}

# various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute

fn check-screen-row-in-color screen: (addr screen), fg: color, row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-color-from screen: (addr screen), fg: color, row-idx: int, col-idx: int, expected: (addr array byte) {
}

# background color is visible even for spaces, so 'expected' behaves as an array of booleans.
# non-space = given background must match; space = background must not match
fn check-screen-row-in-background-color screen: (addr screen), fg: color, row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-background-color-from screen: (addr screen), fg: color, row-idx: int, col-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-bold screen: (addr screen), row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-bold-from screen: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-underline screen: (addr screen), row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-underline-from screen: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-reverse screen: (addr screen), row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-reverse-from screen: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-blinking screen: (addr screen), row-idx: int, expected: (addr array byte) {
}

fn check-screen-row-in-blinking-from screen: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte) {
}

fn test-print-grapheme {
  var screen-on-stack: screen
  var screen/esi: (addr screen) <- address screen-on-stack
  initialize-screen screen, 5, 4
  var c/eax: grapheme <- copy 0x61  # 'a'
  print-grapheme screen, c
  check-screen-row screen, 1, "a"  # top-left corner of the screen
}

#? fn main -> exit-status/ebx: int {
#?   test-print-grapheme
#?   exit-status <- copy 0
#? }