https://github.com/akkartik/mu/blob/main/shell/sandbox.mu

      1 type sandbox {
      2   data: (handle gap-buffer)
      3   value: (handle stream byte)
      4   trace: (handle trace)
      5   cursor-in-trace?: boolean
      6 }
      7
      8 fn initialize-sandbox _self: (addr sandbox) {
      9   var self/esi: (addr sandbox) <- copy _self
     10   var data-ah/eax: (addr handle gap-buffer) <- get self, data
     11   allocate data-ah
     12   var data/eax: (addr gap-buffer) <- lookup *data-ah
     13   initialize-gap-buffer data, 0x1000/4KB
     14   var value-ah/eax: (addr handle stream byte) <- get self, value
     15   populate-stream value-ah, 0x1000/4KB
     16   var trace-ah/eax: (addr handle trace) <- get self, trace
     17   allocate trace-ah
     18   var trace/eax: (addr trace) <- lookup *trace-ah
     19   initialize-trace trace, 0x1000/lines, 0x80/visible-lines
     20 }
     21
     22 ## some helpers for tests
     23
     24 fn initialize-sandbox-with _self: (addr sandbox), s: (addr array byte) {
     25   var self/esi: (addr sandbox) <- copy _self
     26   var data-ah/eax: (addr handle gap-buffer) <- get self, data
     27   allocate data-ah
     28   var data/eax: (addr gap-buffer) <- lookup *data-ah
     29   initialize-gap-buffer-with data, s
     30 }
     31
     32 fn allocate-sandbox-with _out: (addr handle sandbox), s: (addr array byte) {
     33   var out/eax: (addr handle sandbox) <- copy _out
     34   allocate out
     35   var out-addr/eax: (addr sandbox) <- lookup *out
     36   initialize-sandbox-with out-addr, s
     37 }
     38
     39 ##
     40
     41 fn render-sandbox screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int, xmax: int, ymax: int {
     42   clear-screen screen
     43   var self/esi: (addr sandbox) <- copy _self
     44   # data
     45   var data-ah/eax: (addr handle gap-buffer) <- get self, data
     46   var _data/eax: (addr gap-buffer) <- lookup *data-ah
     47   var data/edx: (addr gap-buffer) <- copy _data
     48   var x/eax: int <- copy xmin
     49   var y/ecx: int <- copy ymin
     50   var cursor-in-sandbox?/ebx: boolean <- copy 0/false
     51   {
     52     var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
     53     compare *cursor-in-trace?, 0/false
     54     break-if-!=
     55     cursor-in-sandbox? <- copy 1/true
     56   }
     57   x, y <- render-gap-buffer-wrapping-right-then-down screen, data, x, y, xmax, ymax, cursor-in-sandbox?
     58   y <- increment
     59   # trace
     60   var trace-ah/eax: (addr handle trace) <- get self, trace
     61   var _trace/eax: (addr trace) <- lookup *trace-ah
     62   var trace/edx: (addr trace) <- copy _trace
     63   var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
     64   y <- render-trace screen, trace, xmin, y, xmax, ymax, *cursor-in-trace?
     65   # value
     66   $render-sandbox:value: {
     67     var value-ah/eax: (addr handle stream byte) <- get self, value
     68     var _value/eax: (addr stream byte) <- lookup *value-ah
     69     var value/esi: (addr stream byte) <- copy _value
     70     rewind-stream value
     71     var done?/eax: boolean <- stream-empty? value
     72     compare done?, 0/false
     73     break-if-!=
     74     var x/eax: int <- copy 0
     75     x, y <- draw-text-wrapping-right-then-down screen, "=> ", xmin, y, xmax, ymax, xmin, y, 7/fg, 0/bg
     76     var x2/edx: int <- copy x
     77     var dummy/eax: int <- draw-stream-rightward screen, value, x2, xmax, y, 7/fg=grey, 0/bg
     78   }
     79   # render menu
     80   var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
     81   compare *cursor-in-trace?, 0/false
     82   {
     83     break-if-=
     84     render-trace-menu screen
     85     return
     86   }
     87   render-sandbox-menu screen
     88 }
     89
     90 fn render-sandbox-menu screen: (addr screen) {
     91   var width/eax: int <- copy 0
     92   var height/ecx: int <- copy 0
     93   width, height <- screen-size screen
     94   var y/ecx: int <- copy height
     95   y <- decrement
     96   set-cursor-position screen, 0/x, y
     97   draw-text-rightward-from-cursor screen, " ctrl-s ", width, 0/fg, 7/bg=grey
     98   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0/bg
     99   draw-text-rightward-from-cursor screen, " tab ", width, 0/fg, 9/bg=blue
    100   draw-text-rightward-from-cursor screen, " move to trace  ", width, 7/fg, 0/bg
    101   draw-text-rightward-from-cursor screen, " ctrl-d ", width, 0/fg, 7/bg=grey
    102   draw-text-rightward-from-cursor screen, " down  ", width, 7/fg, 0/bg
    103   draw-text-rightward-from-cursor screen, " ctrl-u ", width, 0/fg, 7/bg=grey
    104   draw-text-rightward-from-cursor screen, " up  ", width, 7/fg, 0/bg
    105 }
    106
    107 fn edit-sandbox _self: (addr sandbox), key: byte {
    108   var self/esi: (addr sandbox) <- copy _self
    109   var g/edx: grapheme <- copy key
    110   # running code
    111   {
    112     compare g, 0x12/ctrl-r
    113     break-if-!=
    114     # ctrl-r: run function outside sandbox
    115     # required: fn (addr screen), (addr keyboard)
    116     # Mu will pass in the real screen and keyboard.
    117     return
    118   }
    119   {
    120     compare g, 0x13/ctrl-s
    121     break-if-!=
    122     # ctrl-s: run sandbox(es)
    123     var data-ah/eax: (addr handle gap-buffer) <- get self, data
    124     var _data/eax: (addr gap-buffer) <- lookup *data-ah
    125     var data/ecx: (addr gap-buffer) <- copy _data
    126     var value-ah/eax: (addr handle stream byte) <- get self, value
    127     var _value/eax: (addr stream byte) <- lookup *value-ah
    128     var value/edx: (addr stream byte) <- copy _value
    129     var trace-ah/eax: (addr handle trace) <- get self, trace
    130     var trace/eax: (addr trace) <- lookup *trace-ah
    131     clear-trace trace
    132     run data, value, trace
    133     # testing write to disk
    134 #?     rewind-stream value
    135 #?     store-first-sector-to-primary-bus-secondary-drive value
    136     return
    137   }
    138   # tab
    139   var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
    140   {
    141     compare g, 9/tab
    142     break-if-!=
    143     # if cursor in input, switch to trace
    144     {
    145       compare *cursor-in-trace?, 0/false
    146       break-if-!=
    147       copy-to *cursor-in-trace?, 1/true
    148       return
    149     }
    150     # if cursor in trace, switch to input
    151     copy-to *cursor-in-trace?, 0/false
    152     return
    153   }
    154   # if cursor in trace, send cursor to trace
    155   {
    156     compare *cursor-in-trace?, 0/false
    157     break-if-=
    158     var trace-ah/eax: (addr handle trace) <- get self, trace
    159     var trace/eax: (addr trace) <- lookup *trace-ah
    160     edit-trace trace, g
    161     return
    162   }
    163   # otherwise send cursor to input
    164   var data-ah/eax: (addr handle gap-buffer) <- get self, data
    165   var data/eax: (addr gap-buffer) <- lookup *data-ah
    166   edit-gap-buffer data, g
    167   return
    168 }
    169
    170 fn run in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) {
    171   var read-result-storage: (handle cell)
    172   var read-result/esi: (addr handle cell) <- address read-result-storage
    173   read-cell in, read-result, trace
    174   var error?/eax: boolean <- has-errors? trace
    175   {
    176     compare error?, 0/false
    177     break-if-=
    178     return
    179   }
    180   var nil-storage: (handle cell)
    181   var nil-ah/eax: (addr handle cell) <- address nil-storage
    182   allocate-pair nil-ah
    183   var eval-result-storage: (handle cell)
    184   var eval-result/edi: (addr handle cell) <- address eval-result-storage
    185   evaluate read-result, eval-result, *nil-ah, trace
    186   var error?/eax: boolean <- has-errors? trace
    187   {
    188     compare error?, 0/false
    189     break-if-=
    190     return
    191   }
    192   clear-stream out
    193   print-cell eval-result, out, trace
    194   mark-lines-dirty trace
    195 }
    196
    197 fn test-run-integer {
    198   var sandbox-storage: sandbox
    199   var sandbox/esi: (addr sandbox) <- address sandbox-storage
    200   initialize-sandbox sandbox
    201   # type "1"
    202   edit-sandbox sandbox, 0x31/1
    203   # eval
    204   edit-sandbox sandbox, 0x13/ctrl-s
    205   # setup: screen
    206   var screen-on-stack: screen
    207   var screen/edi: (addr screen) <- address screen-on-stack
    208   initialize-screen screen, 0x80/width, 0x10/height
    209   #
    210   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    211   check-screen-row screen, 0/y, "1    ", "F - test-run-integer/0"
    212   check-screen-row screen, 1/y, "...  ", "F - test-run-integer/1"
    213   check-screen-row screen, 2/y, "=> 1 ", "F - test-run-integer/2"
    214 }
    215
    216 fn test-run-with-spaces {
    217   var sandbox-storage: sandbox
    218   var sandbox/esi: (addr sandbox) <- address sandbox-storage
    219   initialize-sandbox sandbox
    220   # type input with whitespace before and after
    221   edit-sandbox sandbox, 0x20/space
    222   edit-sandbox sandbox, 0x31/1
    223   edit-sandbox sandbox, 0x20/space
    224   edit-sandbox sandbox, 0xa/newline
    225   # eval
    226   edit-sandbox sandbox, 0x13/ctrl-s
    227   # setup: screen
    228   var screen-on-stack: screen
    229   var screen/edi: (addr screen) <- address screen-on-stack
    230   initialize-screen screen, 0x80/width, 0x10/height
    231   #
    232   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    233   check-screen-row screen, 0/y, " 1   ", "F - test-run-with-spaces/0"
    234   check-screen-row screen, 1/y, "     ", "F - test-run-with-spaces/1"
    235   check-screen-row screen, 2/y, "...  ", "F - test-run-with-spaces/2"
    236   check-screen-row screen, 3/y, "=> 1 ", "F - test-run-with-spaces/3"
    237 }
    238
    239 fn test-run-error-invalid-integer {
    240   var sandbox-storage: sandbox
    241   var sandbox/esi: (addr sandbox) <- address sandbox-storage
    242   initialize-sandbox sandbox
    243   # type "1a"
    244   edit-sandbox sandbox, 0x31/1
    245   edit-sandbox sandbox, 0x61/a
    246   # eval
    247   edit-sandbox sandbox, 0x13/ctrl-s
    248   # setup: screen
    249   var screen-on-stack: screen
    250   var screen/edi: (addr screen) <- address screen-on-stack
    251   initialize-screen screen, 0x80/width, 0x10/height
    252   #
    253   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    254   check-screen-row screen, 0/y, "1a             ", "F - test-run-error-invalid-integer/0"
    255   check-screen-row screen, 1/y, "...            ", "F - test-run-error-invalid-integer/0"
    256   check-screen-row screen, 2/y, "invalid number ", "F - test-run-error-invalid-integer/2"
    257 }
    258
    259 fn test-run-move-cursor-into-trace {
    260   var sandbox-storage: sandbox
    261   var sandbox/esi: (addr sandbox) <- address sandbox-storage
    262   initialize-sandbox sandbox
    263   # type "12"
    264   edit-sandbox sandbox, 0x31/1
    265   edit-sandbox sandbox, 0x32/2
    266   # eval
    267   edit-sandbox sandbox, 0x13/ctrl-s
    268   # setup: screen
    269   var screen-on-stack: screen
    270   var screen/edi: (addr screen) <- address screen-on-stack
    271   initialize-screen screen, 0x80/width, 0x10/height
    272   #
    273   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    274   check-screen-row screen,                                  0/y, "12    ", "F - test-run-move-cursor-into-trace/pre-0"
    275   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "  |   ", "F - test-run-move-cursor-into-trace/pre-0/cursor"
    276   check-screen-row screen,                                  1/y, "...   ", "F - test-run-move-cursor-into-trace/pre-1"
    277   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-run-move-cursor-into-trace/pre-1/cursor"
    278   check-screen-row screen,                                  2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/pre-2"
    279   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-run-move-cursor-into-trace/pre-2/cursor"
    280   # move cursor into trace
    281   edit-sandbox sandbox, 9/tab
    282   #
    283   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    284   check-screen-row screen,                                  0/y, "12    ", "F - test-run-move-cursor-into-trace/trace-0"
    285   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "      ", "F - test-run-move-cursor-into-trace/trace-0/cursor"
    286   check-screen-row screen,                                  1/y, "...   ", "F - test-run-move-cursor-into-trace/trace-1"
    287   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||   ", "F - test-run-move-cursor-into-trace/trace-1/cursor"
    288   check-screen-row screen,                                  2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/trace-2"
    289   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-run-move-cursor-into-trace/trace-2/cursor"
    290   # move cursor into input
    291   edit-sandbox sandbox, 9/tab
    292   #
    293   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
    294   check-screen-row screen,                                  0/y, "12    ", "F - test-run-move-cursor-into-trace/input-0"
    295   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "  |   ", "F - test-run-move-cursor-into-trace/input-0/cursor"
    296   check-screen-row screen,                                  1/y, "...   ", "F - test-run-move-cursor-into-trace/input-1"
    297   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-run-move-cursor-into-trace/input-1/cursor"
    298   check-screen-row screen,                                  2/y, "=> 12 ", "F - test-run-move-cursor-into-trace/input-2"
    299   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-run-move-cursor-into-trace/input-2/cursor"
    300 }