1 ## the 'copy' button makes it easy to duplicate a sandbox, and thence to
  2 ## see code operate in multiple situations
  3 
  4 scenario copy-a-sandbox-to-editor [
  5   local-scope
  6   trace-until 100/app  # trace too long
  7   assume-screen 100/width, 10/height
  8   # empty recipes
  9   assume-resources [
 10   ]
 11   env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
 12   # run it
 13   assume-console [
 14   ¦ press F4
 15   ]
 16   event-loop screen, console, env, resources
 17   screen-should-contain [
 18   ¦ .                                                                                 run (F4)           .
 19   ¦ .                                                  ╎                                                 .
 20   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
 21   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
 22   ¦ .                                                  ╎add 1, 1                                         .
 23   ¦ .                                                  ╎2                                                .
 24   ¦ .                                                  ╎─────────────────────────────────────────────────.
 25   ¦ .                                                  ╎                                                 .
 26   ]
 27   # click at left edge of 'copy' button
 28   assume-console [
 29   ¦ left-click 3, 69
 30   ]
 31   run [
 32   ¦ event-loop screen, console, env, resources
 33   ]
 34   # it copies into editor
 35   screen-should-contain [
 36   ¦ .                                                                                 run (F4)           .
 37   ¦ .                                                  ╎add 1, 1                                         .
 38   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
 39   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
 40   ¦ .                                                  ╎add 1, 1                                         .
 41   ¦ .                                                  ╎2                                                .
 42   ¦ .                                                  ╎─────────────────────────────────────────────────.
 43   ¦ .                                                  ╎                                                 .
 44   ]
 45   # cursor should be in the right place
 46   assume-console [
 47   ¦ type [0]
 48   ]
 49   run [
 50   ¦ event-loop screen, console, env, resources
 51   ]
 52   screen-should-contain [
 53   ¦ .                                                                                 run (F4)           .
 54   ¦ .                                                  ╎0add 1, 1                                        .
 55   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
 56   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
 57   ¦ .                                                  ╎add 1, 1                                         .
 58   ¦ .                                                  ╎2                                                .
 59   ¦ .                                                  ╎─────────────────────────────────────────────────.
 60   ¦ .                                                  ╎                                                 .
 61   ]
 62 ]
 63 
 64 scenario copy-a-sandbox-to-editor-2 [
 65   local-scope
 66   trace-until 100/app  # trace too long
 67   assume-screen 100/width, 10/height
 68   # empty recipes
 69   assume-resources [
 70   ]
 71   env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
 72   # run it
 73   assume-console [
 74   ¦ press F4
 75   ]
 76   event-loop screen, console, env, resources
 77   screen-should-contain [
 78   ¦ .                                                                                 run (F4)           .
 79   ¦ .                                                  ╎                                                 .
 80   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
 81   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
 82   ¦ .                                                  ╎add 1, 1                                         .
 83   ¦ .                                                  ╎2                                                .
 84   ¦ .                                                  ╎─────────────────────────────────────────────────.
 85   ¦ .                                                  ╎                                                 .
 86   ]
 87   # click at right edge of 'copy' button (just before 'delete')
 88   assume-console [
 89   ¦ left-click 3, 76
 90   ]
 91   run [
 92   ¦ event-loop screen, console, env, resources
 93   ]
 94   # it copies into editor
 95   screen-should-contain [
 96   ¦ .                                                                                 run (F4)           .
 97   ¦ .                                                  ╎add 1, 1                                         .
 98   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
 99   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
100   ¦ .                                                  ╎add 1, 1                                         .
101   ¦ .                                                  ╎2                                                .
102   ¦ .                                                  ╎─────────────────────────────────────────────────.
103   ¦ .                                                  ╎                                                 .
104   ]
105   # cursor should be in the right place
106   assume-console [
107   ¦ type [0]
108   ]
109   run [
110   ¦ event-loop screen, console, env, resources
111   ]
112   screen-should-contain [
113   ¦ .                                                                                 run (F4)           .
114   ¦ .                                                  ╎0add 1, 1                                        .
115   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
116   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
117   ¦ .                                                  ╎add 1, 1                                         .
118   ¦ .                                                  ╎2                                                .
119   ¦ .                                                  ╎─────────────────────────────────────────────────.
120   ¦ .                                                  ╎                                                 .
121   ]
122 ]
123 
124 after <global-touch> [
125   # support 'copy' button
126   {
127   ¦ copy?:bool <- should-attempt-copy? click-row, click-column, env
128   ¦ break-unless copy?
129   ¦ copy?, env <- try-copy-sandbox click-row, env
130   ¦ break-unless copy?
131   ¦ screen <- render-sandbox-side screen, env, render
132   ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
133   ¦ loop +next-event
134   }
135 ]
136 
137 # some preconditions for attempting to copy a sandbox
138 def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> result:bool [
139   local-scope
140   load-ingredients
141   # are we below the sandbox editor?
142   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
143   return-unless click-sandbox-area?, 0/false
144   # narrower, is the click in the columns spanning the 'copy' button?
145   first-sandbox:&:editor <- get *env, current-sandbox:offset
146   assert first-sandbox, [!!]
147   sandbox-left-margin:num <- get *first-sandbox, left:offset
148   sandbox-right-margin:num <- get *first-sandbox, right:offset
149   _, _, copy-button-left:num, copy-button-right:num <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
150   copy-button-vertical-area?:bool <- within-range? click-column, copy-button-left, copy-button-right
151   return-unless copy-button-vertical-area?, 0/false
152   # finally, is sandbox editor empty?
153   current-sandbox:&:editor <- get *env, current-sandbox:offset
154   result <- empty-editor? current-sandbox
155 ]
156 
157 def try-copy-sandbox click-row:num, env:&:environment -> clicked-on-copy-button?:bool, env:&:environment [
158   local-scope
159   load-ingredients
160   # identify the sandbox to copy, if the click was actually on the 'copy' button
161   sandbox:&:sandbox <- find-sandbox env, click-row
162   return-unless sandbox, 0/false
163   clicked-on-copy-button? <- copy 1/true
164   text:text <- get *sandbox, data:offset
165   current-sandbox:&:editor <- get *env, current-sandbox:offset
166   current-sandbox <- insert-text current-sandbox, text
167   # reset scroll
168   *env <- put *env, render-from:offset, -1
169   # position cursor in sandbox editor
170   *env <- put *env, sandbox-in-focus?:offset, 1/true
171 ]
172 
173 def find-sandbox env:&:environment, click-row:num -> result:&:sandbox [
174   local-scope
175   load-ingredients
176   curr-sandbox:&:sandbox <- get *env, sandbox:offset
177   {
178   ¦ break-unless curr-sandbox
179   ¦ start:num <- get *curr-sandbox, starting-row-on-screen:offset
180   ¦ found?:bool <- equal click-row, start
181   ¦ return-if found?, curr-sandbox
182   ¦ curr-sandbox <- get *curr-sandbox, next-sandbox:offset
183   ¦ loop
184   }
185   return 0/not-found
186 ]
187 
188 def click-on-sandbox-area? click-row:num, click-column:num, env:&:environment -> result:bool [
189   local-scope
190   load-ingredients
191   current-sandbox:&:editor <- get *env, current-sandbox:offset
192   sandbox-left-margin:num <- get *current-sandbox, left:offset
193   on-sandbox-side?:bool <- greater-or-equal click-column, sandbox-left-margin
194   return-unless on-sandbox-side?, 0/false
195   first-sandbox:&:sandbox <- get *env, sandbox:offset
196   return-unless first-sandbox, 0/false
197   first-sandbox-begins:num <- get *first-sandbox, starting-row-on-screen:offset
198   result <- greater-or-equal click-row, first-sandbox-begins
199 ]
200 
201 def empty-editor? editor:&:editor -> result:bool [
202   local-scope
203   load-ingredients
204   head:&:duplex-list:char <- get *editor, data:offset
205   first:&:duplex-list:char <- next head
206   result <- not first
207 ]
208 
209 def within-range? x:num, low:num, high:num -> result:bool [
210   local-scope
211   load-ingredients
212   not-too-far-left?:bool <- greater-or-equal x, low
213   not-too-far-right?:bool <- lesser-or-equal x, high
214   result <- and not-too-far-left? not-too-far-right?
215 ]
216 
217 scenario copy-fails-if-sandbox-editor-not-empty [
218   local-scope
219   trace-until 100/app  # trace too long
220   assume-screen 100/width, 10/height
221   # empty recipes
222   assume-resources [
223   ]
224   env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
225   # run it
226   assume-console [
227   ¦ press F4
228   ]
229   event-loop screen, console, env, resources
230   screen-should-contain [
231   ¦ .                                                                                 run (F4)           .
232   ¦ .                                                  ╎                                                 .
233   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
234   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
235   ¦ .                                                  ╎add 1, 1                                         .
236   ¦ .                                                  ╎2                                                .
237   ¦ .                                                  ╎─────────────────────────────────────────────────.
238   ¦ .                                                  ╎                                                 .
239   ]
240   # type something into the sandbox editor, then click on the 'copy' button
241   assume-console [
242   ¦ left-click 2, 70  # put cursor in sandbox editor
243   ¦ type [0]  # type something
244   ¦ left-click 3, 70  # click 'copy' button
245   ]
246   run [
247   ¦ event-loop screen, console, env, resources
248   ]
249   # copy doesn't happen
250   screen-should-contain [
251   ¦ .                                                                                 run (F4)           .
252   ¦ .                                                  ╎0                                                .
253   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
254   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
255   ¦ .                                                  ╎add 1, 1                                         .
256   ¦ .                                                  ╎2                                                .
257   ¦ .                                                  ╎─────────────────────────────────────────────────.
258   ¦ .                                                  ╎                                                 .
259   ]
260   # cursor should be in the right place
261   assume-console [
262   ¦ type [1]
263   ]
264   run [
265   ¦ event-loop screen, console, env, resources
266   ]
267   screen-should-contain [
268   ¦ .                                                                                 run (F4)           .
269   ¦ .                                                  ╎01                                               .
270   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
271   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
272   ¦ .                                                  ╎add 1, 1                                         .
273   ¦ .                                                  ╎2                                                .
274   ¦ .                                                  ╎─────────────────────────────────────────────────.
275   ¦ .                                                  ╎                                                 .
276   ]
277 ]
278 
279 ## the 'to recipe' button makes it easy to create a function out of a sandbox
280 
281 scenario copy-a-sandbox-to-recipe-side [
282   local-scope
283   trace-until 100/app  # trace too long
284   assume-screen 100/width, 10/height
285   # empty recipes
286   assume-resources [
287   ]
288   env:&:environment <- new-programming-environment resources, screen, [add 1, 1]  # contents of sandbox editor
289   # run it
290   assume-console [
291   ¦ press F4
292   ]
293   event-loop screen, console, env, resources
294   screen-should-contain [
295   ¦ .                                                                                 run (F4)           .
296   ¦ .                                                  ╎                                                 .
297   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
298   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
299   ¦ .                                                  ╎add 1, 1                                         .
300   ¦ .                                                  ╎2                                                .
301   ¦ .                                                  ╎─────────────────────────────────────────────────.
302   ¦ .                                                  ╎                                                 .
303   ]
304   # click at left edge of 'copy' button
305   assume-console [
306   ¦ left-click 3, 78
307   ]
308   run [
309   ¦ event-loop screen, console, env, resources
310   ]
311   # it copies into recipe side
312   screen-should-contain [
313   ¦ .                                                                                 run (F4)           .
314   ¦ .add 1, 1                                          ╎                                                 .
315   ¦ .                                                  ╎─────────────────────────────────────────────────.
316   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
317   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎add 1, 1                                         .
318   ¦ .                                                  ╎2                                                .
319   ¦ .                                                  ╎─────────────────────────────────────────────────.
320   ¦ .                                                  ╎                                                 .
321   ]
322   # cursor should be at the top left of the recipe side
323   assume-console [
324   ¦ type [0]
325   ]
326   run [
327   ¦ event-loop screen, console, env, resources
328   ]
329   screen-should-contain [
330   ¦ .                                                                                 run (F4)           .
331   ¦ .0add 1, 1                                         ╎                                                 .
332   ¦ .                                                  ╎─────────────────────────────────────────────────.
333   ¦ .                                                  ╎0   edit       copy       to recipe    delete    .
334   ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎add 1, 1                                         .
335   ¦ .                                                  ╎2                                                .
336   ¦ .                                                  ╎─────────────────────────────────────────────────.
337   ¦ .                                                  ╎                                                 .
338   ]
339 ]
340 
341 after <global-touch> [
342   # support 'copy to recipe' button
343   {
344   ¦ copy?:bool <- should-copy-to-recipe? click-row, click-column, env
345   ¦ break-unless copy?
346   ¦ modified?:bool <- prepend-sandbox-into-recipe-side click-row, env
347   ¦ break-unless modified?
348   ¦ *env <- put *env, sandbox-in-focus?:offset, 0/false
349   ¦ screen <- render-recipes screen, env, render
350   ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
351   ¦ loop +next-event
352   }
353 ]
354 
355 # some preconditions for attempting to copy a sandbox into the recipe side
356 def should-copy-to-recipe? click-row:num, click-column:num, env:&:environment -> result:bool [
357   local-scope
358   load-ingredients
359   # are we below the sandbox editor?
360   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
361   return-unless click-sandbox-area?, 0/false
362   # narrower, is the click in the columns spanning the 'copy' button?
363   first-sandbox:&:editor <- get *env, current-sandbox:offset
364   assert first-sandbox, [!!]
365   sandbox-left-margin:num <- get *first-sandbox, left:offset
366   sandbox-right-margin:num <- get *first-sandbox, right:offset
367   _, _, _, _, recipe-button-left:num, recipe-button-right:num <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
368   result <- within-range? click-column, recipe-button-left, recipe-button-right
369 ]
370 
371 def prepend-sandbox-into-recipe-side click-row:num, env:&:environment -> clicked-on-copy-to-recipe-button?:bool, env:&:environment [
372   local-scope
373   load-ingredients
374   sandbox:&:sandbox <- find-sandbox env, click-row
375   return-unless sandbox, 0/false
376   recipe-editor:&:editor <- get *env, recipes:offset
377   recipe-data:&:duplex-list:char <- get *recipe-editor, data:offset
378   # make the newly inserted code easy to delineate
379   newline:char <- copy 10
380   insert newline, recipe-data
381   insert newline, recipe-data
382   # insert code from the selected sandbox
383   sandbox-data:text <- get *sandbox, data:offset
384   insert recipe-data, sandbox-data
385   # reset cursor
386   *recipe-editor <- put *recipe-editor, top-of-screen:offset, recipe-data
387   *recipe-editor <- put *recipe-editor, before-cursor:offset, recipe-data
388   *recipe-editor <- put *recipe-editor, cursor-row:offset, 1
389   *recipe-editor <- put *recipe-editor, cursor-column:offset, 0
390   return 1/true
391 ]