about summary refs log tree commit diff stats
path: root/edit/010-sandbox-trace.mu
blob: 3451cc4b02dfa84e2e27243687064afcef95d54f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
## clicking on the code typed into a sandbox toggles its trace

scenario sandbox-click-on-code-toggles-app-trace [
  trace-until 100/app  # trace too long
  assume-screen 100/width, 10/height
  # basic recipe
  1:address:array:character <- new [ 
recipe foo [
  stash [abc]
]]
  # run it
  2:address:array:character <- new [foo]
  assume-console [
    press F4
  ]
  3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
  event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                   .
    .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .  stash [abc]                                     0   edit          copy            delete         .
    .]                                                 foo                                              .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
  # click on the code in the sandbox
  assume-console [
    left-click 4, 51
  ]
  run [
    event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
    4:character/cursor-icon <- copy 9251/    print screen:address:screen, 4:character/cursor-icon
  ]
  # trace now printed and cursor shouldn't have budged
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                  .
    .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .  stash [abc]                                     0   edit          copy            delete         .
    .]                                                 foo                                              .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                                              .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
  screen-should-contain-in-color 245/grey, [
    .                                                                                                    .
    .                                                                                                   .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
    .                                                                                                   .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                                              .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
  # click again on the same region
  assume-console [
    left-click 4, 55
  ]
  run [
    event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
    print screen:address:screen, 4:character/cursor-icon
  ]
  # trace hidden again
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                  .
    .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .  stash [abc]                                     0   edit          copy            delete         .
    .]                                                 foo                                              .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
]

scenario sandbox-shows-app-trace-and-result [
  trace-until 100/app  # trace too long
  assume-screen 100/width, 10/height
  # basic recipe
  1:address:array:character <- new [ 
recipe foo [
  stash [abc]
  reply 4
]]
  # run it
  2:address:array:character <- new [foo]
  assume-console [
    press F4
  ]
  3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
  event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                   .
    .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .  stash [abc]                                     0   edit          copy            delete         .
    .  reply 4                                         foo                                              .
    .]                                                 4                                                .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
  # click on the code in the sandbox
  assume-console [
    left-click 4, 51
  ]
  run [
    event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
  ]
  # trace now printed above result
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                   .
    .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .  stash [abc]                                     0   edit          copy            delete         .
    .  reply 4                                         foo                                              .
    .]                                                 abc                                              .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
]

scenario clicking-on-app-trace-does-nothing [
  trace-until 100/app  # trace too long
  assume-screen 100/width, 10/height
  1:address:array:character <- new []
  # create and expand the trace
  2:address:array:character <- new [stash 123456789]
  assume-console [
    press F4
    left-click 4, 51
  ]
  3:address:programming-environment-data <- new-programming-environment screen:address:screen, 1:address:array:character, 2:address:array:character
  event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                   .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                  0   edit          copy            delete         .
    .                                                  stash 123456789                                  .
    .                                                  123456789                                        .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
  # click on the stash under the edit-button region (or any of the other buttons, really)
  assume-console [
    left-click 5, 57
  ]
  run [
    event-loop screen:address:screen, console:address:console, 3:address:programming-environment-data
  ]
  # no change; doesn't die
  screen-should-contain [
    .                                                                                 run (F4)           .
    .                                                                                                   .
    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                  0   edit          copy            delete         .
    .                                                  stash 123456789                                  .
    .                                                  123456789                                        .
    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
    .                                                                                                   .
  ]
]

container sandbox-data [
  trace:address:array:character
  display-trace?:boolean
]

# replaced in a later layer
def! update-sandbox sandbox:address:sandbox-data, env:address:programming-environment-data, idx:number -> sandbox:address:sandbox-data, env:address:programming-environment-data [
  local-scope
  load-ingredients
  data:address:array:character <- get *sandbox, data:offset
  response:address:array:character, _, fake-screen:address:screen, trace:address:array:character <- run-interactive data
  *sandbox <- put *sandbox, response:offset, response
  *sandbox <- put *sandbox, screen:offset, fake-screen
  *sandbox <- put *sandbox, trace:offset, trace
]

# clicks on sandbox code toggle its display-trace? flag
after <global-touch> [
  # check if it's inside the code of any sandbox
  {
    sandbox-left-margin:number <- get *current-sandbox, left:offset
    click-column:number <- get t, column:offset
    on-sandbox-side?:boolean <- greater-or-equal click-column, sandbox-left-margin
    break-unless on-sandbox-side?
    first-sandbox:address:sandbox-data <- get *env, sandbox:offset
    break-unless first-sandbox
    first-sandbox-begins:number <- get *first-sandbox, starting-row-on-screen:offset
    click-row:number <- get t, row:offset
    below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins
    break-unless below-sandbox-editor?
    # identify the sandbox whose code is being clicked on
    sandbox:address:sandbox-data <- find-click-in-sandbox-code env, click-row
    break-unless sandbox
    # toggle its display-trace? property
    x:boolean <- get *sandbox, display-trace?:offset
    x <- not x
    *sandbox <- put *sandbox, display-trace?:offset, x
    hide-screen screen
    screen <- render-sandbox-side screen, env, 1/clear
    screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
    # no change in cursor
    show-screen screen
    loop +next-event:label
  }
]

def find-click-in-sandbox-code env:address:programming-environment-data, click-row:number -> sandbox:address:sandbox-data [
  local-scope
  load-ingredients
  # assert click-row >= sandbox.starting-row-on-screen
  sandbox <- get *env, sandbox:offset
  start:number <- get *sandbox, starting-row-on-screen:offset
  clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start
  assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor]
  # while click-row < sandbox.next-sandbox.starting-row-on-screen
  {
    next-sandbox:address:sandbox-data <- get *sandbox, next-sandbox:offset
    break-unless next-sandbox
    next-start:number <- get *next-sandbox, starting-row-on-screen:offset
    found?:boolean <- lesser-than click-row, next-start
    break-if found?
    sandbox <- copy next-sandbox
    loop
  }
  # return sandbox if click is in its code region
  code-ending-row:number <- get *sandbox, code-ending-row-on-screen:offset
  click-above-response?:boolean <- lesser-than click-row, code-ending-row
  start:number <- get *sandbox, starting-row-on-screen:offset
  click-below-menu?:boolean <- greater-than click-row, start
  click-on-sandbox-code?:boolean <- and click-above-response?, click-below-menu?
  {
    break-if click-on-sandbox-code?
    return 0/no-click-in-sandbox-output
  }
  return sandbox
]

# when rendering a sandbox, dump its trace before response/warning if display-trace? property is set
after <render-sandbox-results> [
  {
    display-trace?:boolean <- get *sandbox, display-trace?:offset
    break-unless display-trace?
    sandbox-trace:address:array:character <- get *sandbox, trace:offset
    break-unless sandbox-trace  # nothing to print; move on
    row, screen <- render screen, sandbox-trace, left, right, 245/grey, row
  }
  <render-sandbox-trace-done>
]
span>cursor-x/eax: int <- copy 0 var cursor-y/ecx: int <- copy 0 cursor-x, cursor-y <- cursor-position screen draw-grapheme screen, g, cursor-x, cursor-y, 0/fg, 7/bg } fn clear-screen _screen: (addr screen) { var screen/esi: (addr screen) <- copy _screen { compare screen, 0 break-if-!= clear-real-screen return } # fake screen set-cursor-position screen, 0, 0 var y/eax: int <- copy 0 var height/ecx: (addr int) <- get screen, height { compare y, *height break-if->= var x/edx: int <- copy 0 var width/ebx: (addr int) <- get screen, width { compare x, *width break-if->= draw-code-point screen, 0x20/space, x, y, 0/fg=black, 0/bg=black x <- increment loop } y <- increment loop } set-cursor-position screen, 0, 0 var pixels-ah/eax: (addr handle array byte) <- get screen, pixels var pixels/eax: (addr array byte) <- lookup *pixels-ah var i/ecx: int <- copy 0 var max/edx: int <- length pixels { compare i, max break-if->= var curr/eax: (addr byte) <- index pixels, i var zero/ebx: byte <- copy 0 copy-byte-to *curr, zero i <- increment loop } } fn fake-screen-empty? _screen: (addr screen) -> _/eax: boolean { var screen/esi: (addr screen) <- copy _screen var y/eax: int <- copy 0 var height/ecx: (addr int) <- get screen, height { compare y, *height break-if->= var x/edx: int <- copy 0 var width/ebx: (addr int) <- get screen, width { compare x, *width break-if->= var g/eax: grapheme <- screen-grapheme-at screen, x, y { compare g, 0 break-if-= compare g, 0x20/space break-if-= return 0/false } x <- increment loop } y <- increment loop } var pixels-ah/eax: (addr handle array byte) <- get screen, pixels var pixels/eax: (addr array byte) <- lookup *pixels-ah var y/ebx: int <- copy 0 var height-addr/edx: (addr int) <- get screen, height var height/edx: int <- copy *height-addr height <- shift-left 4/log2-font-height { compare y, height break-if->= var width-addr/edx: (addr int) <- get screen, width var width/edx: int <- copy *width-addr width <- shift-left 3/log2-font-width var x/edi: int <- copy 0 { compare x, width break-if->= var idx/ecx: int <- pixel-index screen, x, y var color-addr/ecx: (addr byte) <- index pixels, idx var color/ecx: byte <- copy-byte *color-addr compare color, 0 { break-if-= return 0/false } x <- increment loop } y <- increment loop } return 1/true } fn clear-rect _screen: (addr screen), xmin: int, ymin: int, xmax: int, ymax: int, background-color: int { var screen/esi: (addr screen) <- copy _screen { compare screen, 0 break-if-!= clear-rect-on-real-screen xmin, ymin, xmax, ymax, background-color return } # fake screen set-cursor-position screen, 0, 0 var y/eax: int <- copy ymin var ymax/ecx: int <- copy ymax { compare y, ymax break-if->= var x/edx: int <- copy xmin var xmax/ebx: int <- copy xmax { compare x, xmax break-if->= draw-code-point screen, 0x20/space, x, y, 0/fg, background-color x <- increment loop } y <- increment loop } set-cursor-position screen, 0, 0 } # there's no grapheme that guarantees to cover every pixel, so we'll bump down # to pixels for a real screen fn clear-real-screen { var y/eax: int <- copy 0 { compare y, 0x300/screen-height=768 break-if->= var x/edx: int <- copy 0 { compare x, 0x400/screen-width=1024 break-if->= pixel-on-real-screen x, y, 0/color=black x <- increment loop } y <- increment loop } } fn clear-rect-on-real-screen xmin: int, ymin: int, xmax: int, ymax: int, background-color: int { var y/eax: int <- copy ymin y <- shift-left 4/log2-font-height var ymax/ecx: int <- copy ymax ymax <- shift-left 4/log2-font-height { compare y, ymax break-if->= var x/edx: int <- copy xmin x <- shift-left 3/log2-font-width var xmax/ebx: int <- copy xmax xmax <- shift-left 3/log2-font-width { compare x, xmax break-if->= pixel-on-real-screen x, y, background-color x <- increment loop } y <- increment loop } } fn screen-grapheme-at _screen: (addr screen), x: int, y: int -> _/eax: grapheme { var screen/esi: (addr screen) <- copy _screen var idx/ecx: int <- screen-cell-index screen, x, y var result/eax: grapheme <- screen-grapheme-at-idx screen, idx return result } fn screen-grapheme-at-idx _screen: (addr screen), idx-on-stack: int -> _/eax: grapheme { var screen/esi: (addr screen) <- copy _screen var data-ah/eax: (addr handle array screen-cell) <- get screen, data var data/eax: (addr array screen-cell) <- lookup *data-ah var idx/ecx: int <- copy idx-on-stack var offset/ecx: (offset screen-cell) <- compute-offset data, idx var cell/eax: (addr screen-cell) <- index data, offset var src/eax: (addr grapheme) <- get cell, data return *src } fn screen-color-at _screen: (addr screen), x: int, y: int -> _/eax: int { var screen/esi: (addr screen) <- copy _screen var idx/ecx: int <- screen-cell-index screen, x, y var result/eax: int <- screen-color-at-idx screen, idx return result } fn screen-color-at-idx _screen: (addr screen), idx-on-stack: int -> _/eax: int { var screen/esi: (addr screen) <- copy _screen var data-ah/eax: (addr handle array screen-cell) <- get screen, data var data/eax: (addr array screen-cell) <- lookup *data-ah var idx/ecx: int <- copy idx-on-stack var offset/ecx: (offset screen-cell) <- compute-offset data, idx var cell/eax: (addr screen-cell) <- index data, offset var src/eax: (addr int) <- get cell, color var result/eax: int <- copy *src return result } fn screen-background-color-at _screen: (addr screen), x: int, y: int -> _/eax: int { var screen/esi: (addr screen) <- copy _screen var idx/ecx: int <- screen-cell-index screen, x, y var result/eax: int <- screen-background-color-at-idx screen, idx return result } fn screen-background-color-at-idx _screen: (addr screen), idx-on-stack: int -> _/eax: int { var screen/esi: (addr screen) <- copy _screen var data-ah/eax: (addr handle array screen-cell) <- get screen, data var data/eax: (addr array screen-cell) <- lookup *data-ah var idx/ecx: int <- copy idx-on-stack var offset/ecx: (offset screen-cell) <- compute-offset data, idx var cell/eax: (addr screen-cell) <- index data, offset var src/eax: (addr int) <- get cell, background-color var result/eax: int <- copy *src return result } fn pixel screen: (addr screen), x: int, y: int, color: int { { compare screen, 0 break-if-!= pixel-on-real-screen x, y, color return } # fake screen var screen/esi: (addr screen) <- copy screen var pixels-ah/eax: (addr handle array byte) <- get screen, pixels var pixels/eax: (addr array byte) <- lookup *pixels-ah { compare pixels, 0 break-if-!= abort "pixel graphics not enabled for this screen" } var idx/ecx: int <- pixel-index screen, x, y var dest/ecx: (addr byte) <- index pixels, idx var src/eax: byte <- copy-byte color copy-byte-to *dest, src } fn pixel-index _screen: (addr screen), x: int, y: int -> _/ecx: int { var screen/esi: (addr screen) <- copy _screen { compare x, 0 break-if->= var invalid/eax: (addr int) <- get screen, invalid-pixel-index return *invalid } { var xmax-a/eax: (addr int) <- get screen, width var xmax/eax: int <- copy *xmax-a xmax <- shift-left 3/log2-font-width compare x, xmax break-if-< var invalid/eax: (addr int) <- get screen, invalid-pixel-index return *invalid } { compare y, 0 break-if->= var invalid/eax: (addr int) <- get screen, invalid-pixel-index return *invalid } { var ymax-a/eax: (addr int) <- get screen, height var ymax/eax: int <- copy *ymax-a ymax <- shift-left 4/log2-font-height compare y, ymax break-if-< var invalid/eax: (addr int) <- get screen, invalid-pixel-index return *invalid } var width-addr/eax: (addr int) <- get screen, width var result/ecx: int <- copy y result <- multiply *width-addr result <- shift-left 3/log2-font-width result <- add x return result } # double-buffering primitive # 'screen' must be a fake screen. 'target-screen' is usually real. # Both screens must have the same size. fn copy-pixels _screen: (addr screen), target-screen: (addr screen) { var screen/esi: (addr screen) <- copy _screen var pixels-ah/eax: (addr handle array byte) <- get screen, pixels var _pixels/eax: (addr array byte) <- lookup *pixels-ah var pixels/edi: (addr array byte) <- copy _pixels var width-a/edx: (addr int) <- get screen, width var width/edx: int <- copy *width-a width <- shift-left 3/log2-font-width var height-a/ebx: (addr int) <- get screen, height var height/ebx: int <- copy *height-a height <- shift-left 4/log2-font-height var i/esi: int <- copy 0 var y/ecx: int <- copy 0 { # screen top left pixels x y width height compare y, height break-if->= var x/eax: int <- copy 0 { compare x, width break-if->= { var color-addr/ebx: (addr byte) <- index pixels, i var color/ebx: byte <- copy-byte *color-addr var color2/ebx: int <- copy color pixel target-screen, x, y, color2 } x <- increment i <- increment loop } y <- increment loop } }