## the 'copy' button makes it easy to duplicate a sandbox, and thence to ## see code operate in multiple situations scenario copy-a-sandbox-to-editor [ local-scope trace-until 100/app # trace too long assume-screen 100/width, 10/height # empty recipes assume-resources [ ] env:&:environment <- new-programming-environment resources, screen, [add 1, 1] # contents of sandbox editor # run it assume-console [ press F4 ] event-loop screen, console, env, resources screen-should-contain [ . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] # click at left edge of 'copy' button assume-console [ left-click 3, 69 ] run [ event-loop screen, console, env, resources ] # it copies into editor screen-should-contain [ . run (F4) . . ┊add 1, 1 . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] # cursor should be in the right place assume-console [ type [0] ] run [ event-loop screen, console, env, resources ] screen-should-contain [ . run (F4) . . ┊0add 1, 1 . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] ] scenario copy-a-sandbox-to-editor-2 [ local-scope trace-until 100/app # trace too long assume-screen 100/width, 10/height # empty recipes assume-resources [ ] env:&:environment <- new-programming-environment resources, screen, [add 1, 1] # contents of sandbox editor # run it assume-console [ press F4 ] event-loop screen, console, env, resources screen-should-contain [ . run (F4) . . ┊ . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] # click at right edge of 'copy' button (just before 'delete') assume-console [ left-click 3, 84 ] run [ event-loop screen, console, env, resources ] # it copies into editor screen-should-contain [ . run (F4) . . ┊add 1, 1 . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] # cursor should be in the right place assume-console [ type [0] ] run [ event-loop screen, console, env, resources ] screen-should-contain [ . run (F4) . . ┊0add 1, 1 . .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊─────────────────────────────────────────────────. . ┊0 edit copy delete . . ┊add 1, 1 . . ┊2 . . ┊─────────────────────────────────────────────────. . ┊ . ] ] after [ # support 'copy' button { copy?:bool <- should-attempt-copy? click-row, click-column, env break-unless copy? copy?, env <- try-copy-sandbox click-row, env break-unless copy? screen <- render-sandbox-side screen, env, render screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env loop +next-event } ] # some preconditions for attempting to copy a sandbox def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> result:bool [ local-scope load-ingredients # are we below the sandbox editor? click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env return-unless click-sandbox-area?, 0/false # narrower, is the click in the columns spanning the 'copy' button? first-sandbox:&:editor <- get *env, current-sandbox:offset assert first-sandbox, [!!] sandbox-left-margin:num <- get *first-sandbox, left:offset sandbox-right-margin:num <- get *first-sandbox, right:offset _, _, copy-button-left:num, copy-button-right:num, _ <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin copy-button-vertical-area?:bool <- within-range? click-column, copy-button-left, copy-button-right return-unless copy-button-vertical-area?, 0/false # finally, is sandbox editor empty? current-sandbox:&:editor <- get *env, current-sandbox:offset result <- empty-editor? current-sandbox ] def try-copy-sandbox click-row:num, env:&:environment -> clicked-on-copy-button?:bool, env:&:environment [ local-scope load-ingredients # identify the sandbox to copy, if the click was actually on the 'copy' button sandbox:&:sandbox <- find-sandbox env, click-row return-unless sandbox, 0/false clicked-on-copy-button? <- copy 1/true text:text <- get *sandbox, data:offset current-sandbox:&:editor <- get *env, current-sandbox:offset current-sandbox <- insert-text current-sandbox, text # reset scroll *env <- put *env, render-from:offset, -1 # position cursor in sandbox editor *env <- put *env, sandbox-in-focus?:offset, 1/true ] def find-sandbox env:&:environment, click-row:num -> result:&:sandbox [ local-scope load-ingredients curr-sandbox:&:sandbox <- get *env, sandbox:offset { break-unless curr-sandbox start:num <- get *curr-sandbox, starting-row-on-screen:offset found?:bool <- equal click-row, start return-if found?, curr-sandbox curr-sandbox <- get *curr-sandbox, next-sandbox:offset loop } return 0/not-found ] def click-on-sandbox-area? click-row:num, click-column:num, env:&:environment -> result:bool [ local-scope load-ingredients current-sandbox:&:editor <- get *env, current-sandbox:offset sandbox-left-margin:num <- get *current-sandbox, left:offset on-sandbox-side?:bool <- greater-or-equal click-column, sandbox-left-margin return-unless on-sandbox-side?, 0/false first-sandbox:&:sandbox <- get *env, sandbox:offset return-unless first-sandbox, 0/false first-sandbox-begins:num <- get *first-sandbox, starting-row-on-screen:offset result <- greater-or-equal click-row, first-sandbox-begins ] def empty-editor? editor:&:editor -> result:bool [ local-scope load-ingredients head:&:duplex-list:char <- get *editor, data:offset firsffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Clas