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