From d5a0abc20f2561d739fcc5cdeeef1e43ddcfd5ce Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 25 Jun 2017 09:46:05 -0700 Subject: 3956 --- html/edit/003-shortcuts.mu.html | 7867 +++++++++++++++++----------------- html/edit/005-sandbox.mu.html | 904 ++-- html/edit/007-sandbox-delete.mu.html | 12 +- html/edit/008-sandbox-edit.mu.html | 10 +- html/edit/011-errors.mu.html | 1134 +++-- html/edit/012-editor-undo.mu.html | 16 +- 6 files changed, 4947 insertions(+), 4996 deletions(-) diff --git a/html/edit/003-shortcuts.mu.html b/html/edit/003-shortcuts.mu.html index 613d2dea..b682f86e 100644 --- a/html/edit/003-shortcuts.mu.html +++ b/html/edit/003-shortcuts.mu.html @@ -455,3555 +455,3555 @@ if ('onhashchange' in window) { 393 ¦ at-right?:bool <- greater-or-equal curr-column, screen-width 394 ¦ return-if at-right?, 1/go-render 395 ¦ break-unless curr - 396 ¦ # newline? done. - 397 ¦ currc:char <- get *curr, value:offset - 398 ¦ at-newline?:bool <- equal currc, 10/newline - 399 ¦ break-if at-newline? - 400 ¦ screen <- print screen, currc - 401 ¦ curr-column <- add curr-column, 1 - 402 ¦ curr <- next curr - 403 ¦ loop - 404 } - 405 # we're guaranteed not to be at the right margin - 406 space:char <- copy 32/space - 407 screen <- print screen, space - 408 go-render? <- copy 0/false - 409 ] - 410 - 411 # right arrow - 412 - 413 scenario editor-moves-cursor-right-with-key [ - 414 local-scope - 415 assume-screen 10/width, 5/height - 416 e:&:editor <- new-editor [abc], 0/left, 10/right - 417 editor-render screen, e - 418 $clear-trace - 419 assume-console [ - 420 ¦ press right-arrow - 421 ¦ type [0] - 422 ] - 423 run [ - 424 ¦ editor-event-loop screen, console, e - 425 ] - 426 screen-should-contain [ - 427 ¦ . . - 428 ¦ .a0bc . - 429 ¦ .╌╌╌╌╌╌╌╌╌╌. - 430 ¦ . . - 431 ] - 432 check-trace-count-for-label 3, [print-character] # 0 and following characters - 433 ] - 434 - 435 after <handle-special-key> [ - 436 { - 437 ¦ move-to-next-character?:bool <- equal k, 65514/right-arrow - 438 ¦ break-unless move-to-next-character? - 439 ¦ # if not at end of text - 440 ¦ next-cursor:&:duplex-list:char <- next before-cursor - 441 ¦ break-unless next-cursor - 442 ¦ # scan to next character - 443 ¦ <move-cursor-begin> - 444 ¦ before-cursor <- copy next-cursor - 445 ¦ *editor <- put *editor, before-cursor:offset, before-cursor - 446 ¦ go-render?:bool <- move-cursor-coordinates-right editor, screen-height - 447 ¦ screen <- move-cursor screen, cursor-row, cursor-column - 448 ¦ undo-coalesce-tag:num <- copy 2/right-arrow - 449 ¦ <move-cursor-end> - 450 ¦ return - 451 } - 452 ] - 453 - 454 def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ - 455 local-scope - 456 load-ingredients - 457 before-cursor:&:duplex-list:char <- get *editor before-cursor:offset - 458 cursor-row:num <- get *editor, cursor-row:offset - 459 cursor-column:num <- get *editor, cursor-column:offset - 460 left:num <- get *editor, left:offset - 461 right:num <- get *editor, right:offset - 462 # if crossed a newline, move cursor to start of next row - 463 { - 464 ¦ old-cursor-character:char <- get *before-cursor, value:offset - 465 ¦ was-at-newline?:bool <- equal old-cursor-character, 10/newline - 466 ¦ break-unless was-at-newline? - 467 ¦ cursor-row <- add cursor-row, 1 - 468 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 469 ¦ cursor-column <- copy left - 470 ¦ *editor <- put *editor, cursor-column:offset, cursor-column - 471 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal - 472 ¦ return-unless below-screen?, 0/don't-render - 473 ¦ <scroll-down> - 474 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range - 475 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 476 ¦ return 1/go-render - 477 } - 478 # if the line wraps, move cursor to start of next row - 479 { - 480 ¦ # if we're at the column just before the wrap indicator - 481 ¦ wrap-column:num <- subtract right, 1 - 482 ¦ at-wrap?:bool <- equal cursor-column, wrap-column - 483 ¦ break-unless at-wrap? - 484 ¦ # and if next character isn't newline - 485 ¦ next:&:duplex-list:char <- next before-cursor - 486 ¦ break-unless next - 487 ¦ next-character:char <- get *next, value:offset - 488 ¦ newline?:bool <- equal next-character, 10/newline - 489 ¦ break-if newline? - 490 ¦ cursor-row <- add cursor-row, 1 - 491 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 492 ¦ cursor-column <- copy left - 493 ¦ *editor <- put *editor, cursor-column:offset, cursor-column - 494 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal - 495 ¦ return-unless below-screen?, 0/no-more-render - 496 ¦ <scroll-down> - 497 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range - 498 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 499 ¦ return 1/go-render - 500 } - 501 # otherwise move cursor one character right - 502 cursor-column <- add cursor-column, 1 - 503 *editor <- put *editor, cursor-column:offset, cursor-column - 504 go-render? <- copy 0/false - 505 ] - 506 - 507 scenario editor-moves-cursor-to-next-line-with-right-arrow [ - 508 local-scope - 509 assume-screen 10/width, 5/height - 510 s:text <- new [abc - 511 d] - 512 e:&:editor <- new-editor s, 0/left, 10/right - 513 editor-render screen, e - 514 $clear-trace - 515 # type right-arrow a few times to get to start of second line - 516 assume-console [ + 396 ¦ currc:char <- get *curr, value:offset + 397 ¦ at-newline?:bool <- equal currc, 10/newline + 398 ¦ break-if at-newline? + 399 ¦ screen <- print screen, currc + 400 ¦ curr-column <- add curr-column, 1 + 401 ¦ curr <- next curr + 402 ¦ loop + 403 } + 404 # we're guaranteed not to be at the right margin + 405 space:char <- copy 32/space + 406 screen <- print screen, space + 407 go-render? <- copy 0/false + 408 ] + 409 + 410 # right arrow + 411 + 412 scenario editor-moves-cursor-right-with-key [ + 413 local-scope + 414 assume-screen 10/width, 5/height + 415 e:&:editor <- new-editor [abc], 0/left, 10/right + 416 editor-render screen, e + 417 $clear-trace + 418 assume-console [ + 419 ¦ press right-arrow + 420 ¦ type [0] + 421 ] + 422 run [ + 423 ¦ editor-event-loop screen, console, e + 424 ] + 425 screen-should-contain [ + 426 ¦ . . + 427 ¦ .a0bc . + 428 ¦ .╌╌╌╌╌╌╌╌╌╌. + 429 ¦ . . + 430 ] + 431 check-trace-count-for-label 3, [print-character] # 0 and following characters + 432 ] + 433 + 434 after <handle-special-key> [ + 435 { + 436 ¦ move-to-next-character?:bool <- equal k, 65514/right-arrow + 437 ¦ break-unless move-to-next-character? + 438 ¦ # if not at end of text + 439 ¦ next-cursor:&:duplex-list:char <- next before-cursor + 440 ¦ break-unless next-cursor + 441 ¦ # scan to next character + 442 ¦ <move-cursor-begin> + 443 ¦ before-cursor <- copy next-cursor + 444 ¦ *editor <- put *editor, before-cursor:offset, before-cursor + 445 ¦ go-render?:bool <- move-cursor-coordinates-right editor, screen-height + 446 ¦ screen <- move-cursor screen, cursor-row, cursor-column + 447 ¦ undo-coalesce-tag:num <- copy 2/right-arrow + 448 ¦ <move-cursor-end> + 449 ¦ return + 450 } + 451 ] + 452 + 453 def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ + 454 local-scope + 455 load-ingredients + 456 before-cursor:&:duplex-list:char <- get *editor before-cursor:offset + 457 cursor-row:num <- get *editor, cursor-row:offset + 458 cursor-column:num <- get *editor, cursor-column:offset + 459 left:num <- get *editor, left:offset + 460 right:num <- get *editor, right:offset + 461 # if crossed a newline, move cursor to start of next row + 462 { + 463 ¦ old-cursor-character:char <- get *before-cursor, value:offset + 464 ¦ was-at-newline?:bool <- equal old-cursor-character, 10/newline + 465 ¦ break-unless was-at-newline? + 466 ¦ cursor-row <- add cursor-row, 1 + 467 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 468 ¦ cursor-column <- copy left + 469 ¦ *editor <- put *editor, cursor-column:offset, cursor-column + 470 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal + 471 ¦ return-unless below-screen?, 0/don't-render + 472 ¦ <scroll-down> + 473 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range + 474 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 475 ¦ return 1/go-render + 476 } + 477 # if the line wraps, move cursor to start of next row + 478 { + 479 ¦ # if we're at the column just before the wrap indicator + 480 ¦ wrap-column:num <- subtract right, 1 + 481 ¦ at-wrap?:bool <- equal cursor-column, wrap-column + 482 ¦ break-unless at-wrap? + 483 ¦ # and if next character isn't newline + 484 ¦ next:&:duplex-list:char <- next before-cursor + 485 ¦ break-unless next + 486 ¦ next-character:char <- get *next, value:offset + 487 ¦ newline?:bool <- equal next-character, 10/newline + 488 ¦ break-if newline? + 489 ¦ cursor-row <- add cursor-row, 1 + 490 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 491 ¦ cursor-column <- copy left + 492 ¦ *editor <- put *editor, cursor-column:offset, cursor-column + 493 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal + 494 ¦ return-unless below-screen?, 0/no-more-render + 495 ¦ <scroll-down> + 496 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range + 497 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 498 ¦ return 1/go-render + 499 } + 500 # otherwise move cursor one character right + 501 cursor-column <- add cursor-column, 1 + 502 *editor <- put *editor, cursor-column:offset, cursor-column + 503 go-render? <- copy 0/false + 504 ] + 505 + 506 scenario editor-moves-cursor-to-next-line-with-right-arrow [ + 507 local-scope + 508 assume-screen 10/width, 5/height + 509 s:text <- new [abc + 510 d] + 511 e:&:editor <- new-editor s, 0/left, 10/right + 512 editor-render screen, e + 513 $clear-trace + 514 # type right-arrow a few times to get to start of second line + 515 assume-console [ + 516 ¦ press right-arrow 517 ¦ press right-arrow 518 ¦ press right-arrow - 519 ¦ press right-arrow - 520 ¦ press right-arrow # next line - 521 ] - 522 run [ - 523 ¦ editor-event-loop screen, console, e - 524 ] - 525 check-trace-count-for-label 0, [print-character] - 526 # type something and ensure it goes where it should - 527 assume-console [ - 528 ¦ type [0] - 529 ] - 530 run [ - 531 ¦ editor-event-loop screen, console, e - 532 ] - 533 screen-should-contain [ - 534 ¦ . . - 535 ¦ .abc . - 536 ¦ .0d . - 537 ¦ .╌╌╌╌╌╌╌╌╌╌. - 538 ¦ . . - 539 ] - 540 check-trace-count-for-label 2, [print-character] # new length of second line - 541 ] - 542 - 543 scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [ - 544 local-scope - 545 assume-screen 10/width, 5/height - 546 s:text <- new [abc - 547 d] - 548 e:&:editor <- new-editor s, 1/left, 10/right - 549 editor-render screen, e - 550 assume-console [ + 519 ¦ press right-arrow # next line + 520 ] + 521 run [ + 522 ¦ editor-event-loop screen, console, e + 523 ] + 524 check-trace-count-for-label 0, [print-character] + 525 # type something and ensure it goes where it should + 526 assume-console [ + 527 ¦ type [0] + 528 ] + 529 run [ + 530 ¦ editor-event-loop screen, console, e + 531 ] + 532 screen-should-contain [ + 533 ¦ . . + 534 ¦ .abc . + 535 ¦ .0d . + 536 ¦ .╌╌╌╌╌╌╌╌╌╌. + 537 ¦ . . + 538 ] + 539 check-trace-count-for-label 2, [print-character] # new length of second line + 540 ] + 541 + 542 scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [ + 543 local-scope + 544 assume-screen 10/width, 5/height + 545 s:text <- new [abc + 546 d] + 547 e:&:editor <- new-editor s, 1/left, 10/right + 548 editor-render screen, e + 549 assume-console [ + 550 ¦ press right-arrow 551 ¦ press right-arrow 552 ¦ press right-arrow - 553 ¦ press right-arrow - 554 ¦ press right-arrow # next line - 555 ¦ type [0] - 556 ] - 557 run [ - 558 ¦ editor-event-loop screen, console, e - 559 ] - 560 screen-should-contain [ - 561 ¦ . . - 562 ¦ . abc . - 563 ¦ . 0d . - 564 ¦ . ╌╌╌╌╌╌╌╌╌. - 565 ¦ . . - 566 ] - 567 ] - 568 - 569 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ - 570 local-scope - 571 assume-screen 10/width, 5/height - 572 e:&:editor <- new-editor [abcdef], 0/left, 5/right - 573 editor-render screen, e - 574 $clear-trace - 575 assume-console [ - 576 ¦ left-click 1, 3 - 577 ¦ press right-arrow - 578 ] - 579 run [ - 580 ¦ editor-event-loop screen, console, e - 581 ¦ 3:num/raw <- get *e, cursor-row:offset - 582 ¦ 4:num/raw <- get *e, cursor-column:offset - 583 ] - 584 screen-should-contain [ - 585 ¦ . . - 586 ¦ .abcd↩ . - 587 ¦ .ef . - 588 ¦ .╌╌╌╌╌ . - 589 ¦ . . - 590 ] - 591 memory-should-contain [ - 592 ¦ 3 <- 2 - 593 ¦ 4 <- 0 - 594 ] - 595 check-trace-count-for-label 0, [print-character] - 596 ] - 597 - 598 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ - 599 local-scope - 600 assume-screen 10/width, 5/height - 601 # line just barely wrapping - 602 e:&:editor <- new-editor [abcde], 0/left, 5/right - 603 editor-render screen, e - 604 $clear-trace - 605 # position cursor at last character before wrap and hit right-arrow - 606 assume-console [ - 607 ¦ left-click 1, 3 - 608 ¦ press right-arrow - 609 ] - 610 run [ - 611 ¦ editor-event-loop screen, console, e - 612 ¦ 3:num/raw <- get *e, cursor-row:offset - 613 ¦ 4:num/raw <- get *e, cursor-column:offset - 614 ] - 615 memory-should-contain [ - 616 ¦ 3 <- 2 - 617 ¦ 4 <- 0 - 618 ] - 619 # now hit right arrow again - 620 assume-console [ - 621 ¦ press right-arrow - 622 ] - 623 run [ - 624 ¦ editor-event-loop screen, console, e - 625 ¦ 3:num/raw <- get *e, cursor-row:offset - 626 ¦ 4:num/raw <- get *e, cursor-column:offset - 627 ] - 628 memory-should-contain [ - 629 ¦ 3 <- 2 - 630 ¦ 4 <- 1 - 631 ] - 632 check-trace-count-for-label 0, [print-character] - 633 ] - 634 - 635 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ - 636 local-scope - 637 assume-screen 10/width, 5/height - 638 e:&:editor <- new-editor [abcdef], 1/left, 6/right - 639 editor-render screen, e - 640 $clear-trace - 641 assume-console [ - 642 ¦ left-click 1, 4 - 643 ¦ press right-arrow - 644 ] - 645 run [ - 646 ¦ editor-event-loop screen, console, e - 647 ¦ 3:num/raw <- get *e, cursor-row:offset - 648 ¦ 4:num/raw <- get *e, cursor-column:offset - 649 ] - 650 screen-should-contain [ - 651 ¦ . . - 652 ¦ . abcd↩ . - 653 ¦ . ef . - 654 ¦ . ╌╌╌╌╌ . - 655 ¦ . . - 656 ] - 657 memory-should-contain [ - 658 ¦ 3 <- 2 - 659 ¦ 4 <- 1 - 660 ] - 661 check-trace-count-for-label 0, [print-character] - 662 ] - 663 - 664 scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ - 665 local-scope - 666 assume-screen 10/width, 5/height - 667 s:text <- new [abc - 668 d] - 669 e:&:editor <- new-editor s, 0/left, 10/right - 670 editor-render screen, e - 671 $clear-trace - 672 # move to end of line, press right-arrow, type a character - 673 assume-console [ - 674 ¦ left-click 1, 3 - 675 ¦ press right-arrow - 676 ¦ type [0] - 677 ] - 678 run [ - 679 ¦ editor-event-loop screen, console, e - 680 ] - 681 # new character should be in next line - 682 screen-should-contain [ - 683 ¦ . . - 684 ¦ .abc . - 685 ¦ .0d . - 686 ¦ .╌╌╌╌╌╌╌╌╌╌. - 687 ¦ . . - 688 ] - 689 check-trace-count-for-label 2, [print-character] - 690 ] - 691 - 692 # todo: ctrl-right: next word-end - 693 - 694 # left arrow - 695 - 696 scenario editor-moves-cursor-left-with-key [ - 697 local-scope - 698 assume-screen 10/width, 5/height - 699 e:&:editor <- new-editor [abc], 0/left, 10/right - 700 editor-render screen, e - 701 $clear-trace - 702 assume-console [ - 703 ¦ left-click 1, 2 - 704 ¦ press left-arrow - 705 ¦ type [0] - 706 ] - 707 run [ - 708 ¦ editor-event-loop screen, console, e - 709 ] - 710 screen-should-contain [ - 711 ¦ . . - 712 ¦ .a0bc . - 713 ¦ .╌╌╌╌╌╌╌╌╌╌. - 714 ¦ . . - 715 ] - 716 check-trace-count-for-label 3, [print-character] - 717 ] - 718 - 719 after <handle-special-key> [ - 720 { - 721 ¦ move-to-previous-character?:bool <- equal k, 65515/left-arrow - 722 ¦ break-unless move-to-previous-character? - 723 ¦ trace 10, [app], [left arrow] - 724 ¦ # if not at start of text (before-cursor at § sentinel) - 725 ¦ prev:&:duplex-list:char <- prev before-cursor - 726 ¦ return-unless prev, 0/don't-render - 727 ¦ <move-cursor-begin> - 728 ¦ go-render? <- move-cursor-coordinates-left editor - 729 ¦ before-cursor <- copy prev - 730 ¦ *editor <- put *editor, before-cursor:offset, before-cursor - 731 ¦ undo-coalesce-tag:num <- copy 1/left-arrow - 732 ¦ <move-cursor-end> - 733 ¦ return - 734 } - 735 ] - 736 - 737 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ - 738 local-scope - 739 assume-screen 10/width, 5/height - 740 # initialize editor with two lines - 741 s:text <- new [abc - 742 d] - 743 e:&:editor <- new-editor s, 0/left, 10/right - 744 editor-render screen, e - 745 $clear-trace - 746 # position cursor at start of second line (so there's no previous newline) - 747 assume-console [ - 748 ¦ left-click 2, 0 - 749 ¦ press left-arrow - 750 ] - 751 run [ - 752 ¦ editor-event-loop screen, console, e - 753 ¦ 3:num/raw <- get *e, cursor-row:offset - 754 ¦ 4:num/raw <- get *e, cursor-column:offset - 755 ] - 756 memory-should-contain [ - 757 ¦ 3 <- 1 - 758 ¦ 4 <- 3 - 759 ] - 760 check-trace-count-for-label 0, [print-character] - 761 ] - 762 - 763 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ - 764 local-scope - 765 assume-screen 10/width, 5/height - 766 # initialize editor with three lines - 767 s:text <- new [abc - 768 def - 769 g] - 770 e:&:editor <- new-editor s:text, 0/left, 10/right - 771 editor-render screen, e - 772 $clear-trace - 773 # position cursor further down (so there's a newline before the character at - 774 # the cursor) - 775 assume-console [ - 776 ¦ left-click 3, 0 - 777 ¦ press left-arrow - 778 ¦ type [0] - 779 ] - 780 run [ - 781 ¦ editor-event-loop screen, console, e - 782 ] - 783 screen-should-contain [ - 784 ¦ . . - 785 ¦ .abc . - 786 ¦ .def0 . - 787 ¦ .g . - 788 ¦ .╌╌╌╌╌╌╌╌╌╌. - 789 ] - 790 check-trace-count-for-label 1, [print-character] # just the '0' - 791 ] - 792 - 793 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ - 794 local-scope - 795 assume-screen 10/width, 5/height - 796 s:text <- new [abc - 797 def - 798 g] - 799 e:&:editor <- new-editor s, 0/left, 10/right - 800 editor-render screen, e - 801 $clear-trace - 802 # position cursor at start of text, press left-arrow, then type a character - 803 assume-console [ - 804 ¦ left-click 1, 0 - 805 ¦ press left-arrow - 806 ¦ type [0] - 807 ] - 808 run [ - 809 ¦ editor-event-loop screen, console, e - 810 ] - 811 # left-arrow should have had no effect - 812 screen-should-contain [ - 813 ¦ . . - 814 ¦ .0abc . - 815 ¦ .def . - 816 ¦ .g . - 817 ¦ .╌╌╌╌╌╌╌╌╌╌. - 818 ] - 819 check-trace-count-for-label 4, [print-character] # length of first line - 820 ] - 821 - 822 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ - 823 local-scope - 824 assume-screen 10/width, 5/height - 825 # initialize editor with text containing an empty line - 826 s:text <- new [abc - 827 - 828 d] - 829 e:&:editor <- new-editor s, 0/left, 10/right - 830 editor-render screen, e:&:editor - 831 $clear-trace - 832 # position cursor right after empty line - 833 assume-console [ - 834 ¦ left-click 3, 0 - 835 ¦ press left-arrow - 836 ¦ type [0] - 837 ] - 838 run [ - 839 ¦ editor-event-loop screen, console, e - 840 ] - 841 screen-should-contain [ - 842 ¦ . . - 843 ¦ .abc . - 844 ¦ .0 . - 845 ¦ .d . - 846 ¦ .╌╌╌╌╌╌╌╌╌╌. - 847 ] - 848 check-trace-count-for-label 1, [print-character] # just the '0' - 849 ] - 850 - 851 scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [ - 852 local-scope - 853 assume-screen 10/width, 5/height - 854 # initialize editor with a wrapping line - 855 e:&:editor <- new-editor [abcdef], 0/left, 5/right - 856 editor-render screen, e - 857 $clear-trace - 858 screen-should-contain [ - 859 ¦ . . - 860 ¦ .abcd↩ . - 861 ¦ .ef . - 862 ¦ .╌╌╌╌╌ . - 863 ¦ . . - 864 ] - 865 # position cursor right after empty line - 866 assume-console [ - 867 ¦ left-click 2, 0 - 868 ¦ press left-arrow - 869 ] - 870 run [ - 871 ¦ editor-event-loop screen, console, e - 872 ¦ 3:num/raw <- get *e, cursor-row:offset - 873 ¦ 4:num/raw <- get *e, cursor-column:offset - 874 ] - 875 memory-should-contain [ - 876 ¦ 3 <- 1 # previous row - 877 ¦ 4 <- 3 # right margin except wrap icon - 878 ] - 879 check-trace-count-for-label 0, [print-character] - 880 ] - 881 - 882 scenario editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [ - 883 local-scope - 884 assume-screen 10/width, 5/height - 885 # initialize editor with a wrapping line followed by a second line - 886 s:text <- new [abcdef - 887 g] - 888 e:&:editor <- new-editor s, 0/left, 5/right - 889 editor-render screen, e - 890 $clear-trace - 891 screen-should-contain [ - 892 ¦ . . - 893 ¦ .abcd↩ . - 894 ¦ .ef . - 895 ¦ .g . - 896 ¦ .╌╌╌╌╌ . - 897 ] - 898 # position cursor right after empty line - 899 assume-console [ - 900 ¦ left-click 3, 0 - 901 ¦ press left-arrow - 902 ] - 903 run [ - 904 ¦ editor-event-loop screen, console, e - 905 ¦ 3:num/raw <- get *e, cursor-row:offset - 906 ¦ 4:num/raw <- get *e, cursor-column:offset - 907 ] - 908 memory-should-contain [ - 909 ¦ 3 <- 2 # previous row - 910 ¦ 4 <- 2 # end of wrapped line - 911 ] - 912 check-trace-count-for-label 0, [print-character] - 913 ] - 914 - 915 scenario editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [ - 916 local-scope - 917 assume-screen 10/width, 5/height - 918 # initialize editor with a line on the verge of wrapping, followed by a second line - 919 s:text <- new [abcd - 920 e] - 921 e:&:editor <- new-editor s, 0/left, 5/right - 922 editor-render screen, e - 923 $clear-trace - 924 screen-should-contain [ - 925 ¦ . . - 926 ¦ .abcd . - 927 ¦ .e . - 928 ¦ .╌╌╌╌╌ . - 929 ¦ . . - 930 ] - 931 # position cursor right after empty line - 932 assume-console [ - 933 ¦ left-click 2, 0 - 934 ¦ press left-arrow - 935 ] - 936 run [ - 937 ¦ editor-event-loop screen, console, e - 938 ¦ 3:num/raw <- get *e, cursor-row:offset - 939 ¦ 4:num/raw <- get *e, cursor-column:offset - 940 ] - 941 memory-should-contain [ - 942 ¦ 3 <- 1 # previous row - 943 ¦ 4 <- 4 # end of wrapped line - 944 ] - 945 check-trace-count-for-label 0, [print-character] - 946 ] - 947 - 948 # todo: ctrl-left: previous word-start - 949 - 950 # up arrow - 951 - 952 scenario editor-moves-to-previous-line-with-up-arrow [ - 953 local-scope - 954 assume-screen 10/width, 5/height - 955 s:text <- new [abc - 956 def] - 957 e:&:editor <- new-editor s, 0/left, 10/right - 958 editor-render screen, e - 959 $clear-trace - 960 assume-console [ - 961 ¦ left-click 2, 1 - 962 ¦ press up-arrow - 963 ] - 964 run [ - 965 ¦ editor-event-loop screen, console, e - 966 ¦ 3:num/raw <- get *e, cursor-row:offset - 967 ¦ 4:num/raw <- get *e, cursor-column:offset - 968 ] - 969 memory-should-contain [ - 970 ¦ 3 <- 1 - 971 ¦ 4 <- 1 - 972 ] - 973 check-trace-count-for-label 0, [print-character] - 974 assume-console [ - 975 ¦ type [0] - 976 ] - 977 run [ - 978 ¦ editor-event-loop screen, console, e - 979 ] - 980 screen-should-contain [ - 981 ¦ . . - 982 ¦ .a0bc . - 983 ¦ .def . - 984 ¦ .╌╌╌╌╌╌╌╌╌╌. - 985 ¦ . . - 986 ] - 987 ] - 988 - 989 after <handle-special-key> [ - 990 { - 991 ¦ move-to-previous-line?:bool <- equal k, 65517/up-arrow - 992 ¦ break-unless move-to-previous-line? - 993 ¦ <move-cursor-begin> - 994 ¦ go-render? <- move-to-previous-line editor - 995 ¦ undo-coalesce-tag:num <- copy 3/up-arrow - 996 ¦ <move-cursor-end> - 997 ¦ return - 998 } - 999 ] -1000 -1001 def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [ -1002 local-scope -1003 load-ingredients -1004 go-render?:bool <- copy 0/false -1005 cursor-row:num <- get *editor, cursor-row:offset -1006 cursor-column:num <- get *editor, cursor-column:offset -1007 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -1008 left:num <- get *editor, left:offset -1009 right:num <- get *editor, right:offset -1010 already-at-top?:bool <- lesser-or-equal cursor-row, 1/top -1011 { -1012 ¦ # if cursor not at top, move it -1013 ¦ break-if already-at-top? -1014 ¦ # if not at start of screen line, move to start of screen line (previous newline) -1015 ¦ # then scan back another line -1016 ¦ # if either step fails, give up without modifying cursor or coordinates -1017 ¦ curr:&:duplex-list:char <- copy before-cursor -1018 ¦ old:&:duplex-list:char <- copy curr -1019 ¦ { -1020 ¦ ¦ at-left?:bool <- equal cursor-column, left -1021 ¦ ¦ break-if at-left? -1022 ¦ ¦ curr <- before-previous-screen-line curr, editor -1023 ¦ ¦ no-motion?:bool <- equal curr, old -1024 ¦ ¦ return-if no-motion? -1025 ¦ } -1026 ¦ { -1027 ¦ ¦ curr <- before-previous-screen-line curr, editor -1028 ¦ ¦ no-motion?:bool <- equal curr, old -1029 ¦ ¦ return-if no-motion? -1030 ¦ } -1031 ¦ before-cursor <- copy curr -1032 ¦ *editor <- put *editor, before-cursor:offset, before-cursor -1033 ¦ cursor-row <- subtract cursor-row, 1 -1034 ¦ *editor <- put *editor, cursor-row:offset, cursor-row -1035 ¦ # scan ahead to right column or until end of line -1036 ¦ target-column:num <- copy cursor-column -1037 ¦ cursor-column <- copy left -1038 ¦ *editor <- put *editor, cursor-column:offset, cursor-column -1039 ¦ { -1040 ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column -1041 ¦ ¦ break-if done? -1042 ¦ ¦ curr:&:duplex-list:char <- next before-cursor -1043 ¦ ¦ break-unless curr -1044 ¦ ¦ currc:char <- get *curr, value:offset -1045 ¦ ¦ at-newline?:bool <- equal currc, 10/newline -1046 ¦ ¦ break-if at-newline? -1047 ¦ ¦ # -1048 ¦ ¦ before-cursor <- copy curr -1049 ¦ ¦ *editor <- put *editor, before-cursor:offset, before-cursor -1050 ¦ ¦ cursor-column <- add cursor-column, 1 -1051 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column -1052 ¦ ¦ loop -1053 ¦ } -1054 ¦ return -1055 } -1056 { -1057 ¦ # if cursor already at top, scroll up -1058 ¦ break-unless already-at-top? -1059 ¦ <scroll-up> -1060 ¦ return 1/go-render -1061 } -1062 ] -1063 -1064 scenario editor-adjusts-column-at-previous-line [ -1065 local-scope -1066 assume-screen 10/width, 5/height -1067 s:text <- new [ab -1068 def] -1069 e:&:editor <- new-editor s, 0/left, 10/right -1070 editor-render screen, e -1071 $clear-trace -1072 assume-console [ -1073 ¦ left-click 2, 3 -1074 ¦ press up-arrow -1075 ] -1076 run [ -1077 ¦ editor-event-loop screen, console, e -1078 ¦ 3:num/raw <- get *e, cursor-row:offset -1079 ¦ 4:num/raw <- get *e, cursor-column:offset -1080 ] -1081 memory-should-contain [ -1082 ¦ 3 <- 1 -1083 ¦ 4 <- 2 -1084 ] -1085 check-trace-count-for-label 0, [print-character] -1086 assume-console [ -1087 ¦ type [0] -1088 ] -1089 run [ -1090 ¦ editor-event-loop screen, console, e -1091 ] -1092 screen-should-contain [ -1093 ¦ . . -1094 ¦ .ab0 . -1095 ¦ .def . -1096 ¦ .╌╌╌╌╌╌╌╌╌╌. -1097 ¦ . . -1098 ] -1099 ] -1100 -1101 scenario editor-adjusts-column-at-empty-line [ -1102 local-scope -1103 assume-screen 10/width, 5/height -1104 s:text <- new [ -1105 def] -1106 e:&:editor <- new-editor s, 0/left, 10/right -1107 editor-render screen, e -1108 $clear-trace -1109 assume-console [ -1110 ¦ left-click 2, 3 -1111 ¦ press up-arrow -1112 ] -1113 run [ -1114 ¦ editor-event-loop screen, console, e -1115 ¦ 3:num/raw <- get *e, cursor-row:offset -1116 ¦ 4:num/raw <- get *e, cursor-column:offset -1117 ] -1118 memory-should-contain [ -1119 ¦ 3 <- 1 -1120 ¦ 4 <- 0 -1121 ] -1122 check-trace-count-for-label 0, [print-character] -1123 assume-console [ -1124 ¦ type [0] -1125 ] -1126 run [ -1127 ¦ editor-event-loop screen, console, e -1128 ] -1129 screen-should-contain [ -1130 ¦ . . -1131 ¦ .0 . -1132 ¦ .def . -1133 ¦ .╌╌╌╌╌╌╌╌╌╌. -1134 ¦ . . -1135 ] -1136 ] -1137 -1138 scenario editor-moves-to-previous-line-from-zero-margin [ -1139 local-scope -1140 assume-screen 10/width, 5/height -1141 # start out with three lines -1142 s:text <- new [abc -1143 def -1144 ghi] -1145 e:&:editor <- new-editor s, 0/left, 10/right -1146 editor-render screen, e -1147 $clear-trace -1148 # click on the third line and hit up-arrow, so you end up just after a newline -1149 assume-console [ -1150 ¦ left-click 3, 0 -1151 ¦ press up-arrow -1152 ] -1153 run [ -1154 ¦ editor-event-loop screen, console, e -1155 ¦ 3:num/raw <- get *e, cursor-row:offset -1156 ¦ 4:num/raw <- get *e, cursor-column:offset -1157 ] -1158 memory-should-contain [ -1159 ¦ 3 <- 2 -1160 ¦ 4 <- 0 -1161 ] -1162 check-trace-count-for-label 0, [print-character] -1163 assume-console [ -1164 ¦ type [0] -1165 ] -1166 run [ -1167 ¦ editor-event-loop screen, console, e -1168 ] -1169 screen-should-contain [ -1170 ¦ . . -1171 ¦ .abc . -1172 ¦ .0def . -1173 ¦ .ghi . -1174 ¦ .╌╌╌╌╌╌╌╌╌╌. -1175 ] -1176 ] -1177 -1178 scenario editor-moves-to-previous-line-from-left-margin [ -1179 local-scope -1180 assume-screen 10/width, 5/height -1181 # start out with three lines -1182 s:text <- new [abc -1183 def -1184 ghi] -1185 e:&:editor <- new-editor s, 1/left, 10/right -1186 editor-render screen, e -1187 $clear-trace -1188 # click on the third line and hit up-arrow, so you end up just after a newline -1189 assume-console [ -1190 ¦ left-click 3, 1 -1191 ¦ press up-arrow -1192 ] -1193 run [ -1194 ¦ editor-event-loop screen, console, e -1195 ¦ 3:num/raw <- get *e, cursor-row:offset -1196 ¦ 4:num/raw <- get *e, cursor-column:offset -1197 ] -1198 memory-should-contain [ -1199 ¦ 3 <- 2 -1200 ¦ 4 <- 1 -1201 ] -1202 check-trace-count-for-label 0, [print-character] -1203 assume-console [ -1204 ¦ type [0] -1205 ] -1206 run [ -1207 ¦ editor-event-loop screen, console, e -1208 ] -1209 screen-should-contain [ -1210 ¦ . . -1211 ¦ . abc . -1212 ¦ . 0def . -1213 ¦ . ghi . -1214 ¦ . ╌╌╌╌╌╌╌╌╌. -1215 ] -1216 ] -1217 -1218 scenario editor-moves-to-top-line-in-presence-of-wrapped-line [ -1219 local-scope -1220 assume-screen 10/width, 5/height -1221 e:&:editor <- new-editor [abcde], 0/left, 5/right -1222 editor-render screen, e -1223 screen-should-contain [ -1224 ¦ . . -1225 ¦ .abcd↩ . -1226 ¦ .e . -1227 ¦ .╌╌╌╌╌ . -1228 ] -1229 $clear-trace -1230 assume-console [ -1231 ¦ left-click 2, 0 -1232 ¦ press up-arrow -1233 ] -1234 run [ -1235 ¦ editor-event-loop screen, console, e -1236 ¦ 3:num/raw <- get *e, cursor-row:offset -1237 ¦ 4:num/raw <- get *e, cursor-column:offset -1238 ] -1239 memory-should-contain [ -1240 ¦ 3 <- 1 -1241 ¦ 4 <- 0 -1242 ] -1243 check-trace-count-for-label 0, [print-character] -1244 assume-console [ -1245 ¦ type [0] -1246 ] -1247 run [ -1248 ¦ editor-event-loop screen, console, e -1249 ] -1250 screen-should-contain [ -1251 ¦ . . -1252 ¦ .0abc↩ . -1253 ¦ .de . -1254 ¦ .╌╌╌╌╌ . -1255 ] -1256 ] -1257 -1258 scenario editor-moves-to-top-line-in-presence-of-wrapped-line-2 [ -1259 local-scope -1260 assume-screen 10/width, 5/height -1261 s:text <- new [abc -1262 defgh] -1263 e:&:editor <- new-editor s, 0/left, 5/right -1264 editor-render screen, e -1265 screen-should-contain [ -1266 ¦ . . -1267 ¦ .abc . -1268 ¦ .defg↩ . -1269 ¦ .h . -1270 ¦ .╌╌╌╌╌ . -1271 ] -1272 $clear-trace -1273 assume-console [ -1274 ¦ left-click 3, 0 + 553 ¦ press right-arrow # next line + 554 ¦ type [0] + 555 ] + 556 run [ + 557 ¦ editor-event-loop screen, console, e + 558 ] + 559 screen-should-contain [ + 560 ¦ . . + 561 ¦ . abc . + 562 ¦ . 0d . + 563 ¦ . ╌╌╌╌╌╌╌╌╌. + 564 ¦ . . + 565 ] + 566 ] + 567 + 568 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ + 569 local-scope + 570 assume-screen 10/width, 5/height + 571 e:&:editor <- new-editor [abcdef], 0/left, 5/right + 572 editor-render screen, e + 573 $clear-trace + 574 assume-console [ + 575 ¦ left-click 1, 3 + 576 ¦ press right-arrow + 577 ] + 578 run [ + 579 ¦ editor-event-loop screen, console, e + 580 ¦ 3:num/raw <- get *e, cursor-row:offset + 581 ¦ 4:num/raw <- get *e, cursor-column:offset + 582 ] + 583 screen-should-contain [ + 584 ¦ . . + 585 ¦ .abcd↩ . + 586 ¦ .ef . + 587 ¦ .╌╌╌╌╌ . + 588 ¦ . . + 589 ] + 590 memory-should-contain [ + 591 ¦ 3 <- 2 + 592 ¦ 4 <- 0 + 593 ] + 594 check-trace-count-for-label 0, [print-character] + 595 ] + 596 + 597 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ + 598 local-scope + 599 assume-screen 10/width, 5/height + 600 # line just barely wrapping + 601 e:&:editor <- new-editor [abcde], 0/left, 5/right + 602 editor-render screen, e + 603 $clear-trace + 604 # position cursor at last character before wrap and hit right-arrow + 605 assume-console [ + 606 ¦ left-click 1, 3 + 607 ¦ press right-arrow + 608 ] + 609 run [ + 610 ¦ editor-event-loop screen, console, e + 611 ¦ 3:num/raw <- get *e, cursor-row:offset + 612 ¦ 4:num/raw <- get *e, cursor-column:offset + 613 ] + 614 memory-should-contain [ + 615 ¦ 3 <- 2 + 616 ¦ 4 <- 0 + 617 ] + 618 # now hit right arrow again + 619 assume-console [ + 620 ¦ press right-arrow + 621 ] + 622 run [ + 623 ¦ editor-event-loop screen, console, e + 624 ¦ 3:num/raw <- get *e, cursor-row:offset + 625 ¦ 4:num/raw <- get *e, cursor-column:offset + 626 ] + 627 memory-should-contain [ + 628 ¦ 3 <- 2 + 629 ¦ 4 <- 1 + 630 ] + 631 check-trace-count-for-label 0, [print-character] + 632 ] + 633 + 634 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ + 635 local-scope + 636 assume-screen 10/width, 5/height + 637 e:&:editor <- new-editor [abcdef], 1/left, 6/right + 638 editor-render screen, e + 639 $clear-trace + 640 assume-console [ + 641 ¦ left-click 1, 4 + 642 ¦ press right-arrow + 643 ] + 644 run [ + 645 ¦ editor-event-loop screen, console, e + 646 ¦ 3:num/raw <- get *e, cursor-row:offset + 647 ¦ 4:num/raw <- get *e, cursor-column:offset + 648 ] + 649 screen-should-contain [ + 650 ¦ . . + 651 ¦ . abcd↩ . + 652 ¦ . ef . + 653 ¦ . ╌╌╌╌╌ . + 654 ¦ . . + 655 ] + 656 memory-should-contain [ + 657 ¦ 3 <- 2 + 658 ¦ 4 <- 1 + 659 ] + 660 check-trace-count-for-label 0, [print-character] + 661 ] + 662 + 663 scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ + 664 local-scope + 665 assume-screen 10/width, 5/height + 666 s:text <- new [abc + 667 d] + 668 e:&:editor <- new-editor s, 0/left, 10/right + 669 editor-render screen, e + 670 $clear-trace + 671 # move to end of line, press right-arrow, type a character + 672 assume-console [ + 673 ¦ left-click 1, 3 + 674 ¦ press right-arrow + 675 ¦ type [0] + 676 ] + 677 run [ + 678 ¦ editor-event-loop screen, console, e + 679 ] + 680 # new character should be in next line + 681 screen-should-contain [ + 682 ¦ . . + 683 ¦ .abc . + 684 ¦ .0d . + 685 ¦ .╌╌╌╌╌╌╌╌╌╌. + 686 ¦ . . + 687 ] + 688 check-trace-count-for-label 2, [print-character] + 689 ] + 690 + 691 # todo: ctrl-right: next word-end + 692 + 693 # left arrow + 694 + 695 scenario editor-moves-cursor-left-with-key [ + 696 local-scope + 697 assume-screen 10/width, 5/height + 698 e:&:editor <- new-editor [abc], 0/left, 10/right + 699 editor-render screen, e + 700 $clear-trace + 701 assume-console [ + 702 ¦ left-click 1, 2 + 703 ¦ press left-arrow + 704 ¦ type [0] + 705 ] + 706 run [ + 707 ¦ editor-event-loop screen, console, e + 708 ] + 709 screen-should-contain [ + 710 ¦ . . + 711 ¦ .a0bc . + 712 ¦ .╌╌╌╌╌╌╌╌╌╌. + 713 ¦ . . + 714 ] + 715 check-trace-count-for-label 3, [print-character] + 716 ] + 717 + 718 after <handle-special-key> [ + 719 { + 720 ¦ move-to-previous-character?:bool <- equal k, 65515/left-arrow + 721 ¦ break-unless move-to-previous-character? + 722 ¦ trace 10, [app], [left arrow] + 723 ¦ # if not at start of text (before-cursor at § sentinel) + 724 ¦ prev:&:duplex-list:char <- prev before-cursor + 725 ¦ return-unless prev, 0/don't-render + 726 ¦ <move-cursor-begin> + 727 ¦ go-render? <- move-cursor-coordinates-left editor + 728 ¦ before-cursor <- copy prev + 729 ¦ *editor <- put *editor, before-cursor:offset, before-cursor + 730 ¦ undo-coalesce-tag:num <- copy 1/left-arrow + 731 ¦ <move-cursor-end> + 732 ¦ return + 733 } + 734 ] + 735 + 736 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ + 737 local-scope + 738 assume-screen 10/width, 5/height + 739 # initialize editor with two lines + 740 s:text <- new [abc + 741 d] + 742 e:&:editor <- new-editor s, 0/left, 10/right + 743 editor-render screen, e + 744 $clear-trace + 745 # position cursor at start of second line (so there's no previous newline) + 746 assume-console [ + 747 ¦ left-click 2, 0 + 748 ¦ press left-arrow + 749 ] + 750 run [ + 751 ¦ editor-event-loop screen, console, e + 752 ¦ 3:num/raw <- get *e, cursor-row:offset + 753 ¦ 4:num/raw <- get *e, cursor-column:offset + 754 ] + 755 memory-should-contain [ + 756 ¦ 3 <- 1 + 757 ¦ 4 <- 3 + 758 ] + 759 check-trace-count-for-label 0, [print-character] + 760 ] + 761 + 762 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ + 763 local-scope + 764 assume-screen 10/width, 5/height + 765 # initialize editor with three lines + 766 s:text <- new [abc + 767 def + 768 g] + 769 e:&:editor <- new-editor s:text, 0/left, 10/right + 770 editor-render screen, e + 771 $clear-trace + 772 # position cursor further down (so there's a newline before the character at + 773 # the cursor) + 774 assume-console [ + 775 ¦ left-click 3, 0 + 776 ¦ press left-arrow + 777 ¦ type [0] + 778 ] + 779 run [ + 780 ¦ editor-event-loop screen, console, e + 781 ] + 782 screen-should-contain [ + 783 ¦ . . + 784 ¦ .abc . + 785 ¦ .def0 . + 786 ¦ .g . + 787 ¦ .╌╌╌╌╌╌╌╌╌╌. + 788 ] + 789 check-trace-count-for-label 1, [print-character] # just the '0' + 790 ] + 791 + 792 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ + 793 local-scope + 794 assume-screen 10/width, 5/height + 795 s:text <- new [abc + 796 def + 797 g] + 798 e:&:editor <- new-editor s, 0/left, 10/right + 799 editor-render screen, e + 800 $clear-trace + 801 # position cursor at start of text, press left-arrow, then type a character + 802 assume-console [ + 803 ¦ left-click 1, 0 + 804 ¦ press left-arrow + 805 ¦ type [0] + 806 ] + 807 run [ + 808 ¦ editor-event-loop screen, console, e + 809 ] + 810 # left-arrow should have had no effect + 811 screen-should-contain [ + 812 ¦ . . + 813 ¦ .0abc . + 814 ¦ .def . + 815 ¦ .g . + 816 ¦ .╌╌╌╌╌╌╌╌╌╌. + 817 ] + 818 check-trace-count-for-label 4, [print-character] # length of first line + 819 ] + 820 + 821 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ + 822 local-scope + 823 assume-screen 10/width, 5/height + 824 # initialize editor with text containing an empty line + 825 s:text <- new [abc + 826 + 827 d] + 828 e:&:editor <- new-editor s, 0/left, 10/right + 829 editor-render screen, e:&:editor + 830 $clear-trace + 831 # position cursor right after empty line + 832 assume-console [ + 833 ¦ left-click 3, 0 + 834 ¦ press left-arrow + 835 ¦ type [0] + 836 ] + 837 run [ + 838 ¦ editor-event-loop screen, console, e + 839 ] + 840 screen-should-contain [ + 841 ¦ . . + 842 ¦ .abc . + 843 ¦ .0 . + 844 ¦ .d . + 845 ¦ .╌╌╌╌╌╌╌╌╌╌. + 846 ] + 847 check-trace-count-for-label 1, [print-character] # just the '0' + 848 ] + 849 + 850 scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [ + 851 local-scope + 852 assume-screen 10/width, 5/height + 853 # initialize editor with a wrapping line + 854 e:&:editor <- new-editor [abcdef], 0/left, 5/right + 855 editor-render screen, e + 856 $clear-trace + 857 screen-should-contain [ + 858 ¦ . . + 859 ¦ .abcd↩ . + 860 ¦ .ef . + 861 ¦ .╌╌╌╌╌ . + 862 ¦ . . + 863 ] + 864 # position cursor right after empty line + 865 assume-console [ + 866 ¦ left-click 2, 0 + 867 ¦ press left-arrow + 868 ] + 869 run [ + 870 ¦ editor-event-loop screen, console, e + 871 ¦ 3:num/raw <- get *e, cursor-row:offset + 872 ¦ 4:num/raw <- get *e, cursor-column:offset + 873 ] + 874 memory-should-contain [ + 875 ¦ 3 <- 1 # previous row + 876 ¦ 4 <- 3 # right margin except wrap icon + 877 ] + 878 check-trace-count-for-label 0, [print-character] + 879 ] + 880 + 881 scenario editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [ + 882 local-scope + 883 assume-screen 10/width, 5/height + 884 # initialize editor with a wrapping line followed by a second line + 885 s:text <- new [abcdef + 886 g] + 887 e:&:editor <- new-editor s, 0/left, 5/right + 888 editor-render screen, e + 889 $clear-trace + 890 screen-should-contain [ + 891 ¦ . . + 892 ¦ .abcd↩ . + 893 ¦ .ef . + 894 ¦ .g . + 895 ¦ .╌╌╌╌╌ . + 896 ] + 897 # position cursor right after empty line + 898 assume-console [ + 899 ¦ left-click 3, 0 + 900 ¦ press left-arrow + 901 ] + 902 run [ + 903 ¦ editor-event-loop screen, console, e + 904 ¦ 3:num/raw <- get *e, cursor-row:offset + 905 ¦ 4:num/raw <- get *e, cursor-column:offset + 906 ] + 907 memory-should-contain [ + 908 ¦ 3 <- 2 # previous row + 909 ¦ 4 <- 2 # end of wrapped line + 910 ] + 911 check-trace-count-for-label 0, [print-character] + 912 ] + 913 + 914 scenario editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [ + 915 local-scope + 916 assume-screen 10/width, 5/height + 917 # initialize editor with a line on the verge of wrapping, followed by a second line + 918 s:text <- new [abcd + 919 e] + 920 e:&:editor <- new-editor s, 0/left, 5/right + 921 editor-render screen, e + 922 $clear-trace + 923 screen-should-contain [ + 924 ¦ . . + 925 ¦ .abcd . + 926 ¦ .e . + 927 ¦ .╌╌╌╌╌ . + 928 ¦ . . + 929 ] + 930 # position cursor right after empty line + 931 assume-console [ + 932 ¦ left-click 2, 0 + 933 ¦ press left-arrow + 934 ] + 935 run [ + 936 ¦ editor-event-loop screen, console, e + 937 ¦ 3:num/raw <- get *e, cursor-row:offset + 938 ¦ 4:num/raw <- get *e, cursor-column:offset + 939 ] + 940 memory-should-contain [ + 941 ¦ 3 <- 1 # previous row + 942 ¦ 4 <- 4 # end of wrapped line + 943 ] + 944 check-trace-count-for-label 0, [print-character] + 945 ] + 946 + 947 # todo: ctrl-left: previous word-start + 948 + 949 # up arrow + 950 + 951 scenario editor-moves-to-previous-line-with-up-arrow [ + 952 local-scope + 953 assume-screen 10/width, 5/height + 954 s:text <- new [abc + 955 def] + 956 e:&:editor <- new-editor s, 0/left, 10/right + 957 editor-render screen, e + 958 $clear-trace + 959 assume-console [ + 960 ¦ left-click 2, 1 + 961 ¦ press up-arrow + 962 ] + 963 run [ + 964 ¦ editor-event-loop screen, console, e + 965 ¦ 3:num/raw <- get *e, cursor-row:offset + 966 ¦ 4:num/raw <- get *e, cursor-column:offset + 967 ] + 968 memory-should-contain [ + 969 ¦ 3 <- 1 + 970 ¦ 4 <- 1 + 971 ] + 972 check-trace-count-for-label 0, [print-character] + 973 assume-console [ + 974 ¦ type [0] + 975 ] + 976 run [ + 977 ¦ editor-event-loop screen, console, e + 978 ] + 979 screen-should-contain [ + 980 ¦ . . + 981 ¦ .a0bc . + 982 ¦ .def . + 983 ¦ .╌╌╌╌╌╌╌╌╌╌. + 984 ¦ . . + 985 ] + 986 ] + 987 + 988 after <handle-special-key> [ + 989 { + 990 ¦ move-to-previous-line?:bool <- equal k, 65517/up-arrow + 991 ¦ break-unless move-to-previous-line? + 992 ¦ <move-cursor-begin> + 993 ¦ go-render? <- move-to-previous-line editor + 994 ¦ undo-coalesce-tag:num <- copy 3/up-arrow + 995 ¦ <move-cursor-end> + 996 ¦ return + 997 } + 998 ] + 999 +1000 def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [ +1001 local-scope +1002 load-ingredients +1003 go-render?:bool <- copy 0/false +1004 cursor-row:num <- get *editor, cursor-row:offset +1005 cursor-column:num <- get *editor, cursor-column:offset +1006 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +1007 left:num <- get *editor, left:offset +1008 right:num <- get *editor, right:offset +1009 already-at-top?:bool <- lesser-or-equal cursor-row, 1/top +1010 { +1011 ¦ # if cursor not at top, move it +1012 ¦ break-if already-at-top? +1013 ¦ # if not at start of screen line, move to start of screen line (previous newline) +1014 ¦ # then scan back another line +1015 ¦ # if either step fails, give up without modifying cursor or coordinates +1016 ¦ curr:&:duplex-list:char <- copy before-cursor +1017 ¦ old:&:duplex-list:char <- copy curr +1018 ¦ { +1019 ¦ ¦ at-left?:bool <- equal cursor-column, left +1020 ¦ ¦ break-if at-left? +1021 ¦ ¦ curr <- before-previous-screen-line curr, editor +1022 ¦ ¦ no-motion?:bool <- equal curr, old +1023 ¦ ¦ return-if no-motion? +1024 ¦ } +1025 ¦ { +1026 ¦ ¦ curr <- before-previous-screen-line curr, editor +1027 ¦ ¦ no-motion?:bool <- equal curr, old +1028 ¦ ¦ return-if no-motion? +1029 ¦ } +1030 ¦ before-cursor <- copy curr +1031 ¦ *editor <- put *editor, before-cursor:offset, before-cursor +1032 ¦ cursor-row <- subtract cursor-row, 1 +1033 ¦ *editor <- put *editor, cursor-row:offset, cursor-row +1034 ¦ # scan ahead to right column or until end of line +1035 ¦ target-column:num <- copy cursor-column +1036 ¦ cursor-column <- copy left +1037 ¦ *editor <- put *editor, cursor-column:offset, cursor-column +1038 ¦ { +1039 ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column +1040 ¦ ¦ break-if done? +1041 ¦ ¦ curr:&:duplex-list:char <- next before-cursor +1042 ¦ ¦ break-unless curr +1043 ¦ ¦ currc:char <- get *curr, value:offset +1044 ¦ ¦ at-newline?:bool <- equal currc, 10/newline +1045 ¦ ¦ break-if at-newline? +1046 ¦ ¦ # +1047 ¦ ¦ before-cursor <- copy curr +1048 ¦ ¦ *editor <- put *editor, before-cursor:offset, before-cursor +1049 ¦ ¦ cursor-column <- add cursor-column, 1 +1050 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column +1051 ¦ ¦ loop +1052 ¦ } +1053 ¦ return +1054 } +1055 { +1056 ¦ # if cursor already at top, scroll up +1057 ¦ break-unless already-at-top? +1058 ¦ <scroll-up> +1059 ¦ return 1/go-render +1060 } +1061 ] +1062 +1063 scenario editor-adjusts-column-at-previous-line [ +1064 local-scope +1065 assume-screen 10/width, 5/height +1066 s:text <- new [ab +1067 def] +1068 e:&:editor <- new-editor s, 0/left, 10/right +1069 editor-render screen, e +1070 $clear-trace +1071 assume-console [ +1072 ¦ left-click 2, 3 +1073 ¦ press up-arrow +1074 ] +1075 run [ +1076 ¦ editor-event-loop screen, console, e +1077 ¦ 3:num/raw <- get *e, cursor-row:offset +1078 ¦ 4:num/raw <- get *e, cursor-column:offset +1079 ] +1080 memory-should-contain [ +1081 ¦ 3 <- 1 +1082 ¦ 4 <- 2 +1083 ] +1084 check-trace-count-for-label 0, [print-character] +1085 assume-console [ +1086 ¦ type [0] +1087 ] +1088 run [ +1089 ¦ editor-event-loop screen, console, e +1090 ] +1091 screen-should-contain [ +1092 ¦ . . +1093 ¦ .ab0 . +1094 ¦ .def . +1095 ¦ .╌╌╌╌╌╌╌╌╌╌. +1096 ¦ . . +1097 ] +1098 ] +1099 +1100 scenario editor-adjusts-column-at-empty-line [ +1101 local-scope +1102 assume-screen 10/width, 5/height +1103 s:text <- new [ +1104 def] +1105 e:&:editor <- new-editor s, 0/left, 10/right +1106 editor-render screen, e +1107 $clear-trace +1108 assume-console [ +1109 ¦ left-click 2, 3 +1110 ¦ press up-arrow +1111 ] +1112 run [ +1113 ¦ editor-event-loop screen, console, e +1114 ¦ 3:num/raw <- get *e, cursor-row:offset +1115 ¦ 4:num/raw <- get *e, cursor-column:offset +1116 ] +1117 memory-should-contain [ +1118 ¦ 3 <- 1 +1119 ¦ 4 <- 0 +1120 ] +1121 check-trace-count-for-label 0, [print-character] +1122 assume-console [ +1123 ¦ type [0] +1124 ] +1125 run [ +1126 ¦ editor-event-loop screen, console, e +1127 ] +1128 screen-should-contain [ +1129 ¦ . . +1130 ¦ .0 . +1131 ¦ .def . +1132 ¦ .╌╌╌╌╌╌╌╌╌╌. +1133 ¦ . . +1134 ] +1135 ] +1136 +1137 scenario editor-moves-to-previous-line-from-zero-margin [ +1138 local-scope +1139 assume-screen 10/width, 5/height +1140 # start out with three lines +1141 s:text <- new [abc +1142 def +1143 ghi] +1144 e:&:editor <- new-editor s, 0/left, 10/right +1145 editor-render screen, e +1146 $clear-trace +1147 # click on the third line and hit up-arrow, so you end up just after a newline +1148 assume-console [ +1149 ¦ left-click 3, 0 +1150 ¦ press up-arrow +1151 ] +1152 run [ +1153 ¦ editor-event-loop screen, console, e +1154 ¦ 3:num/raw <- get *e, cursor-row:offset +1155 ¦ 4:num/raw <- get *e, cursor-column:offset +1156 ] +1157 memory-should-contain [ +1158 ¦ 3 <- 2 +1159 ¦ 4 <- 0 +1160 ] +1161 check-trace-count-for-label 0, [print-character] +1162 assume-console [ +1163 ¦ type [0] +1164 ] +1165 run [ +1166 ¦ editor-event-loop screen, console, e +1167 ] +1168 screen-should-contain [ +1169 ¦ . . +1170 ¦ .abc . +1171 ¦ .0def . +1172 ¦ .ghi . +1173 ¦ .╌╌╌╌╌╌╌╌╌╌. +1174 ] +1175 ] +1176 +1177 scenario editor-moves-to-previous-line-from-left-margin [ +1178 local-scope +1179 assume-screen 10/width, 5/height +1180 # start out with three lines +1181 s:text <- new [abc +1182 def +1183 ghi] +1184 e:&:editor <- new-editor s, 1/left, 10/right +1185 editor-render screen, e +1186 $clear-trace +1187 # click on the third line and hit up-arrow, so you end up just after a newline +1188 assume-console [ +1189 ¦ left-click 3, 1 +1190 ¦ press up-arrow +1191 ] +1192 run [ +1193 ¦ editor-event-loop screen, console, e +1194 ¦ 3:num/raw <- get *e, cursor-row:offset +1195 ¦ 4:num/raw <- get *e, cursor-column:offset +1196 ] +1197 memory-should-contain [ +1198 ¦ 3 <- 2 +1199 ¦ 4 <- 1 +1200 ] +1201 check-trace-count-for-label 0, [print-character] +1202 assume-console [ +1203 ¦ type [0] +1204 ] +1205 run [ +1206 ¦ editor-event-loop screen, console, e +1207 ] +1208 screen-should-contain [ +1209 ¦ . . +1210 ¦ . abc . +1211 ¦ . 0def . +1212 ¦ . ghi . +1213 ¦ . ╌╌╌╌╌╌╌╌╌. +1214 ] +1215 ] +1216 +1217 scenario editor-moves-to-top-line-in-presence-of-wrapped-line [ +1218 local-scope +1219 assume-screen 10/width, 5/height +1220 e:&:editor <- new-editor [abcde], 0/left, 5/right +1221 editor-render screen, e +1222 screen-should-contain [ +1223 ¦ . . +1224 ¦ .abcd↩ . +1225 ¦ .e . +1226 ¦ .╌╌╌╌╌ . +1227 ] +1228 $clear-trace +1229 assume-console [ +1230 ¦ left-click 2, 0 +1231 ¦ press up-arrow +1232 ] +1233 run [ +1234 ¦ editor-event-loop screen, console, e +1235 ¦ 3:num/raw <- get *e, cursor-row:offset +1236 ¦ 4:num/raw <- get *e, cursor-column:offset +1237 ] +1238 memory-should-contain [ +1239 ¦ 3 <- 1 +1240 ¦ 4 <- 0 +1241 ] +1242 check-trace-count-for-label 0, [print-character] +1243 assume-console [ +1244 ¦ type [0] +1245 ] +1246 run [ +1247 ¦ editor-event-loop screen, console, e +1248 ] +1249 screen-should-contain [ +1250 ¦ . . +1251 ¦ .0abc↩ . +1252 ¦ .de . +1253 ¦ .╌╌╌╌╌ . +1254 ] +1255 ] +1256 +1257 scenario editor-moves-to-top-line-in-presence-of-wrapped-line-2 [ +1258 local-scope +1259 assume-screen 10/width, 5/height +1260 s:text <- new [abc +1261 defgh] +1262 e:&:editor <- new-editor s, 0/left, 5/right +1263 editor-render screen, e +1264 screen-should-contain [ +1265 ¦ . . +1266 ¦ .abc . +1267 ¦ .defg↩ . +1268 ¦ .h . +1269 ¦ .╌╌╌╌╌ . +1270 ] +1271 $clear-trace +1272 assume-console [ +1273 ¦ left-click 3, 0 +1274 ¦ press up-arrow 1275 ¦ press up-arrow -1276 ¦ press up-arrow -1277 ] -1278 run [ -1279 ¦ editor-event-loop screen, console, e -1280 ¦ 3:num/raw <- get *e, cursor-row:offset -1281 ¦ 4:num/raw <- get *e, cursor-column:offset -1282 ] -1283 memory-should-contain [ -1284 ¦ 3 <- 1 -1285 ¦ 4 <- 0 -1286 ] -1287 check-trace-count-for-label 0, [print-character] -1288 assume-console [ -1289 ¦ type [0] -1290 ] -1291 run [ -1292 ¦ editor-event-loop screen, console, e -1293 ] -1294 screen-should-contain [ -1295 ¦ . . -1296 ¦ .0abc . -1297 ¦ .defg↩ . -1298 ¦ .h . -1299 ¦ .╌╌╌╌╌ . -1300 ] -1301 ] -1302 -1303 # down arrow -1304 -1305 scenario editor-moves-to-next-line-with-down-arrow [ -1306 local-scope -1307 assume-screen 10/width, 5/height -1308 s:text <- new [abc -1309 def] -1310 e:&:editor <- new-editor s, 0/left, 10/right -1311 editor-render screen, e -1312 $clear-trace -1313 # cursor starts out at (1, 0) -1314 assume-console [ -1315 ¦ press down-arrow -1316 ] -1317 run [ -1318 ¦ editor-event-loop screen, console, e -1319 ¦ 3:num/raw <- get *e, cursor-row:offset -1320 ¦ 4:num/raw <- get *e, cursor-column:offset -1321 ] -1322 # ..and ends at (2, 0) -1323 memory-should-contain [ -1324 ¦ 3 <- 2 -1325 ¦ 4 <- 0 -1326 ] -1327 check-trace-count-for-label 0, [print-character] -1328 assume-console [ -1329 ¦ type [0] -1330 ] -1331 run [ -1332 ¦ editor-event-loop screen, console, e -1333 ] -1334 screen-should-contain [ -1335 ¦ . . -1336 ¦ .abc . -1337 ¦ .0def . -1338 ¦ .╌╌╌╌╌╌╌╌╌╌. -1339 ¦ . . -1340 ] -1341 ] -1342 -1343 after <handle-special-key> [ -1344 { -1345 ¦ move-to-next-line?:bool <- equal k, 65516/down-arrow -1346 ¦ break-unless move-to-next-line? -1347 ¦ <move-cursor-begin> -1348 ¦ go-render? <- move-to-next-line editor, screen-height -1349 ¦ undo-coalesce-tag:num <- copy 4/down-arrow -1350 ¦ <move-cursor-end> -1351 ¦ return -1352 } -1353 ] -1354 -1355 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ -1356 local-scope -1357 load-ingredients -1358 cursor-row:num <- get *editor, cursor-row:offset -1359 cursor-column:num <- get *editor, cursor-column:offset -1360 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -1361 left:num <- get *editor, left:offset -1362 right:num <- get *editor, right:offset -1363 last-line:num <- subtract screen-height, 1 -1364 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line +1276 ] +1277 run [ +1278 ¦ editor-event-loop screen, console, e +1279 ¦ 3:num/raw <- get *e, cursor-row:offset +1280 ¦ 4:num/raw <- get *e, cursor-column:offset +1281 ] +1282 memory-should-contain [ +1283 ¦ 3 <- 1 +1284 ¦ 4 <- 0 +1285 ] +1286 check-trace-count-for-label 0, [print-character] +1287 assume-console [ +1288 ¦ type [0] +1289 ] +1290 run [ +1291 ¦ editor-event-loop screen, console, e +1292 ] +1293 screen-should-contain [ +1294 ¦ . . +1295 ¦ .0abc . +1296 ¦ .defg↩ . +1297 ¦ .h . +1298 ¦ .╌╌╌╌╌ . +1299 ] +1300 ] +1301 +1302 # down arrow +1303 +1304 scenario editor-moves-to-next-line-with-down-arrow [ +1305 local-scope +1306 assume-screen 10/width, 5/height +1307 s:text <- new [abc +1308 def] +1309 e:&:editor <- new-editor s, 0/left, 10/right +1310 editor-render screen, e +1311 $clear-trace +1312 # cursor starts out at (1, 0) +1313 assume-console [ +1314 ¦ press down-arrow +1315 ] +1316 run [ +1317 ¦ editor-event-loop screen, console, e +1318 ¦ 3:num/raw <- get *e, cursor-row:offset +1319 ¦ 4:num/raw <- get *e, cursor-column:offset +1320 ] +1321 # ..and ends at (2, 0) +1322 memory-should-contain [ +1323 ¦ 3 <- 2 +1324 ¦ 4 <- 0 +1325 ] +1326 check-trace-count-for-label 0, [print-character] +1327 assume-console [ +1328 ¦ type [0] +1329 ] +1330 run [ +1331 ¦ editor-event-loop screen, console, e +1332 ] +1333 screen-should-contain [ +1334 ¦ . . +1335 ¦ .abc . +1336 ¦ .0def . +1337 ¦ .╌╌╌╌╌╌╌╌╌╌. +1338 ¦ . . +1339 ] +1340 ] +1341 +1342 after <handle-special-key> [ +1343 { +1344 ¦ move-to-next-line?:bool <- equal k, 65516/down-arrow +1345 ¦ break-unless move-to-next-line? +1346 ¦ <move-cursor-begin> +1347 ¦ go-render? <- move-to-next-line editor, screen-height +1348 ¦ undo-coalesce-tag:num <- copy 4/down-arrow +1349 ¦ <move-cursor-end> +1350 ¦ return +1351 } +1352 ] +1353 +1354 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ +1355 local-scope +1356 load-ingredients +1357 cursor-row:num <- get *editor, cursor-row:offset +1358 cursor-column:num <- get *editor, cursor-column:offset +1359 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +1360 left:num <- get *editor, left:offset +1361 right:num <- get *editor, right:offset +1362 last-line:num <- subtract screen-height, 1 +1363 bottom:num <- get *editor, bottom:offset +1364 at-bottom-of-screen?:bool <- greater-or-equal bottom, last-line 1365 { -1366 ¦ # if cursor not at bottom, move it -1367 ¦ break-if already-at-bottom? -1368 ¦ # scan to start of next line, then to right column or until end of line -1369 ¦ max:num <- subtract right, left -1370 ¦ next-line:&:duplex-list:char <- before-start-of-next-line before-cursor, max +1366 ¦ break-if before-cursor +1367 ¦ { +1368 ¦ ¦ break-if at-bottom-of-screen? +1369 ¦ ¦ return 0/don't-render +1370 ¦ } 1371 ¦ { -1372 ¦ ¦ # already at end of buffer? try to scroll up (so we can see more -1373 ¦ ¦ # warnings or sandboxes below) -1374 ¦ ¦ no-motion?:bool <- equal next-line, before-cursor -1375 ¦ ¦ break-unless no-motion? -1376 ¦ ¦ scroll?:bool <- greater-than cursor-row, 1 -1377 ¦ ¦ break-if scroll?, +try-to-scroll -1378 ¦ ¦ return 0/don't-render -1379 ¦ } -1380 ¦ cursor-row <- add cursor-row, 1 -1381 ¦ *editor <- put *editor, cursor-row:offset, cursor-row -1382 ¦ before-cursor <- copy next-line -1383 ¦ *editor <- put *editor, before-cursor:offset, before-cursor -1384 ¦ target-column:num <- copy cursor-column -1385 ¦ cursor-column <- copy left -1386 ¦ *editor <- put *editor, cursor-column:offset, cursor-column -1387 ¦ { -1388 ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column -1389 ¦ ¦ break-if done? -1390 ¦ ¦ curr:&:duplex-list:char <- next before-cursor -1391 ¦ ¦ break-unless curr -1392 ¦ ¦ currc:char <- get *curr, value:offset -1393 ¦ ¦ at-newline?:bool <- equal currc, 10/newline -1394 ¦ ¦ break-if at-newline? -1395 ¦ ¦ # -1396 ¦ ¦ before-cursor <- copy curr -1397 ¦ ¦ *editor <- put *editor, before-cursor:offset, before-cursor -1398 ¦ ¦ cursor-column <- add cursor-column, 1 -1399 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column -1400 ¦ ¦ loop -1401 ¦ } -1402 ¦ return 0/don't-render -1403 } -1404 +try-to-scroll -1405 <scroll-down> -1406 go-render? <- copy 1/true -1407 ] -1408 -1409 scenario editor-adjusts-column-at-next-line [ -1410 local-scope -1411 assume-screen 10/width, 5/height -1412 s:text <- new [abc -1413 de] -1414 e:&:editor <- new-editor s, 0/left, 10/right -1415 editor-render screen, e -1416 $clear-trace -1417 assume-console [ -1418 ¦ left-click 1, 3 -1419 ¦ press down-arrow -1420 ] -1421 run [ -1422 ¦ editor-event-loop screen, console, e -1423 ¦ 3:num/raw <- get *e, cursor-row:offset -1424 ¦ 4:num/raw <- get *e, cursor-column:offset -1425 ] -1426 memory-should-contain [ -1427 ¦ 3 <- 2 -1428 ¦ 4 <- 2 -1429 ] -1430 check-trace-count-for-label 0, [print-character] -1431 assume-console [ -1432 ¦ type [0] -1433 ] -1434 run [ -1435 ¦ editor-event-loop screen, console, e -1436 ] -1437 screen-should-contain [ -1438 ¦ . . -1439 ¦ .abc . -1440 ¦ .de0 . -1441 ¦ .╌╌╌╌╌╌╌╌╌╌. -1442 ¦ . . -1443 ] -1444 ] -1445 -1446 # ctrl-a/home - move cursor to start of line -1447 -1448 scenario editor-moves-to-start-of-line-with-ctrl-a [ -1449 local-scope -1450 assume-screen 10/width, 5/height -1451 s:text <- new [123 -1452 456] -1453 e:&:editor <- new-editor s, 0/left, 10/right -1454 editor-render screen, e -1455 $clear-trace -1456 # start on second line, press ctrl-a -1457 assume-console [ -1458 ¦ left-click 2, 3 -1459 ¦ press ctrl-a -1460 ] -1461 run [ -1462 ¦ editor-event-loop screen, console, e -1463 ¦ 4:num/raw <- get *e, cursor-row:offset -1464 ¦ 5:num/raw <- get *e, cursor-column:offset +1372 ¦ ¦ break-unless at-bottom-of-screen? +1373 ¦ ¦ jump +try-to-scroll +1374 ¦ } +1375 } +1376 next:&:duplex-list:char <- next before-cursor +1377 { +1378 ¦ break-if next +1379 ¦ { +1380 ¦ ¦ break-if at-bottom-of-screen? +1381 ¦ ¦ return 0/don't-render +1382 ¦ } +1383 ¦ { +1384 ¦ ¦ break-unless at-bottom-of-screen? +1385 ¦ ¦ jump +try-to-scroll +1386 ¦ } +1387 } +1388 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line +1389 { +1390 ¦ # if cursor not at bottom, move it +1391 ¦ break-if already-at-bottom? +1392 ¦ target-column:num <- copy cursor-column +1393 ¦ # scan to start of next line +1394 ¦ { +1395 ¦ ¦ next:&:duplex-list:char <- next before-cursor +1396 ¦ ¦ break-unless next +1397 ¦ ¦ done?:bool <- greater-or-equal cursor-column, right +1398 ¦ ¦ break-if done? +1399 ¦ ¦ cursor-column <- add cursor-column, 1 +1400 ¦ ¦ before-cursor <- copy next +1401 ¦ ¦ c:char <- get *next, value:offset +1402 ¦ ¦ at-newline?:bool <- equal c, 10/newline +1403 ¦ ¦ break-if at-newline? +1404 ¦ ¦ loop +1405 ¦ } +1406 ¦ { +1407 ¦ ¦ break-if next +1408 ¦ ¦ { +1409 ¦ ¦ ¦ break-if at-bottom-of-screen? +1410 ¦ ¦ ¦ return 0/don't-render +1411 ¦ ¦ } +1412 ¦ ¦ { +1413 ¦ ¦ ¦ break-unless at-bottom-of-screen? +1414 ¦ ¦ ¦ jump +try-to-scroll +1415 ¦ ¦ } +1416 ¦ } +1417 ¦ cursor-row <- add cursor-row, 1 +1418 ¦ cursor-column <- copy left +1419 ¦ { +1420 ¦ ¦ next:&:duplex-list:char <- next before-cursor +1421 ¦ ¦ break-unless next +1422 ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column +1423 ¦ ¦ break-if done? +1424 ¦ ¦ cursor-column <- add cursor-column, 1 +1425 ¦ ¦ before-cursor <- copy next +1426 ¦ ¦ loop +1427 ¦ } +1428 ¦ *editor <- put *editor, before-cursor:offset, before-cursor +1429 ¦ *editor <- put *editor, cursor-column:offset, cursor-column +1430 ¦ *editor <- put *editor, cursor-row:offset, cursor-row +1431 ¦ return 0/don't-render +1432 } +1433 +try-to-scroll +1434 <scroll-down> +1435 go-render? <- copy 1/true +1436 ] +1437 +1438 scenario editor-adjusts-column-at-next-line [ +1439 local-scope +1440 assume-screen 10/width, 5/height +1441 s:text <- new [abc +1442 de] +1443 e:&:editor <- new-editor s, 0/left, 10/right +1444 editor-render screen, e +1445 $clear-trace +1446 assume-console [ +1447 ¦ left-click 1, 3 +1448 ¦ press down-arrow +1449 ] +1450 run [ +1451 ¦ editor-event-loop screen, console, e +1452 ¦ 3:num/raw <- get *e, cursor-row:offset +1453 ¦ 4:num/raw <- get *e, cursor-column:offset +1454 ] +1455 memory-should-contain [ +1456 ¦ 3 <- 2 +1457 ¦ 4 <- 2 +1458 ] +1459 check-trace-count-for-label 0, [print-character] +1460 assume-console [ +1461 ¦ type [0] +1462 ] +1463 run [ +1464 ¦ editor-event-loop screen, console, e 1465 ] -1466 # cursor moves to start of line -1467 memory-should-contain [ -1468 ¦ 4 <- 2 -1469 ¦ 5 <- 0 -1470 ] -1471 check-trace-count-for-label 0, [print-character] -1472 ] -1473 -1474 after <handle-special-character> [ -1475 { -1476 ¦ move-to-start-of-line?:bool <- equal c, 1/ctrl-a -1477 ¦ break-unless move-to-start-of-line? -1478 ¦ <move-cursor-begin> -1479 ¦ move-to-start-of-screen-line editor -1480 ¦ undo-coalesce-tag:num <- copy 0/never -1481 ¦ <move-cursor-end> -1482 ¦ return 0/don't-render -1483 } -1484 ] -1485 -1486 after <handle-special-key> [ -1487 { -1488 ¦ move-to-start-of-line?:bool <- equal k, 65521/home -1489 ¦ break-unless move-to-start-of-line? -1490 ¦ <move-cursor-begin> -1491 ¦ move-to-start-of-screen-line editor -1492 ¦ undo-coalesce-tag:num <- copy 0/never -1493 ¦ <move-cursor-end> -1494 ¦ return 0/don't-render -1495 } -1496 ] -1497 -1498 # handles wrapped lines -1499 # precondition: cursor-column should be in a consistent state -1500 def move-to-start-of-screen-line editor:&:editor -> editor:&:editor [ -1501 local-scope -1502 load-ingredients -1503 # update cursor column -1504 left:num <- get *editor, left:offset -1505 col:num <- get *editor, cursor-column:offset -1506 # update before-cursor -1507 curr:&:duplex-list:char <- get *editor, before-cursor:offset -1508 # while not at start of line, move -1509 { -1510 ¦ done?:bool <- equal col, left -1511 ¦ break-if done? -1512 ¦ assert curr, [move-to-start-of-line tried to move before start of text] -1513 ¦ curr <- prev curr -1514 ¦ col <- subtract col, 1 -1515 ¦ loop -1516 } -1517 *editor <- put *editor, cursor-column:offset, col -1518 *editor <- put *editor, before-cursor:offset, curr -1519 ] -1520 -1521 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [ -1522 local-scope -1523 assume-screen 10/width, 5/height -1524 s:text <- new [123 -1525 456] -1526 e:&:editor <- new-editor s, 0/left, 10/right -1527 editor-render screen, e -1528 $clear-trace -1529 # start on first line (no newline before), press ctrl-a -1530 assume-console [ -1531 ¦ left-click 1, 3 -1532 ¦ press ctrl-a -1533 ] -1534 run [ -1535 ¦ editor-event-loop screen, console, e -1536 ¦ 4:num/raw <- get *e, cursor-row:offset -1537 ¦ 5:num/raw <- get *e, cursor-column:offset -1538 ] -1539 # cursor moves to start of line -1540 memory-should-contain [ -1541 ¦ 4 <- 1 -1542 ¦ 5 <- 0 -1543 ] -1544 check-trace-count-for-label 0, [print-character] -1545 ] -1546 -1547 scenario editor-moves-to-start-of-line-with-home [ -1548 local-scope -1549 assume-screen 10/width, 5/height -1550 s:text <- new [123 -1551 456] -1552 e:&:editor <- new-editor s, 0/left, 10/right -1553 $clear-trace -1554 # start on second line, press 'home' -1555 assume-console [ -1556 ¦ left-click 2, 3 -1557 ¦ press home -1558 ] -1559 run [ -1560 ¦ editor-event-loop screen, console, e -1561 ¦ 3:num/raw <- get *e, cursor-row:offset -1562 ¦ 4:num/raw <- get *e, cursor-column:offset -1563 ] -1564 # cursor moves to start of line -1565 memory-should-contain [ -1566 ¦ 3 <- 2 -1567 ¦ 4 <- 0 -1568 ] -1569 check-trace-count-for-label 0, [print-character] -1570 ] -1571 -1572 scenario editor-moves-to-start-of-line-with-home-2 [ -1573 local-scope -1574 assume-screen 10/width, 5/height -1575 s:text <- new [123 -1576 456] -1577 e:&:editor <- new-editor s, 0/left, 10/right -1578 editor-render screen, e -1579 $clear-trace -1580 # start on first line (no newline before), press 'home' -1581 assume-console [ -1582 ¦ left-click 1, 3 -1583 ¦ press home -1584 ] -1585 run [ -1586 ¦ editor-event-loop screen, console, e -1587 ¦ 3:num/raw <- get *e, cursor-row:offset -1588 ¦ 4:num/raw <- get *e, cursor-column:offset -1589 ] -1590 # cursor moves to start of line -1591 memory-should-contain [ -1592 ¦ 3 <- 1 -1593 ¦ 4 <- 0 -1594 ] -1595 check-trace-count-for-label 0, [print-character] -1596 ] -1597 -1598 scenario editor-moves-to-start-of-screen-line-with-ctrl-a [ -1599 local-scope -1600 assume-screen 10/width, 5/height -1601 e:&:editor <- new-editor [123456], 0/left, 5/right -1602 editor-render screen, e -1603 screen-should-contain [ -1604 ¦ . . -1605 ¦ .1234↩ . -1606 ¦ .56 . -1607 ¦ .╌╌╌╌╌ . -1608 ¦ . . -1609 ] -1610 $clear-trace -1611 # start on second line, press ctrl-a then up -1612 assume-console [ -1613 ¦ left-click 2, 1 -1614 ¦ press ctrl-a -1615 ¦ press up-arrow +1466 screen-should-contain [ +1467 ¦ . . +1468 ¦ .abc . +1469 ¦ .de0 . +1470 ¦ .╌╌╌╌╌╌╌╌╌╌. +1471 ¦ . . +1472 ] +1473 ] +1474 +1475 scenario editor-moves-down-within-wrapped-line [ +1476 local-scope +1477 assume-screen 10/width, 5/height +1478 e:&:editor <- new-editor [abcdefghijklmno], 0/left, 10/right +1479 editor-render screen, e +1480 screen-should-contain [ +1481 ¦ . . +1482 ¦ .abcdefghi↩. +1483 ¦ .jklmno . +1484 ¦ .╌╌╌╌╌╌╌╌╌╌. +1485 ¦ . . +1486 ] +1487 # position cursor on first screen line, but past end of second screen line +1488 assume-console [ +1489 ¦ left-click 1, 8 +1490 ¦ press down-arrow +1491 ] +1492 run [ +1493 ¦ editor-event-loop screen, console, e +1494 ¦ 3:num/raw <- get *e, cursor-row:offset +1495 ¦ 4:num/raw <- get *e, cursor-column:offset +1496 ] +1497 # cursor should be at end of second screen line +1498 memory-should-contain [ +1499 ¦ 3 <- 2 +1500 ¦ 4 <- 6 +1501 ] +1502 ] +1503 +1504 # ctrl-a/home - move cursor to start of line +1505 +1506 scenario editor-moves-to-start-of-line-with-ctrl-a [ +1507 local-scope +1508 assume-screen 10/width, 5/height +1509 s:text <- new [123 +1510 456] +1511 e:&:editor <- new-editor s, 0/left, 10/right +1512 editor-render screen, e +1513 $clear-trace +1514 # start on second line, press ctrl-a +1515 assume-console [ +1516 ¦ left-click 2, 3 +1517 ¦ press ctrl-a +1518 ] +1519 run [ +1520 ¦ editor-event-loop screen, console, e +1521 ¦ 4:num/raw <- get *e, cursor-row:offset +1522 ¦ 5:num/raw <- get *e, cursor-column:offset +1523 ] +1524 # cursor moves to start of line +1525 memory-should-contain [ +1526 ¦ 4 <- 2 +1527 ¦ 5 <- 0 +1528 ] +1529 check-trace-count-for-label 0, [print-character] +1530 ] +1531 +1532 after <handle-special-character> [ +1533 { +1534 ¦ move-to-start-of-line?:bool <- equal c, 1/ctrl-a +1535 ¦ break-unless move-to-start-of-line? +1536 ¦ <move-cursor-begin> +1537 ¦ move-to-start-of-screen-line editor +1538 ¦ undo-coalesce-tag:num <- copy 0/never +1539 ¦ <move-cursor-end> +1540 ¦ return 0/don't-render +1541 } +1542 ] +1543 +1544 after <handle-special-key> [ +1545 { +1546 ¦ move-to-start-of-line?:bool <- equal k, 65521/home +1547 ¦ break-unless move-to-start-of-line? +1548 ¦ <move-cursor-begin> +1549 ¦ move-to-start-of-screen-line editor +1550 ¦ undo-coalesce-tag:num <- copy 0/never +1551 ¦ <move-cursor-end> +1552 ¦ return 0/don't-render +1553 } +1554 ] +1555 +1556 # handles wrapped lines +1557 # precondition: cursor-column should be in a consistent state +1558 def move-to-start-of-screen-line editor:&:editor -> editor:&:editor [ +1559 local-scope +1560 load-ingredients +1561 # update cursor column +1562 left:num <- get *editor, left:offset +1563 col:num <- get *editor, cursor-column:offset +1564 # update before-cursor +1565 curr:&:duplex-list:char <- get *editor, before-cursor:offset +1566 # while not at start of line, move +1567 { +1568 ¦ done?:bool <- equal col, left +1569 ¦ break-if done? +1570 ¦ assert curr, [move-to-start-of-line tried to move before start of text] +1571 ¦ curr <- prev curr +1572 ¦ col <- subtract col, 1 +1573 ¦ loop +1574 } +1575 *editor <- put *editor, cursor-column:offset, col +1576 *editor <- put *editor, before-cursor:offset, curr +1577 ] +1578 +1579 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [ +1580 local-scope +1581 assume-screen 10/width, 5/height +1582 s:text <- new [123 +1583 456] +1584 e:&:editor <- new-editor s, 0/left, 10/right +1585 editor-render screen, e +1586 $clear-trace +1587 # start on first line (no newline before), press ctrl-a +1588 assume-console [ +1589 ¦ left-click 1, 3 +1590 ¦ press ctrl-a +1591 ] +1592 run [ +1593 ¦ editor-event-loop screen, console, e +1594 ¦ 4:num/raw <- get *e, cursor-row:offset +1595 ¦ 5:num/raw <- get *e, cursor-column:offset +1596 ] +1597 # cursor moves to start of line +1598 memory-should-contain [ +1599 ¦ 4 <- 1 +1600 ¦ 5 <- 0 +1601 ] +1602 check-trace-count-for-label 0, [print-character] +1603 ] +1604 +1605 scenario editor-moves-to-start-of-line-with-home [ +1606 local-scope +1607 assume-screen 10/width, 5/height +1608 s:text <- new [123 +1609 456] +1610 e:&:editor <- new-editor s, 0/left, 10/right +1611 $clear-trace +1612 # start on second line, press 'home' +1613 assume-console [ +1614 ¦ left-click 2, 3 +1615 ¦ press home 1616 ] 1617 run [ 1618 ¦ editor-event-loop screen, console, e -1619 ¦ 4:num/raw <- get *e, cursor-row:offset -1620 ¦ 5:num/raw <- get *e, cursor-column:offset +1619 ¦ 3:num/raw <- get *e, cursor-row:offset +1620 ¦ 4:num/raw <- get *e, cursor-column:offset 1621 ] -1622 # cursor moves to start of first line +1622 # cursor moves to start of line 1623 memory-should-contain [ -1624 ¦ 4 <- 1 # cursor-row -1625 ¦ 5 <- 0 # cursor-column +1624 ¦ 3 <- 2 +1625 ¦ 4 <- 0 1626 ] 1627 check-trace-count-for-label 0, [print-character] -1628 # make sure before-cursor is in sync -1629 assume-console [ -1630 ¦ type [a] -1631 ] -1632 run [ -1633 ¦ editor-event-loop screen, console, e -1634 ¦ 4:num/raw <- get *e, cursor-row:offset -1635 ¦ 5:num/raw <- get *e, cursor-column:offset -1636 ] -1637 screen-should-contain [ -1638 ¦ . . -1639 ¦ .a123↩ . -1640 ¦ .456 . -1641 ¦ .╌╌╌╌╌ . -1642 ¦ . . -1643 ] -1644 memory-should-contain [ -1645 ¦ 4 <- 1 # cursor-row -1646 ¦ 5 <- 1 # cursor-column +1628 ] +1629 +1630 scenario editor-moves-to-start-of-line-with-home-2 [ +1631 local-scope +1632 assume-screen 10/width, 5/height +1633 s:text <- new [123 +1634 456] +1635 e:&:editor <- new-editor s, 0/left, 10/right +1636 editor-render screen, e +1637 $clear-trace +1638 # start on first line (no newline before), press 'home' +1639 assume-console [ +1640 ¦ left-click 1, 3 +1641 ¦ press home +1642 ] +1643 run [ +1644 ¦ editor-event-loop screen, console, e +1645 ¦ 3:num/raw <- get *e, cursor-row:offset +1646 ¦ 4:num/raw <- get *e, cursor-column:offset 1647 ] -1648 ] -1649 -1650 # ctrl-e/end - move cursor to end of line -1651 -1652 scenario editor-moves-to-end-of-line-with-ctrl-e [ -1653 local-scope -1654 assume-screen 10/width, 5/height -1655 s:text <- new [123 -1656 456] -1657 e:&:editor <- new-editor s, 0/left, 10/right -1658 editor-render screen, e -1659 $clear-trace -1660 # start on first line, press ctrl-e -1661 assume-console [ -1662 ¦ left-click 1, 1 -1663 ¦ press ctrl-e -1664 ] -1665 run [ -1666 ¦ editor-event-loop screen, console, e -1667 ¦ 4:num/raw <- get *e, cursor-row:offset -1668 ¦ 5:num/raw <- get *e, cursor-column:offset -1669 ] -1670 # cursor moves to end of line -1671 memory-should-contain [ -1672 ¦ 4 <- 1 -1673 ¦ 5 <- 3 +1648 # cursor moves to start of line +1649 memory-should-contain [ +1650 ¦ 3 <- 1 +1651 ¦ 4 <- 0 +1652 ] +1653 check-trace-count-for-label 0, [print-character] +1654 ] +1655 +1656 scenario editor-moves-to-start-of-screen-line-with-ctrl-a [ +1657 local-scope +1658 assume-screen 10/width, 5/height +1659 e:&:editor <- new-editor [123456], 0/left, 5/right +1660 editor-render screen, e +1661 screen-should-contain [ +1662 ¦ . . +1663 ¦ .1234↩ . +1664 ¦ .56 . +1665 ¦ .╌╌╌╌╌ . +1666 ¦ . . +1667 ] +1668 $clear-trace +1669 # start on second line, press ctrl-a then up +1670 assume-console [ +1671 ¦ left-click 2, 1 +1672 ¦ press ctrl-a +1673 ¦ press up-arrow 1674 ] -1675 check-trace-count-for-label 0, [print-character] -1676 # editor inserts future characters at cursor -1677 assume-console [ -1678 ¦ type [z] +1675 run [ +1676 ¦ editor-event-loop screen, console, e +1677 ¦ 4:num/raw <- get *e, cursor-row:offset +1678 ¦ 5:num/raw <- get *e, cursor-column:offset 1679 ] -1680 run [ -1681 ¦ editor-event-loop screen, console, e -1682 ¦ 4:num/raw <- get *e, cursor-row:offset -1683 ¦ 5:num/raw <- get *e, cursor-column:offset +1680 # cursor moves to start of first line +1681 memory-should-contain [ +1682 ¦ 4 <- 1 # cursor-row +1683 ¦ 5 <- 0 # cursor-column 1684 ] -1685 memory-should-contain [ -1686 ¦ 4 <- 1 -1687 ¦ 5 <- 4 -1688 ] -1689 screen-should-contain [ -1690 ¦ . . -1691 ¦ .123z . -1692 ¦ .456 . -1693 ¦ .╌╌╌╌╌╌╌╌╌╌. -1694 ¦ . . -1695 ] -1696 check-trace-count-for-label 1, [print-character] -1697 ] -1698 -1699 after <handle-special-character> [ -1700 { -1701 ¦ move-to-end-of-line?:bool <- equal c, 5/ctrl-e -1702 ¦ break-unless move-to-end-of-line? -1703 ¦ <move-cursor-begin> -1704 ¦ move-to-end-of-line editor -1705 ¦ undo-coalesce-tag:num <- copy 0/never -1706 ¦ <move-cursor-end> -1707 ¦ return 0/don't-render -1708 } -1709 ] -1710 -1711 after <handle-special-key> [ -1712 { -1713 ¦ move-to-end-of-line?:bool <- equal k, 65520/end -1714 ¦ break-unless move-to-end-of-line? -1715 ¦ <move-cursor-begin> -1716 ¦ move-to-end-of-line editor -1717 ¦ undo-coalesce-tag:num <- copy 0/never -1718 ¦ <move-cursor-end> -1719 ¦ return 0/don't-render -1720 } -1721 ] -1722 -1723 def move-to-end-of-line editor:&:editor -> editor:&:editor [ -1724 local-scope -1725 load-ingredients -1726 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -1727 cursor-column:num <- get *editor, cursor-column:offset -1728 right:num <- get *editor, right:offset -1729 # while not at end of line, move -1730 { -1731 ¦ next:&:duplex-list:char <- next before-cursor -1732 ¦ break-unless next # end of text -1733 ¦ nextc:char <- get *next, value:offset -1734 ¦ at-end-of-line?:bool <- equal nextc, 10/newline -1735 ¦ break-if at-end-of-line? -1736 ¦ cursor-column <- add cursor-column, 1 -1737 ¦ at-right?:bool <- equal cursor-column, right -1738 ¦ break-if at-right? -1739 ¦ *editor <- put *editor, cursor-column:offset, cursor-column -1740 ¦ before-cursor <- copy next -1741 ¦ *editor <- put *editor, before-cursor:offset, before-cursor -1742 ¦ loop -1743 } -1744 ] -1745 -1746 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [ -1747 local-scope -1748 assume-screen 10/width, 5/height -1749 s:text <- new [123 -1750 456] -1751 e:&:editor <- new-editor s, 0/left, 10/right -1752 editor-render screen, e -1753 $clear-trace -1754 # start on second line (no newline after), press ctrl-e -1755 assume-console [ -1756 ¦ left-click 2, 1 -1757 ¦ press ctrl-e -1758 ] -1759 run [ -1760 ¦ editor-event-loop screen, console, e -1761 ¦ 4:num/raw <- get *e, cursor-row:offset -1762 ¦ 5:num/raw <- get *e, cursor-column:offset -1763 ] -1764 # cursor moves to end of line -1765 memory-should-contain [ -1766 ¦ 4 <- 2 -1767 ¦ 5 <- 3 -1768 ] -1769 check-trace-count-for-label 0, [print-character] -1770 ] -1771 -1772 scenario editor-moves-to-end-of-line-with-end [ -1773 local-scope -1774 assume-screen 10/width, 5/height -1775 s:text <- new [123 -1776 456] -1777 e:&:editor <- new-editor s, 0/left, 10/right -1778 editor-render screen, e -1779 $clear-trace -1780 # start on first line, press 'end' -1781 assume-console [ -1782 ¦ left-click 1, 1 -1783 ¦ press end -1784 ] -1785 run [ -1786 ¦ editor-event-loop screen, console, e -1787 ¦ 3:num/raw <- get *e, cursor-row:offset -1788 ¦ 4:num/raw <- get *e, cursor-column:offset -1789 ] -1790 # cursor moves to end of line -1791 memory-should-contain [ -1792 ¦ 3 <- 1 -1793 ¦ 4 <- 3 -1794 ] -1795 check-trace-count-for-label 0, [print-character] -1796 ] -1797 -1798 scenario editor-moves-to-end-of-line-with-end-2 [ -1799 local-scope -1800 assume-screen 10/width, 5/height -1801 s:text <- new [123 -1802 456] -1803 e:&:editor <- new-editor s, 0/left, 10/right -1804 editor-render screen, e -1805 $clear-trace -1806 # start on second line (no newline after), press 'end' -1807 assume-console [ -1808 ¦ left-click 2, 1 -1809 ¦ press end -1810 ] -1811 run [ -1812 ¦ editor-event-loop screen, console, e -1813 ¦ 3:num/raw <- get *e, cursor-row:offset -1814 ¦ 4:num/raw <- get *e, cursor-column:offset -1815 ] -1816 # cursor moves to end of line -1817 memory-should-contain [ -1818 ¦ 3 <- 2 -1819 ¦ 4 <- 3 -1820 ] -1821 check-trace-count-for-label 0, [print-character] -1822 ] -1823 -1824 scenario editor-moves-to-end-of-wrapped-line [ -1825 local-scope -1826 assume-screen 10/width, 5/height -1827 s:text <- new [123456 -1828 789] -1829 e:&:editor <- new-editor s, 0/left, 5/right -1830 editor-render screen, e -1831 $clear-trace -1832 # start on first line, press 'end' -1833 assume-console [ -1834 ¦ left-click 1, 1 -1835 ¦ press end -1836 ] -1837 run [ -1838 ¦ editor-event-loop screen, console, e -1839 ¦ 10:num/raw <- get *e, cursor-row:offset -1840 ¦ 11:num/raw <- get *e, cursor-column:offset -1841 ] -1842 # cursor moves to end of line -1843 memory-should-contain [ -1844 ¦ 10 <- 1 -1845 ¦ 11 <- 3 -1846 ] -1847 # no prints -1848 check-trace-count-for-label 0, [print-character] -1849 # before-cursor is also consistent -1850 assume-console [ -1851 ¦ type [a] +1685 check-trace-count-for-label 0, [print-character] +1686 # make sure before-cursor is in sync +1687 assume-console [ +1688 ¦ type [a] +1689 ] +1690 run [ +1691 ¦ editor-event-loop screen, console, e +1692 ¦ 4:num/raw <- get *e, cursor-row:offset +1693 ¦ 5:num/raw <- get *e, cursor-column:offset +1694 ] +1695 screen-should-contain [ +1696 ¦ . . +1697 ¦ .a123↩ . +1698 ¦ .456 . +1699 ¦ .╌╌╌╌╌ . +1700 ¦ . . +1701 ] +1702 memory-should-contain [ +1703 ¦ 4 <- 1 # cursor-row +1704 ¦ 5 <- 1 # cursor-column +1705 ] +1706 ] +1707 +1708 # ctrl-e/end - move cursor to end of line +1709 +1710 scenario editor-moves-to-end-of-line-with-ctrl-e [ +1711 local-scope +1712 assume-screen 10/width, 5/height +1713 s:text <- new [123 +1714 456] +1715 e:&:editor <- new-editor s, 0/left, 10/right +1716 editor-render screen, e +1717 $clear-trace +1718 # start on first line, press ctrl-e +1719 assume-console [ +1720 ¦ left-click 1, 1 +1721 ¦ press ctrl-e +1722 ] +1723 run [ +1724 ¦ editor-event-loop screen, console, e +1725 ¦ 4:num/raw <- get *e, cursor-row:offset +1726 ¦ 5:num/raw <- get *e, cursor-column:offset +1727 ] +1728 # cursor moves to end of line +1729 memory-should-contain [ +1730 ¦ 4 <- 1 +1731 ¦ 5 <- 3 +1732 ] +1733 check-trace-count-for-label 0, [print-character] +1734 # editor inserts future characters at cursor +1735 assume-console [ +1736 ¦ type [z] +1737 ] +1738 run [ +1739 ¦ editor-event-loop screen, console, e +1740 ¦ 4:num/raw <- get *e, cursor-row:offset +1741 ¦ 5:num/raw <- get *e, cursor-column:offset +1742 ] +1743 memory-should-contain [ +1744 ¦ 4 <- 1 +1745 ¦ 5 <- 4 +1746 ] +1747 screen-should-contain [ +1748 ¦ . . +1749 ¦ .123z . +1750 ¦ .456 . +1751 ¦ .╌╌╌╌╌╌╌╌╌╌. +1752 ¦ . . +1753 ] +1754 check-trace-count-for-label 1, [print-character] +1755 ] +1756 +1757 after <handle-special-character> [ +1758 { +1759 ¦ move-to-end-of-line?:bool <- equal c, 5/ctrl-e +1760 ¦ break-unless move-to-end-of-line? +1761 ¦ <move-cursor-begin> +1762 ¦ move-to-end-of-line editor +1763 ¦ undo-coalesce-tag:num <- copy 0/never +1764 ¦ <move-cursor-end> +1765 ¦ return 0/don't-render +1766 } +1767 ] +1768 +1769 after <handle-special-key> [ +1770 { +1771 ¦ move-to-end-of-line?:bool <- equal k, 65520/end +1772 ¦ break-unless move-to-end-of-line? +1773 ¦ <move-cursor-begin> +1774 ¦ move-to-end-of-line editor +1775 ¦ undo-coalesce-tag:num <- copy 0/never +1776 ¦ <move-cursor-end> +1777 ¦ return 0/don't-render +1778 } +1779 ] +1780 +1781 def move-to-end-of-line editor:&:editor -> editor:&:editor [ +1782 local-scope +1783 load-ingredients +1784 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +1785 cursor-column:num <- get *editor, cursor-column:offset +1786 right:num <- get *editor, right:offset +1787 # while not at end of line, move +1788 { +1789 ¦ next:&:duplex-list:char <- next before-cursor +1790 ¦ break-unless next # end of text +1791 ¦ nextc:char <- get *next, value:offset +1792 ¦ at-end-of-line?:bool <- equal nextc, 10/newline +1793 ¦ break-if at-end-of-line? +1794 ¦ cursor-column <- add cursor-column, 1 +1795 ¦ at-right?:bool <- equal cursor-column, right +1796 ¦ break-if at-right? +1797 ¦ *editor <- put *editor, cursor-column:offset, cursor-column +1798 ¦ before-cursor <- copy next +1799 ¦ *editor <- put *editor, before-cursor:offset, before-cursor +1800 ¦ loop +1801 } +1802 ] +1803 +1804 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [ +1805 local-scope +1806 assume-screen 10/width, 5/height +1807 s:text <- new [123 +1808 456] +1809 e:&:editor <- new-editor s, 0/left, 10/right +1810 editor-render screen, e +1811 $clear-trace +1812 # start on second line (no newline after), press ctrl-e +1813 assume-console [ +1814 ¦ left-click 2, 1 +1815 ¦ press ctrl-e +1816 ] +1817 run [ +1818 ¦ editor-event-loop screen, console, e +1819 ¦ 4:num/raw <- get *e, cursor-row:offset +1820 ¦ 5:num/raw <- get *e, cursor-column:offset +1821 ] +1822 # cursor moves to end of line +1823 memory-should-contain [ +1824 ¦ 4 <- 2 +1825 ¦ 5 <- 3 +1826 ] +1827 check-trace-count-for-label 0, [print-character] +1828 ] +1829 +1830 scenario editor-moves-to-end-of-line-with-end [ +1831 local-scope +1832 assume-screen 10/width, 5/height +1833 s:text <- new [123 +1834 456] +1835 e:&:editor <- new-editor s, 0/left, 10/right +1836 editor-render screen, e +1837 $clear-trace +1838 # start on first line, press 'end' +1839 assume-console [ +1840 ¦ left-click 1, 1 +1841 ¦ press end +1842 ] +1843 run [ +1844 ¦ editor-event-loop screen, console, e +1845 ¦ 3:num/raw <- get *e, cursor-row:offset +1846 ¦ 4:num/raw <- get *e, cursor-column:offset +1847 ] +1848 # cursor moves to end of line +1849 memory-should-contain [ +1850 ¦ 3 <- 1 +1851 ¦ 4 <- 3 1852 ] -1853 run [ -1854 ¦ editor-event-loop screen, console, e -1855 ] -1856 screen-should-contain [ -1857 ¦ . . -1858 ¦ .123a↩ . -1859 ¦ .456 . -1860 ¦ .789 . -1861 ¦ .╌╌╌╌╌ . -1862 ] -1863 ] -1864 -1865 # ctrl-u - delete text from start of line until (but not at) cursor -1866 -1867 scenario editor-deletes-to-start-of-line-with-ctrl-u [ -1868 local-scope -1869 assume-screen 10/width, 5/height -1870 s:text <- new [123 -1871 456] -1872 e:&:editor <- new-editor s, 0/left, 10/right -1873 editor-render screen, e -1874 $clear-trace -1875 # start on second line, press ctrl-u -1876 assume-console [ -1877 ¦ left-click 2, 2 -1878 ¦ press ctrl-u -1879 ] -1880 run [ -1881 ¦ editor-event-loop screen, console, e -1882 ] -1883 # cursor deletes to start of line -1884 screen-should-contain [ -1885 ¦ . . -1886 ¦ .123 . -1887 ¦ .6 . -1888 ¦ .╌╌╌╌╌╌╌╌╌╌. -1889 ¦ . . -1890 ] -1891 check-trace-count-for-label 10, [print-character] -1892 ] -1893 -1894 after <handle-special-character> [ -1895 { -1896 ¦ delete-to-start-of-line?:bool <- equal c, 21/ctrl-u -1897 ¦ break-unless delete-to-start-of-line? -1898 ¦ <delete-to-start-of-line-begin> -1899 ¦ deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor -1900 ¦ <delete-to-start-of-line-end> -1901 ¦ go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells -1902 ¦ return -1903 } -1904 ] -1905 -1906 def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [ -1907 local-scope -1908 load-ingredients -1909 curr-column:num <- get *editor, cursor-column:offset -1910 # accumulate the current line as text and render it -1911 buf:&:buffer:char <- new-buffer 30 # accumulator for the text we need to render -1912 curr:&:duplex-list:char <- get *editor, before-cursor:offset -1913 i:num <- copy curr-column -1914 right:num <- get *editor, right:offset -1915 { -1916 ¦ # if we have a wrapped line, give up and render the whole screen -1917 ¦ wrap?:bool <- greater-or-equal i, right -1918 ¦ return-if wrap?, 1/go-render -1919 ¦ curr <- next curr -1920 ¦ break-unless curr -1921 ¦ c:char <- get *curr, value:offset -1922 ¦ b:bool <- equal c, 10 -1923 ¦ break-if b -1924 ¦ buf <- append buf, c -1925 ¦ i <- add i, 1 -1926 ¦ loop -1927 } -1928 # if the line used to be wrapped, give up and render the whole screen -1929 num-deleted-cells:num <- length deleted-cells -1930 old-row-len:num <- add i, num-deleted-cells -1931 left:num <- get *editor, left:offset -1932 end:num <- subtract right, left -1933 wrap?:bool <- greater-or-equal old-row-len, end -1934 return-if wrap?, 1/go-render -1935 curr-line:text <- buffer-to-array buf -1936 curr-row:num <- get *editor, cursor-row:offset -1937 render-code screen, curr-line, curr-column, right, curr-row -1938 return 0/dont-render -1939 ] -1940 -1941 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [ -1942 local-scope -1943 load-ingredients -1944 # compute range to delete -1945 init:&:duplex-list:char <- get *editor, data:offset -1946 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -1947 update-top-of-screen?:bool <- copy 0/false -1948 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -1949 start:&:duplex-list:char <- copy before-cursor -1950 end:&:duplex-list:char <- next before-cursor -1951 { -1952 ¦ at-start-of-text?:bool <- equal start, init -1953 ¦ break-if at-start-of-text? -1954 ¦ curr:char <- get *start, value:offset -1955 ¦ at-start-of-line?:bool <- equal curr, 10/newline -1956 ¦ break-if at-start-of-line? -1957 ¦ # if we went past top-of-screen, make a note to update it as well -1958 ¦ at-top-of-screen?:bool <- equal start, top-of-screen -1959 ¦ update-top-of-screen?:bool <- or update-top-of-screen?, at-top-of-screen? -1960 ¦ start <- prev start -1961 ¦ assert start, [delete-to-start-of-line tried to move before start of text] -1962 ¦ loop -1963 } -1964 # snip it out -1965 result:&:duplex-list:char <- next start -1966 remove-between start, end -1967 # update top-of-screen if it's just been invalidated -1968 { -1969 ¦ break-unless update-top-of-screen? -1970 ¦ put *editor, top-of-screen:offset, start -1971 } -1972 # adjust cursor -1973 before-cursor <- copy start -1974 *editor <- put *editor, before-cursor:offset, before-cursor -1975 left:num <- get *editor, left:offset -1976 *editor <- put *editor, cursor-column:offset, left -1977 # if the line wrapped before, we may need to adjust cursor-row as well -1978 right:num <- get *editor, right:offset -1979 width:num <- subtract right, left -1980 num-deleted:num <- length result -1981 cursor-row-adjustment:num <- divide-with-remainder num-deleted, width -1982 return-unless cursor-row-adjustment -1983 cursor-row:num <- get *editor, cursor-row:offset -1984 cursor-row-in-editor:num <- subtract cursor-row, 1 # ignore menubar -1985 at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment -1986 { -1987 ¦ break-unless at-top? -1988 ¦ cursor-row <- copy 1 # top of editor, below menubar -1989 } -1990 { -1991 ¦ break-if at-top? -1992 ¦ cursor-row <- subtract cursor-row, cursor-row-adjustment -1993 } -1994 put *editor, cursor-row:offset, cursor-row -1995 ] -1996 -1997 def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num, screen:&:screen [ -1998 local-scope -1999 load-ingredients -2000 return-unless s -2001 color:num <- copy 7/white -2002 column:num <- copy left -2003 screen <- move-cursor screen, row, column -2004 screen-height:num <- screen-height screen -2005 i:num <- copy 0 -2006 len:num <- length *s -2007 { -2008 ¦ +next-character -2009 ¦ done?:bool <- greater-or-equal i, len -2010 ¦ break-if done? -2011 ¦ done? <- greater-or-equal row, screen-height -2012 ¦ break-if done? -2013 ¦ c:char <- index *s, i -2014 ¦ <character-c-received> -2015 ¦ { -2016 ¦ ¦ # newline? move to left rather than 0 -2017 ¦ ¦ newline?:bool <- equal c, 10/newline -2018 ¦ ¦ break-unless newline? -2019 ¦ ¦ # clear rest of line in this window -2020 ¦ ¦ { -2021 ¦ ¦ ¦ done?:bool <- greater-than column, right -2022 ¦ ¦ ¦ break-if done? -2023 ¦ ¦ ¦ space:char <- copy 32/space -2024 ¦ ¦ ¦ print screen, space -2025 ¦ ¦ ¦ column <- add column, 1 -2026 ¦ ¦ ¦ loop -2027 ¦ ¦ } -2028 ¦ ¦ row <- add row, 1 -2029 ¦ ¦ column <- copy left -2030 ¦ ¦ screen <- move-cursor screen, row, column -2031 ¦ ¦ i <- add i, 1 -2032 ¦ ¦ loop +next-character -2033 ¦ } -2034 ¦ { -2035 ¦ ¦ # at right? wrap. -2036 ¦ ¦ at-right?:bool <- equal column, right -2037 ¦ ¦ break-unless at-right? -2038 ¦ ¦ # print wrap icon -2039 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left -2040 ¦ ¦ print screen, wrap-icon, 245/grey -2041 ¦ ¦ column <- copy left -2042 ¦ ¦ row <- add row, 1 -2043 ¦ ¦ screen <- move-cursor screen, row, column -2044 ¦ ¦ # don't increment i -2045 ¦ ¦ loop +next-character -2046 ¦ } -2047 ¦ i <- add i, 1 -2048 ¦ print screen, c, color -2049 ¦ column <- add column, 1 -2050 ¦ loop +1853 check-trace-count-for-label 0, [print-character] +1854 ] +1855 +1856 scenario editor-moves-to-end-of-line-with-end-2 [ +1857 local-scope +1858 assume-screen 10/width, 5/height +1859 s:text <- new [123 +1860 456] +1861 e:&:editor <- new-editor s, 0/left, 10/right +1862 editor-render screen, e +1863 $clear-trace +1864 # start on second line (no newline after), press 'end' +1865 assume-console [ +1866 ¦ left-click 2, 1 +1867 ¦ press end +1868 ] +1869 run [ +1870 ¦ editor-event-loop screen, console, e +1871 ¦ 3:num/raw <- get *e, cursor-row:offset +1872 ¦ 4:num/raw <- get *e, cursor-column:offset +1873 ] +1874 # cursor moves to end of line +1875 memory-should-contain [ +1876 ¦ 3 <- 2 +1877 ¦ 4 <- 3 +1878 ] +1879 check-trace-count-for-label 0, [print-character] +1880 ] +1881 +1882 scenario editor-moves-to-end-of-wrapped-line [ +1883 local-scope +1884 assume-screen 10/width, 5/height +1885 s:text <- new [123456 +1886 789] +1887 e:&:editor <- new-editor s, 0/left, 5/right +1888 editor-render screen, e +1889 $clear-trace +1890 # start on first line, press 'end' +1891 assume-console [ +1892 ¦ left-click 1, 1 +1893 ¦ press end +1894 ] +1895 run [ +1896 ¦ editor-event-loop screen, console, e +1897 ¦ 10:num/raw <- get *e, cursor-row:offset +1898 ¦ 11:num/raw <- get *e, cursor-column:offset +1899 ] +1900 # cursor moves to end of line +1901 memory-should-contain [ +1902 ¦ 10 <- 1 +1903 ¦ 11 <- 3 +1904 ] +1905 # no prints +1906 check-trace-count-for-label 0, [print-character] +1907 # before-cursor is also consistent +1908 assume-console [ +1909 ¦ type [a] +1910 ] +1911 run [ +1912 ¦ editor-event-loop screen, console, e +1913 ] +1914 screen-should-contain [ +1915 ¦ . . +1916 ¦ .123a↩ . +1917 ¦ .456 . +1918 ¦ .789 . +1919 ¦ .╌╌╌╌╌ . +1920 ] +1921 ] +1922 +1923 # ctrl-u - delete text from start of line until (but not at) cursor +1924 +1925 scenario editor-deletes-to-start-of-line-with-ctrl-u [ +1926 local-scope +1927 assume-screen 10/width, 5/height +1928 s:text <- new [123 +1929 456] +1930 e:&:editor <- new-editor s, 0/left, 10/right +1931 editor-render screen, e +1932 $clear-trace +1933 # start on second line, press ctrl-u +1934 assume-console [ +1935 ¦ left-click 2, 2 +1936 ¦ press ctrl-u +1937 ] +1938 run [ +1939 ¦ editor-event-loop screen, console, e +1940 ] +1941 # cursor deletes to start of line +1942 screen-should-contain [ +1943 ¦ . . +1944 ¦ .123 . +1945 ¦ .6 . +1946 ¦ .╌╌╌╌╌╌╌╌╌╌. +1947 ¦ . . +1948 ] +1949 check-trace-count-for-label 10, [print-character] +1950 ] +1951 +1952 after <handle-special-character> [ +1953 { +1954 ¦ delete-to-start-of-line?:bool <- equal c, 21/ctrl-u +1955 ¦ break-unless delete-to-start-of-line? +1956 ¦ <delete-to-start-of-line-begin> +1957 ¦ deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor +1958 ¦ <delete-to-start-of-line-end> +1959 ¦ go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells +1960 ¦ return +1961 } +1962 ] +1963 +1964 def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [ +1965 local-scope +1966 load-ingredients +1967 curr-column:num <- get *editor, cursor-column:offset +1968 # accumulate the current line as text and render it +1969 buf:&:buffer:char <- new-buffer 30 # accumulator for the text we need to render +1970 curr:&:duplex-list:char <- get *editor, before-cursor:offset +1971 i:num <- copy curr-column +1972 right:num <- get *editor, right:offset +1973 { +1974 ¦ # if we have a wrapped line, give up and render the whole screen +1975 ¦ wrap?:bool <- greater-or-equal i, right +1976 ¦ return-if wrap?, 1/go-render +1977 ¦ curr <- next curr +1978 ¦ break-unless curr +1979 ¦ c:char <- get *curr, value:offset +1980 ¦ b:bool <- equal c, 10 +1981 ¦ break-if b +1982 ¦ buf <- append buf, c +1983 ¦ i <- add i, 1 +1984 ¦ loop +1985 } +1986 # if the line used to be wrapped, give up and render the whole screen +1987 num-deleted-cells:num <- length deleted-cells +1988 old-row-len:num <- add i, num-deleted-cells +1989 left:num <- get *editor, left:offset +1990 end:num <- subtract right, left +1991 wrap?:bool <- greater-or-equal old-row-len, end +1992 return-if wrap?, 1/go-render +1993 curr-line:text <- buffer-to-array buf +1994 curr-row:num <- get *editor, cursor-row:offset +1995 render-code screen, curr-line, curr-column, right, curr-row +1996 return 0/dont-render +1997 ] +1998 +1999 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [ +2000 local-scope +2001 load-ingredients +2002 # compute range to delete +2003 init:&:duplex-list:char <- get *editor, data:offset +2004 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +2005 update-top-of-screen?:bool <- copy 0/false +2006 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +2007 start:&:duplex-list:char <- copy before-cursor +2008 end:&:duplex-list:char <- next before-cursor +2009 { +2010 ¦ at-start-of-text?:bool <- equal start, init +2011 ¦ break-if at-start-of-text? +2012 ¦ curr:char <- get *start, value:offset +2013 ¦ at-start-of-line?:bool <- equal curr, 10/newline +2014 ¦ break-if at-start-of-line? +2015 ¦ # if we went past top-of-screen, make a note to update it as well +2016 ¦ at-top-of-screen?:bool <- equal start, top-of-screen +2017 ¦ update-top-of-screen?:bool <- or update-top-of-screen?, at-top-of-screen? +2018 ¦ start <- prev start +2019 ¦ assert start, [delete-to-start-of-line tried to move before start of text] +2020 ¦ loop +2021 } +2022 # snip it out +2023 result:&:duplex-list:char <- next start +2024 remove-between start, end +2025 # update top-of-screen if it's just been invalidated +2026 { +2027 ¦ break-unless update-top-of-screen? +2028 ¦ put *editor, top-of-screen:offset, start +2029 } +2030 # adjust cursor +2031 before-cursor <- copy start +2032 *editor <- put *editor, before-cursor:offset, before-cursor +2033 left:num <- get *editor, left:offset +2034 *editor <- put *editor, cursor-column:offset, left +2035 # if the line wrapped before, we may need to adjust cursor-row as well +2036 right:num <- get *editor, right:offset +2037 width:num <- subtract right, left +2038 num-deleted:num <- length result +2039 cursor-row-adjustment:num <- divide-with-remainder num-deleted, width +2040 return-unless cursor-row-adjustment +2041 cursor-row:num <- get *editor, cursor-row:offset +2042 cursor-row-in-editor:num <- subtract cursor-row, 1 # ignore menubar +2043 at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment +2044 { +2045 ¦ break-unless at-top? +2046 ¦ cursor-row <- copy 1 # top of editor, below menubar +2047 } +2048 { +2049 ¦ break-if at-top? +2050 ¦ cursor-row <- subtract cursor-row, cursor-row-adjustment 2051 } -2052 was-at-left?:bool <- equal column, left -2053 clear-line-until screen, right -2054 { -2055 ¦ break-if was-at-left? -2056 ¦ row <- add row, 1 -2057 } -2058 move-cursor screen, row, left -2059 ] -2060 -2061 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ -2062 local-scope -2063 assume-screen 10/width, 5/height -2064 s:text <- new [123 -2065 456] -2066 e:&:editor <- new-editor s, 0/left, 10/right -2067 editor-render screen, e -2068 $clear-trace -2069 # start on first line (no newline before), press ctrl-u -2070 assume-console [ -2071 ¦ left-click 1, 2 -2072 ¦ press ctrl-u -2073 ] -2074 run [ -2075 ¦ editor-event-loop screen, console, e -2076 ] -2077 # cursor deletes to start of line -2078 screen-should-contain [ -2079 ¦ . . -2080 ¦ .3 . -2081 ¦ .456 . -2082 ¦ .╌╌╌╌╌╌╌╌╌╌. -2083 ¦ . . -2084 ] -2085 check-trace-count-for-label 10, [print-character] -2086 ] -2087 -2088 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [ -2089 local-scope -2090 assume-screen 10/width, 5/height -2091 s:text <- new [123 -2092 456] -2093 e:&:editor <- new-editor s, 0/left, 10/right -2094 editor-render screen, e -2095 $clear-trace -2096 # start past end of line, press ctrl-u -2097 assume-console [ -2098 ¦ left-click 1, 3 -2099 ¦ press ctrl-u -2100 ] -2101 run [ -2102 ¦ editor-event-loop screen, console, e -2103 ] -2104 # cursor deletes to start of line -2105 screen-should-contain [ -2106 ¦ . . -2107 ¦ . . -2108 ¦ .456 . -2109 ¦ .╌╌╌╌╌╌╌╌╌╌. -2110 ¦ . . -2111 ] -2112 check-trace-count-for-label 10, [print-character] -2113 ] -2114 -2115 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [ -2116 local-scope -2117 assume-screen 10/width, 5/height -2118 s:text <- new [123 -2119 456] -2120 e:&:editor <- new-editor s, 0/left, 10/right -2121 editor-render screen, e -2122 $clear-trace -2123 # start past end of final line, press ctrl-u -2124 assume-console [ -2125 ¦ left-click 2, 3 -2126 ¦ press ctrl-u -2127 ] -2128 run [ -2129 ¦ editor-event-loop screen, console, e -2130 ] -2131 # cursor deletes to start of line -2132 screen-should-contain [ -2133 ¦ . . -2134 ¦ .123 . -2135 ¦ . . -2136 ¦ .╌╌╌╌╌╌╌╌╌╌. +2052 put *editor, cursor-row:offset, cursor-row +2053 ] +2054 +2055 def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num, screen:&:screen [ +2056 local-scope +2057 load-ingredients +2058 return-unless s +2059 color:num <- copy 7/white +2060 column:num <- copy left +2061 screen <- move-cursor screen, row, column +2062 screen-height:num <- screen-height screen +2063 i:num <- copy 0 +2064 len:num <- length *s +2065 { +2066 ¦ +next-character +2067 ¦ done?:bool <- greater-or-equal i, len +2068 ¦ break-if done? +2069 ¦ done? <- greater-or-equal row, screen-height +2070 ¦ break-if done? +2071 ¦ c:char <- index *s, i +2072 ¦ <character-c-received> +2073 ¦ { +2074 ¦ ¦ # newline? move to left rather than 0 +2075 ¦ ¦ newline?:bool <- equal c, 10/newline +2076 ¦ ¦ break-unless newline? +2077 ¦ ¦ # clear rest of line in this window +2078 ¦ ¦ { +2079 ¦ ¦ ¦ done?:bool <- greater-than column, right +2080 ¦ ¦ ¦ break-if done? +2081 ¦ ¦ ¦ space:char <- copy 32/space +2082 ¦ ¦ ¦ print screen, space +2083 ¦ ¦ ¦ column <- add column, 1 +2084 ¦ ¦ ¦ loop +2085 ¦ ¦ } +2086 ¦ ¦ row <- add row, 1 +2087 ¦ ¦ column <- copy left +2088 ¦ ¦ screen <- move-cursor screen, row, column +2089 ¦ ¦ i <- add i, 1 +2090 ¦ ¦ loop +next-character +2091 ¦ } +2092 ¦ { +2093 ¦ ¦ # at right? wrap. +2094 ¦ ¦ at-right?:bool <- equal column, right +2095 ¦ ¦ break-unless at-right? +2096 ¦ ¦ # print wrap icon +2097 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left +2098 ¦ ¦ print screen, wrap-icon, 245/grey +2099 ¦ ¦ column <- copy left +2100 ¦ ¦ row <- add row, 1 +2101 ¦ ¦ screen <- move-cursor screen, row, column +2102 ¦ ¦ # don't increment i +2103 ¦ ¦ loop +next-character +2104 ¦ } +2105 ¦ i <- add i, 1 +2106 ¦ print screen, c, color +2107 ¦ column <- add column, 1 +2108 ¦ loop +2109 } +2110 was-at-left?:bool <- equal column, left +2111 clear-line-until screen, right +2112 { +2113 ¦ break-if was-at-left? +2114 ¦ row <- add row, 1 +2115 } +2116 move-cursor screen, row, left +2117 ] +2118 +2119 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ +2120 local-scope +2121 assume-screen 10/width, 5/height +2122 s:text <- new [123 +2123 456] +2124 e:&:editor <- new-editor s, 0/left, 10/right +2125 editor-render screen, e +2126 $clear-trace +2127 # start on first line (no newline before), press ctrl-u +2128 assume-console [ +2129 ¦ left-click 1, 2 +2130 ¦ press ctrl-u +2131 ] +2132 run [ +2133 ¦ editor-event-loop screen, console, e +2134 ] +2135 # cursor deletes to start of line +2136 screen-should-contain [ 2137 ¦ . . -2138 ] -2139 check-trace-count-for-label 10, [print-character] -2140 ] -2141 -2142 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u [ -2143 local-scope -2144 assume-screen 10/width, 10/height -2145 # first line starts out wrapping -2146 s:text <- new [123456 -2147 789] -2148 e:&:editor <- new-editor s, 0/left, 5/right -2149 editor-render screen, e -2150 screen-should-contain [ -2151 ¦ . . -2152 ¦ .1234↩ . -2153 ¦ .56 . -2154 ¦ .789 . -2155 ¦ .╌╌╌╌╌ . -2156 ¦ . . -2157 ] -2158 $clear-trace -2159 # ctrl-u enough of the first line that it's no longer wrapping -2160 assume-console [ -2161 ¦ left-click 1, 3 -2162 ¦ press ctrl-u -2163 ] -2164 run [ -2165 ¦ editor-event-loop screen, console, e -2166 ] -2167 # entire screen needs to be refreshed -2168 screen-should-contain [ -2169 ¦ . . -2170 ¦ .456 . -2171 ¦ .789 . -2172 ¦ .╌╌╌╌╌ . -2173 ¦ . . -2174 ] -2175 check-trace-count-for-label 45, [print-character] -2176 ] -2177 -2178 # sometimes hitting ctrl-u needs to adjust the cursor row -2179 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-2 [ -2180 local-scope -2181 assume-screen 10/width, 10/height -2182 # third line starts out wrapping -2183 s:text <- new [1 -2184 2 -2185 345678 -2186 9] -2187 e:&:editor <- new-editor s, 0/left, 5/right -2188 editor-render screen, e -2189 screen-should-contain [ -2190 ¦ . . -2191 ¦ .1 . -2192 ¦ .2 . -2193 ¦ .3456↩ . -2194 ¦ .78 . -2195 ¦ .9 . -2196 ¦ .╌╌╌╌╌ . -2197 ¦ . . -2198 ] -2199 # position cursor on screen line after the wrap and hit ctrl-u -2200 assume-console [ -2201 ¦ left-click 4, 1 # on '8' -2202 ¦ press ctrl-u -2203 ] -2204 run [ -2205 ¦ editor-event-loop screen, console, e -2206 ¦ 10:num/raw <- get *e, cursor-row:offset -2207 ¦ 11:num/raw <- get *e, cursor-column:offset -2208 ] -2209 screen-should-contain [ -2210 ¦ . . -2211 ¦ .1 . -2212 ¦ .2 . -2213 ¦ .8 . -2214 ¦ .9 . -2215 ¦ .╌╌╌╌╌ . -2216 ¦ . . -2217 ] -2218 # cursor moves up one screen line -2219 memory-should-contain [ -2220 ¦ 10 <- 3 # cursor-row -2221 ¦ 11 <- 0 # cursor-column -2222 ] -2223 ] -2224 -2225 # line wrapping twice (taking up 3 screen lines) -2226 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-3 [ -2227 local-scope -2228 assume-screen 10/width, 10/height -2229 # third line starts out wrapping -2230 s:text <- new [1 -2231 2 -2232 3456789abcd -2233 e] -2234 e:&:editor <- new-editor s, 0/left, 5/right -2235 editor-render screen, e -2236 assume-console [ -2237 ¦ left-click 4, 1 # on '8' -2238 ] -2239 editor-event-loop screen, console, e -2240 screen-should-contain [ -2241 ¦ . . -2242 ¦ .1 . -2243 ¦ .2 . -2244 ¦ .3456↩ . -2245 ¦ .789a↩ . -2246 ¦ .bcd . -2247 ¦ .e . -2248 ¦ .╌╌╌╌╌ . -2249 ¦ . . -2250 ] -2251 assume-console [ -2252 ¦ left-click 5, 1 -2253 ¦ press ctrl-u -2254 ] -2255 run [ -2256 ¦ editor-event-loop screen, console, e -2257 ¦ 10:num/raw <- get *e, cursor-row:offset -2258 ¦ 11:num/raw <- get *e, cursor-column:offset -2259 ] -2260 screen-should-contain [ -2261 ¦ . . -2262 ¦ .1 . -2263 ¦ .2 . -2264 ¦ .cd . -2265 ¦ .e . -2266 ¦ .╌╌╌╌╌ . -2267 ¦ . . -2268 ] -2269 # make sure we adjusted cursor-row -2270 memory-should-contain [ -2271 ¦ 10 <- 3 # cursor-row -2272 ¦ 11 <- 0 # cursor-column -2273 ] -2274 ] -2275 -2276 # adjusting cursor row at the top of the screen -2277 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-4 [ -2278 local-scope -2279 assume-screen 10/width, 10/height -2280 # first line starts out wrapping -2281 s:text <- new [1234567 -2282 89] -2283 e:&:editor <- new-editor s, 0/left, 5/right -2284 editor-render screen, e -2285 screen-should-contain [ -2286 ¦ . . -2287 ¦ .1234↩ . -2288 ¦ .567 . -2289 ¦ .89 . -2290 ¦ .╌╌╌╌╌ . -2291 ¦ . . -2292 ] -2293 # position cursor on second screen line (after the wrap) and hit ctrl-u +2138 ¦ .3 . +2139 ¦ .456 . +2140 ¦ .╌╌╌╌╌╌╌╌╌╌. +2141 ¦ . . +2142 ] +2143 check-trace-count-for-label 10, [print-character] +2144 ] +2145 +2146 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [ +2147 local-scope +2148 assume-screen 10/width, 5/height +2149 s:text <- new [123 +2150 456] +2151 e:&:editor <- new-editor s, 0/left, 10/right +2152 editor-render screen, e +2153 $clear-trace +2154 # start past end of line, press ctrl-u +2155 assume-console [ +2156 ¦ left-click 1, 3 +2157 ¦ press ctrl-u +2158 ] +2159 run [ +2160 ¦ editor-event-loop screen, console, e +2161 ] +2162 # cursor deletes to start of line +2163 screen-should-contain [ +2164 ¦ . . +2165 ¦ . . +2166 ¦ .456 . +2167 ¦ .╌╌╌╌╌╌╌╌╌╌. +2168 ¦ . . +2169 ] +2170 check-trace-count-for-label 10, [print-character] +2171 ] +2172 +2173 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [ +2174 local-scope +2175 assume-screen 10/width, 5/height +2176 s:text <- new [123 +2177 456] +2178 e:&:editor <- new-editor s, 0/left, 10/right +2179 editor-render screen, e +2180 $clear-trace +2181 # start past end of final line, press ctrl-u +2182 assume-console [ +2183 ¦ left-click 2, 3 +2184 ¦ press ctrl-u +2185 ] +2186 run [ +2187 ¦ editor-event-loop screen, console, e +2188 ] +2189 # cursor deletes to start of line +2190 screen-should-contain [ +2191 ¦ . . +2192 ¦ .123 . +2193 ¦ . . +2194 ¦ .╌╌╌╌╌╌╌╌╌╌. +2195 ¦ . . +2196 ] +2197 check-trace-count-for-label 10, [print-character] +2198 ] +2199 +2200 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u [ +2201 local-scope +2202 assume-screen 10/width, 10/height +2203 # first line starts out wrapping +2204 s:text <- new [123456 +2205 789] +2206 e:&:editor <- new-editor s, 0/left, 5/right +2207 editor-render screen, e +2208 screen-should-contain [ +2209 ¦ . . +2210 ¦ .1234↩ . +2211 ¦ .56 . +2212 ¦ .789 . +2213 ¦ .╌╌╌╌╌ . +2214 ¦ . . +2215 ] +2216 $clear-trace +2217 # ctrl-u enough of the first line that it's no longer wrapping +2218 assume-console [ +2219 ¦ left-click 1, 3 +2220 ¦ press ctrl-u +2221 ] +2222 run [ +2223 ¦ editor-event-loop screen, console, e +2224 ] +2225 # entire screen needs to be refreshed +2226 screen-should-contain [ +2227 ¦ . . +2228 ¦ .456 . +2229 ¦ .789 . +2230 ¦ .╌╌╌╌╌ . +2231 ¦ . . +2232 ] +2233 check-trace-count-for-label 45, [print-character] +2234 ] +2235 +2236 # sometimes hitting ctrl-u needs to adjust the cursor row +2237 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-2 [ +2238 local-scope +2239 assume-screen 10/width, 10/height +2240 # third line starts out wrapping +2241 s:text <- new [1 +2242 2 +2243 345678 +2244 9] +2245 e:&:editor <- new-editor s, 0/left, 5/right +2246 editor-render screen, e +2247 screen-should-contain [ +2248 ¦ . . +2249 ¦ .1 . +2250 ¦ .2 . +2251 ¦ .3456↩ . +2252 ¦ .78 . +2253 ¦ .9 . +2254 ¦ .╌╌╌╌╌ . +2255 ¦ . . +2256 ] +2257 # position cursor on screen line after the wrap and hit ctrl-u +2258 assume-console [ +2259 ¦ left-click 4, 1 # on '8' +2260 ¦ press ctrl-u +2261 ] +2262 run [ +2263 ¦ editor-event-loop screen, console, e +2264 ¦ 10:num/raw <- get *e, cursor-row:offset +2265 ¦ 11:num/raw <- get *e, cursor-column:offset +2266 ] +2267 screen-should-contain [ +2268 ¦ . . +2269 ¦ .1 . +2270 ¦ .2 . +2271 ¦ .8 . +2272 ¦ .9 . +2273 ¦ .╌╌╌╌╌ . +2274 ¦ . . +2275 ] +2276 # cursor moves up one screen line +2277 memory-should-contain [ +2278 ¦ 10 <- 3 # cursor-row +2279 ¦ 11 <- 0 # cursor-column +2280 ] +2281 ] +2282 +2283 # line wrapping twice (taking up 3 screen lines) +2284 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-3 [ +2285 local-scope +2286 assume-screen 10/width, 10/height +2287 # third line starts out wrapping +2288 s:text <- new [1 +2289 2 +2290 3456789abcd +2291 e] +2292 e:&:editor <- new-editor s, 0/left, 5/right +2293 editor-render screen, e 2294 assume-console [ -2295 ¦ left-click 2, 1 -2296 ¦ press ctrl-u -2297 ] -2298 run [ -2299 ¦ editor-event-loop screen, console, e -2300 ¦ 10:num/raw <- get *e, cursor-row:offset -2301 ¦ 11:num/raw <- get *e, cursor-column:offset -2302 ] -2303 screen-should-contain [ -2304 ¦ . . -2305 ¦ .67 . -2306 ¦ .89 . -2307 ¦ .╌╌╌╌╌ . -2308 ¦ . . -2309 ] -2310 # cursor moves up to screen line 1 -2311 memory-should-contain [ -2312 ¦ 10 <- 1 # cursor-row -2313 ¦ 11 <- 0 # cursor-column -2314 ] -2315 ] -2316 -2317 # screen begins part-way through a wrapping line -2318 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-5 [ -2319 local-scope -2320 assume-screen 10/width, 10/height -2321 # third line starts out wrapping -2322 s:text <- new [1 -2323 2 -2324 345678 -2325 9] -2326 e:&:editor <- new-editor s, 0/left, 5/right -2327 editor-render screen, e -2328 # position the '78' line at the top of the screen -2329 assume-console [ -2330 ¦ left-click 4, 1 # on '8' -2331 ¦ press ctrl-t -2332 ] -2333 editor-event-loop screen, console, e -2334 screen-should-contain [ -2335 ¦ . . -2336 ¦ .78 . -2337 ¦ .9 . -2338 ¦ .╌╌╌╌╌ . -2339 ¦ . . -2340 ] -2341 assume-console [ -2342 ¦ left-click 1, 1 -2343 ¦ press ctrl-u -2344 ] -2345 run [ -2346 ¦ editor-event-loop screen, console, e -2347 ¦ 10:num/raw <- get *e, cursor-row:offset -2348 ¦ 11:num/raw <- get *e, cursor-column:offset -2349 ] -2350 # make sure we updated top-of-screen correctly -2351 screen-should-contain [ -2352 ¦ . . -2353 ¦ .8 . -2354 ¦ .9 . -2355 ¦ .╌╌╌╌╌ . -2356 ¦ . . -2357 ] -2358 memory-should-contain [ -2359 ¦ 10 <- 1 # cursor-row -2360 ¦ 11 <- 0 # cursor-column -2361 ] -2362 # the entire line is deleted, even the part not shown on screen -2363 assume-console [ -2364 ¦ press up-arrow -2365 ] -2366 run [ -2367 ¦ editor-event-loop screen, console, e -2368 ] -2369 screen-should-contain [ -2370 ¦ . . -2371 ¦ .2 . -2372 ¦ .8 . -2373 ¦ .9 . -2374 ¦ .╌╌╌╌╌ . -2375 ¦ . . -2376 ] -2377 ] -2378 -2379 # screen begins part-way through a line wrapping twice (taking up 3 screen lines) -2380 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-6 [ -2381 local-scope -2382 assume-screen 10/width, 10/height -2383 # third line starts out wrapping -2384 s:text <- new [1 -2385 2 -2386 3456789abcd -2387 e] -2388 e:&:editor <- new-editor s, 0/left, 5/right -2389 editor-render screen, e -2390 # position the 'bcd' line at the top of the screen -2391 assume-console [ -2392 ¦ left-click 4, 1 # on '8' -2393 ¦ press ctrl-t -2394 ¦ press ctrl-s # now on 'c' -2395 ] -2396 editor-event-loop screen, console, e -2397 screen-should-contain [ -2398 ¦ . . -2399 ¦ .bcd . -2400 ¦ .e . -2401 ¦ .╌╌╌╌╌ . -2402 ¦ . . -2403 ] -2404 assume-console [ -2405 ¦ left-click 1, 1 -2406 ¦ press ctrl-u +2295 ¦ left-click 4, 1 # on '8' +2296 ] +2297 editor-event-loop screen, console, e +2298 screen-should-contain [ +2299 ¦ . . +2300 ¦ .1 . +2301 ¦ .2 . +2302 ¦ .3456↩ . +2303 ¦ .789a↩ . +2304 ¦ .bcd . +2305 ¦ .e . +2306 ¦ .╌╌╌╌╌ . +2307 ¦ . . +2308 ] +2309 assume-console [ +2310 ¦ left-click 5, 1 +2311 ¦ press ctrl-u +2312 ] +2313 run [ +2314 ¦ editor-event-loop screen, console, e +2315 ¦ 10:num/raw <- get *e, cursor-row:offset +2316 ¦ 11:num/raw <- get *e, cursor-column:offset +2317 ] +2318 screen-should-contain [ +2319 ¦ . . +2320 ¦ .1 . +2321 ¦ .2 . +2322 ¦ .cd . +2323 ¦ .e . +2324 ¦ .╌╌╌╌╌ . +2325 ¦ . . +2326 ] +2327 # make sure we adjusted cursor-row +2328 memory-should-contain [ +2329 ¦ 10 <- 3 # cursor-row +2330 ¦ 11 <- 0 # cursor-column +2331 ] +2332 ] +2333 +2334 # adjusting cursor row at the top of the screen +2335 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-4 [ +2336 local-scope +2337 assume-screen 10/width, 10/height +2338 # first line starts out wrapping +2339 s:text <- new [1234567 +2340 89] +2341 e:&:editor <- new-editor s, 0/left, 5/right +2342 editor-render screen, e +2343 screen-should-contain [ +2344 ¦ . . +2345 ¦ .1234↩ . +2346 ¦ .567 . +2347 ¦ .89 . +2348 ¦ .╌╌╌╌╌ . +2349 ¦ . . +2350 ] +2351 # position cursor on second screen line (after the wrap) and hit ctrl-u +2352 assume-console [ +2353 ¦ left-click 2, 1 +2354 ¦ press ctrl-u +2355 ] +2356 run [ +2357 ¦ editor-event-loop screen, console, e +2358 ¦ 10:num/raw <- get *e, cursor-row:offset +2359 ¦ 11:num/raw <- get *e, cursor-column:offset +2360 ] +2361 screen-should-contain [ +2362 ¦ . . +2363 ¦ .67 . +2364 ¦ .89 . +2365 ¦ .╌╌╌╌╌ . +2366 ¦ . . +2367 ] +2368 # cursor moves up to screen line 1 +2369 memory-should-contain [ +2370 ¦ 10 <- 1 # cursor-row +2371 ¦ 11 <- 0 # cursor-column +2372 ] +2373 ] +2374 +2375 # screen begins part-way through a wrapping line +2376 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-5 [ +2377 local-scope +2378 assume-screen 10/width, 10/height +2379 # third line starts out wrapping +2380 s:text <- new [1 +2381 2 +2382 345678 +2383 9] +2384 e:&:editor <- new-editor s, 0/left, 5/right +2385 editor-render screen, e +2386 # position the '78' line at the top of the screen +2387 assume-console [ +2388 ¦ left-click 4, 1 # on '8' +2389 ¦ press ctrl-t +2390 ] +2391 editor-event-loop screen, console, e +2392 screen-should-contain [ +2393 ¦ . . +2394 ¦ .78 . +2395 ¦ .9 . +2396 ¦ .╌╌╌╌╌ . +2397 ¦ . . +2398 ] +2399 assume-console [ +2400 ¦ left-click 1, 1 +2401 ¦ press ctrl-u +2402 ] +2403 run [ +2404 ¦ editor-event-loop screen, console, e +2405 ¦ 10:num/raw <- get *e, cursor-row:offset +2406 ¦ 11:num/raw <- get *e, cursor-column:offset 2407 ] -2408 run [ -2409 ¦ editor-event-loop screen, console, e -2410 ¦ 10:num/raw <- get *e, cursor-row:offset -2411 ¦ 11:num/raw <- get *e, cursor-column:offset -2412 ] -2413 # make sure we updated top-of-screen correctly -2414 screen-should-contain [ -2415 ¦ . . -2416 ¦ .cd . -2417 ¦ .e . -2418 ¦ .╌╌╌╌╌ . -2419 ¦ . . -2420 ] -2421 memory-should-contain [ -2422 ¦ 10 <- 1 # cursor-row -2423 ¦ 11 <- 0 # cursor-column -2424 ] -2425 # the entire line is deleted, even the part not shown on screen -2426 assume-console [ -2427 ¦ press up-arrow -2428 ] -2429 run [ -2430 ¦ editor-event-loop screen, console, e -2431 ] -2432 screen-should-contain [ +2408 # make sure we updated top-of-screen correctly +2409 screen-should-contain [ +2410 ¦ . . +2411 ¦ .8 . +2412 ¦ .9 . +2413 ¦ .╌╌╌╌╌ . +2414 ¦ . . +2415 ] +2416 memory-should-contain [ +2417 ¦ 10 <- 1 # cursor-row +2418 ¦ 11 <- 0 # cursor-column +2419 ] +2420 # the entire line is deleted, even the part not shown on screen +2421 assume-console [ +2422 ¦ press up-arrow +2423 ] +2424 run [ +2425 ¦ editor-event-loop screen, console, e +2426 ] +2427 screen-should-contain [ +2428 ¦ . . +2429 ¦ .2 . +2430 ¦ .8 . +2431 ¦ .9 . +2432 ¦ .╌╌╌╌╌ . 2433 ¦ . . -2434 ¦ .2 . -2435 ¦ .cd . -2436 ¦ .e . -2437 ¦ .╌╌╌╌╌ . -2438 ¦ . . -2439 ] -2440 ] -2441 -2442 # ctrl-k - delete text from cursor to end of line (but not the newline) -2443 -2444 scenario editor-deletes-to-end-of-line-with-ctrl-k [ -2445 local-scope -2446 assume-screen 10/width, 5/height -2447 s:text <- new [123 -2448 456] -2449 e:&:editor <- new-editor s, 0/left, 10/right -2450 editor-render screen, e -2451 $clear-trace -2452 # start on first line, press ctrl-k -2453 assume-console [ -2454 ¦ left-click 1, 1 -2455 ¦ press ctrl-k -2456 ] -2457 run [ -2458 ¦ editor-event-loop screen, console, e -2459 ] -2460 # cursor deletes to end of line -2461 screen-should-contain [ -2462 ¦ . . -2463 ¦ .1 . -2464 ¦ .456 . -2465 ¦ .╌╌╌╌╌╌╌╌╌╌. -2466 ¦ . . -2467 ] -2468 check-trace-count-for-label 9, [print-character] -2469 ] -2470 -2471 after <handle-special-character> [ -2472 { -2473 ¦ delete-to-end-of-line?:bool <- equal c, 11/ctrl-k -2474 ¦ break-unless delete-to-end-of-line? -2475 ¦ <delete-to-end-of-line-begin> -2476 ¦ deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor -2477 ¦ <delete-to-end-of-line-end> -2478 ¦ # checks if we can do a minimal render and if we can it will do a minimal render -2479 ¦ go-render?:bool <- minimal-render-for-ctrl-k screen, editor, deleted-cells -2480 ¦ return -2481 } -2482 ] -2483 -2484 def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [ -2485 local-scope -2486 load-ingredients -2487 # if we deleted nothing, there's nothing to render -2488 return-unless deleted-cells, 0/dont-render -2489 # if the line used to wrap before, give up and render the whole screen -2490 curr-column:num <- get *editor, cursor-column:offset -2491 num-deleted-cells:num <- length deleted-cells -2492 old-row-len:num <- add curr-column, num-deleted-cells -2493 left:num <- get *editor, left:offset -2494 right:num <- get *editor, right:offset -2495 end:num <- subtract right, left -2496 wrap?:bool <- greater-or-equal old-row-len, end -2497 return-if wrap?, 1/go-render -2498 clear-line-until screen, right -2499 return 0/dont-render -2500 ] +2434 ] +2435 ] +2436 +2437 # screen begins part-way through a line wrapping twice (taking up 3 screen lines) +2438 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-6 [ +2439 local-scope +2440 assume-screen 10/width, 10/height +2441 # third line starts out wrapping +2442 s:text <- new [1 +2443 2 +2444 3456789abcd +2445 e] +2446 e:&:editor <- new-editor s, 0/left, 5/right +2447 editor-render screen, e +2448 # position the 'bcd' line at the top of the screen +2449 assume-console [ +2450 ¦ left-click 4, 1 # on '8' +2451 ¦ press ctrl-t +2452 ¦ press ctrl-s # now on 'c' +2453 ] +2454 editor-event-loop screen, console, e +2455 screen-should-contain [ +2456 ¦ . . +2457 ¦ .bcd . +2458 ¦ .e . +2459 ¦ .╌╌╌╌╌ . +2460 ¦ . . +2461 ] +2462 assume-console [ +2463 ¦ left-click 1, 1 +2464 ¦ press ctrl-u +2465 ] +2466 run [ +2467 ¦ editor-event-loop screen, console, e +2468 ¦ 10:num/raw <- get *e, cursor-row:offset +2469 ¦ 11:num/raw <- get *e, cursor-column:offset +2470 ] +2471 # make sure we updated top-of-screen correctly +2472 screen-should-contain [ +2473 ¦ . . +2474 ¦ .cd . +2475 ¦ .e . +2476 ¦ .╌╌╌╌╌ . +2477 ¦ . . +2478 ] +2479 memory-should-contain [ +2480 ¦ 10 <- 1 # cursor-row +2481 ¦ 11 <- 0 # cursor-column +2482 ] +2483 # the entire line is deleted, even the part not shown on screen +2484 assume-console [ +2485 ¦ press up-arrow +2486 ] +2487 run [ +2488 ¦ editor-event-loop screen, console, e +2489 ] +2490 screen-should-contain [ +2491 ¦ . . +2492 ¦ .2 . +2493 ¦ .cd . +2494 ¦ .e . +2495 ¦ .╌╌╌╌╌ . +2496 ¦ . . +2497 ] +2498 ] +2499 +2500 # ctrl-k - delete text from cursor to end of line (but not the newline) 2501 -2502 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [ +2502 scenario editor-deletes-to-end-of-line-with-ctrl-k [ 2503 local-scope -2504 load-ingredients -2505 # compute range to delete -2506 start:&:duplex-list:char <- get *editor, before-cursor:offset -2507 end:&:duplex-list:char <- next start -2508 { -2509 ¦ at-end-of-text?:bool <- equal end, 0/null -2510 ¦ break-if at-end-of-text? -2511 ¦ curr:char <- get *end, value:offset -2512 ¦ at-end-of-line?:bool <- equal curr, 10/newline -2513 ¦ break-if at-end-of-line? -2514 ¦ end <- next end -2515 ¦ loop -2516 } -2517 # snip it out -2518 result <- next start -2519 remove-between start, end -2520 ] -2521 -2522 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ -2523 local-scope -2524 assume-screen 10/width, 5/height -2525 s:text <- new [123 -2526 456] -2527 e:&:editor <- new-editor s, 0/left, 10/right -2528 editor-render screen, e -2529 $clear-trace -2530 # start on second line (no newline after), press ctrl-k -2531 assume-console [ -2532 ¦ left-click 2, 1 -2533 ¦ press ctrl-k -2534 ] -2535 run [ -2536 ¦ editor-event-loop screen, console, e -2537 ] -2538 # cursor deletes to end of line -2539 screen-should-contain [ -2540 ¦ . . -2541 ¦ .123 . -2542 ¦ .4 . -2543 ¦ .╌╌╌╌╌╌╌╌╌╌. -2544 ¦ . . -2545 ] -2546 check-trace-count-for-label 9, [print-character] -2547 ] -2548 -2549 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [ -2550 local-scope -2551 assume-screen 10/width, 5/height -2552 s:text <- new [123 -2553 456] -2554 e:&:editor <- new-editor s, 0/left, 10/right -2555 editor-render screen, e -2556 $clear-trace -2557 # start at end of line -2558 assume-console [ -2559 ¦ left-click 1, 2 -2560 ¦ press ctrl-k -2561 ] -2562 run [ -2563 ¦ editor-event-loop screen, console, e -2564 ] -2565 # cursor deletes just last character -2566 screen-should-contain [ -2567 ¦ . . -2568 ¦ .12 . -2569 ¦ .456 . -2570 ¦ .╌╌╌╌╌╌╌╌╌╌. -2571 ¦ . . -2572 ] -2573 check-trace-count-for-label 8, [print-character] -2574 ] -2575 -2576 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [ -2577 local-scope -2578 assume-screen 10/width, 5/height -2579 s:text <- new [123 -2580 456] -2581 e:&:editor <- new-editor s, 0/left, 10/right -2582 editor-render screen, e -2583 $clear-trace -2584 # start past end of line -2585 assume-console [ -2586 ¦ left-click 1, 3 -2587 ¦ press ctrl-k -2588 ] -2589 run [ -2590 ¦ editor-event-loop screen, console, e -2591 ] -2592 # cursor deletes nothing -2593 screen-should-contain [ -2594 ¦ . . -2595 ¦ .123 . -2596 ¦ .456 . -2597 ¦ .╌╌╌╌╌╌╌╌╌╌. +2504 assume-screen 10/width, 5/height +2505 s:text <- new [123 +2506 456] +2507 e:&:editor <- new-editor s, 0/left, 10/right +2508 editor-render screen, e +2509 $clear-trace +2510 # start on first line, press ctrl-k +2511 assume-console [ +2512 ¦ left-click 1, 1 +2513 ¦ press ctrl-k +2514 ] +2515 run [ +2516 ¦ editor-event-loop screen, console, e +2517 ] +2518 # cursor deletes to end of line +2519 screen-should-contain [ +2520 ¦ . . +2521 ¦ .1 . +2522 ¦ .456 . +2523 ¦ .╌╌╌╌╌╌╌╌╌╌. +2524 ¦ . . +2525 ] +2526 check-trace-count-for-label 9, [print-character] +2527 ] +2528 +2529 after <handle-special-character> [ +2530 { +2531 ¦ delete-to-end-of-line?:bool <- equal c, 11/ctrl-k +2532 ¦ break-unless delete-to-end-of-line? +2533 ¦ <delete-to-end-of-line-begin> +2534 ¦ deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor +2535 ¦ <delete-to-end-of-line-end> +2536 ¦ # checks if we can do a minimal render and if we can it will do a minimal render +2537 ¦ go-render?:bool <- minimal-render-for-ctrl-k screen, editor, deleted-cells +2538 ¦ return +2539 } +2540 ] +2541 +2542 def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [ +2543 local-scope +2544 load-ingredients +2545 # if we deleted nothing, there's nothing to render +2546 return-unless deleted-cells, 0/dont-render +2547 # if the line used to wrap before, give up and render the whole screen +2548 curr-column:num <- get *editor, cursor-column:offset +2549 num-deleted-cells:num <- length deleted-cells +2550 old-row-len:num <- add curr-column, num-deleted-cells +2551 left:num <- get *editor, left:offset +2552 right:num <- get *editor, right:offset +2553 end:num <- subtract right, left +2554 wrap?:bool <- greater-or-equal old-row-len, end +2555 return-if wrap?, 1/go-render +2556 clear-line-until screen, right +2557 return 0/dont-render +2558 ] +2559 +2560 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [ +2561 local-scope +2562 load-ingredients +2563 # compute range to delete +2564 start:&:duplex-list:char <- get *editor, before-cursor:offset +2565 end:&:duplex-list:char <- next start +2566 { +2567 ¦ at-end-of-text?:bool <- equal end, 0/null +2568 ¦ break-if at-end-of-text? +2569 ¦ curr:char <- get *end, value:offset +2570 ¦ at-end-of-line?:bool <- equal curr, 10/newline +2571 ¦ break-if at-end-of-line? +2572 ¦ end <- next end +2573 ¦ loop +2574 } +2575 # snip it out +2576 result <- next start +2577 remove-between start, end +2578 ] +2579 +2580 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ +2581 local-scope +2582 assume-screen 10/width, 5/height +2583 s:text <- new [123 +2584 456] +2585 e:&:editor <- new-editor s, 0/left, 10/right +2586 editor-render screen, e +2587 $clear-trace +2588 # start on second line (no newline after), press ctrl-k +2589 assume-console [ +2590 ¦ left-click 2, 1 +2591 ¦ press ctrl-k +2592 ] +2593 run [ +2594 ¦ editor-event-loop screen, console, e +2595 ] +2596 # cursor deletes to end of line +2597 screen-should-contain [ 2598 ¦ . . -2599 ] -2600 check-trace-count-for-label 7, [print-character] -2601 ] -2602 -2603 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [ -2604 local-scope -2605 assume-screen 10/width, 5/height -2606 s:text <- new [123 -2607 456] -2608 e:&:editor <- new-editor s, 0/left, 10/right -2609 editor-render screen, e -2610 $clear-trace -2611 # start at end of text -2612 assume-console [ -2613 ¦ left-click 2, 2 -2614 ¦ press ctrl-k -2615 ] -2616 run [ -2617 ¦ editor-event-loop screen, console, e -2618 ] -2619 # cursor deletes just the final character -2620 screen-should-contain [ -2621 ¦ . . -2622 ¦ .123 . -2623 ¦ .45 . -2624 ¦ .╌╌╌╌╌╌╌╌╌╌. +2599 ¦ .123 . +2600 ¦ .4 . +2601 ¦ .╌╌╌╌╌╌╌╌╌╌. +2602 ¦ . . +2603 ] +2604 check-trace-count-for-label 9, [print-character] +2605 ] +2606 +2607 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [ +2608 local-scope +2609 assume-screen 10/width, 5/height +2610 s:text <- new [123 +2611 456] +2612 e:&:editor <- new-editor s, 0/left, 10/right +2613 editor-render screen, e +2614 $clear-trace +2615 # start at end of line +2616 assume-console [ +2617 ¦ left-click 1, 2 +2618 ¦ press ctrl-k +2619 ] +2620 run [ +2621 ¦ editor-event-loop screen, console, e +2622 ] +2623 # cursor deletes just last character +2624 screen-should-contain [ 2625 ¦ . . -2626 ] -2627 check-trace-count-for-label 8, [print-character] -2628 ] -2629 -2630 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ -2631 local-scope -2632 assume-screen 10/width, 5/height -2633 s:text <- new [123 -2634 456] -2635 e:&:editor <- new-editor s, 0/left, 10/right -2636 editor-render screen, e -2637 $clear-trace -2638 # start past end of text -2639 assume-console [ -2640 ¦ left-click 2, 3 -2641 ¦ press ctrl-k -2642 ] -2643 run [ -2644 ¦ editor-event-loop screen, console, e -2645 ] -2646 # cursor deletes nothing -2647 screen-should-contain [ -2648 ¦ . . -2649 ¦ .123 . -2650 ¦ .456 . -2651 ¦ .╌╌╌╌╌╌╌╌╌╌. +2626 ¦ .12 . +2627 ¦ .456 . +2628 ¦ .╌╌╌╌╌╌╌╌╌╌. +2629 ¦ . . +2630 ] +2631 check-trace-count-for-label 8, [print-character] +2632 ] +2633 +2634 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [ +2635 local-scope +2636 assume-screen 10/width, 5/height +2637 s:text <- new [123 +2638 456] +2639 e:&:editor <- new-editor s, 0/left, 10/right +2640 editor-render screen, e +2641 $clear-trace +2642 # start past end of line +2643 assume-console [ +2644 ¦ left-click 1, 3 +2645 ¦ press ctrl-k +2646 ] +2647 run [ +2648 ¦ editor-event-loop screen, console, e +2649 ] +2650 # cursor deletes nothing +2651 screen-should-contain [ 2652 ¦ . . -2653 ] -2654 # no prints necessary -2655 check-trace-count-for-label 0, [print-character] -2656 ] -2657 -2658 scenario editor-deletes-to-end-of-wrapped-line-with-ctrl-k [ -2659 local-scope -2660 assume-screen 10/width, 5/height -2661 # create an editor with the first line wrapping to a second screen row -2662 s:text <- new [1234 -2663 567] -2664 e:&:editor <- new-editor s, 0/left, 4/right -2665 editor-render screen, e -2666 $clear-trace -2667 # delete all of the first wrapped line -2668 assume-console [ -2669 ¦ press ctrl-k -2670 ] -2671 run [ -2672 ¦ editor-event-loop screen, console, e +2653 ¦ .123 . +2654 ¦ .456 . +2655 ¦ .╌╌╌╌╌╌╌╌╌╌. +2656 ¦ . . +2657 ] +2658 check-trace-count-for-label 7, [print-character] +2659 ] +2660 +2661 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [ +2662 local-scope +2663 assume-screen 10/width, 5/height +2664 s:text <- new [123 +2665 456] +2666 e:&:editor <- new-editor s, 0/left, 10/right +2667 editor-render screen, e +2668 $clear-trace +2669 # start at end of text +2670 assume-console [ +2671 ¦ left-click 2, 2 +2672 ¦ press ctrl-k 2673 ] -2674 # screen shows an empty unwrapped first line -2675 screen-should-contain [ -2676 ¦ . . -2677 ¦ . . -2678 ¦ .567 . -2679 ¦ .╌╌╌╌ . -2680 ¦ . . -2681 ] -2682 # entire screen is refreshed -2683 check-trace-count-for-label 16, [print-character] -2684 ] -2685 -2686 # cursor-down can scroll if necessary +2674 run [ +2675 ¦ editor-event-loop screen, console, e +2676 ] +2677 # cursor deletes just the final character +2678 screen-should-contain [ +2679 ¦ . . +2680 ¦ .123 . +2681 ¦ .45 . +2682 ¦ .╌╌╌╌╌╌╌╌╌╌. +2683 ¦ . . +2684 ] +2685 check-trace-count-for-label 8, [print-character] +2686 ] 2687 -2688 scenario editor-can-scroll-down-using-arrow-keys [ +2688 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ 2689 local-scope -2690 # screen has 1 line for menu + 3 lines -2691 assume-screen 10/width, 4/height -2692 # initialize editor with >3 lines -2693 s:text <- new [a -2694 b -2695 c -2696 d] -2697 e:&:editor <- new-editor s, 0/left, 10/right -2698 editor-render screen, e -2699 screen-should-contain [ -2700 ¦ . . -2701 ¦ .a . -2702 ¦ .b . -2703 ¦ .c . -2704 ] -2705 # position cursor at last line, then try to move further down -2706 assume-console [ -2707 ¦ left-click 3, 0 -2708 ¦ press down-arrow -2709 ] -2710 run [ -2711 ¦ editor-event-loop screen, console, e -2712 ] -2713 # screen slides by one line -2714 screen-should-contain [ -2715 ¦ . . -2716 ¦ .b . -2717 ¦ .c . -2718 ¦ .d . -2719 ] -2720 ] -2721 -2722 after <scroll-down> [ -2723 trace 10, [app], [scroll down] -2724 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -2725 left:num <- get *editor, left:offset -2726 right:num <- get *editor, right:offset -2727 max:num <- subtract right, left -2728 old-top:&:duplex-list:char <- copy top-of-screen -2729 top-of-screen <- before-start-of-next-line top-of-screen, max -2730 *editor <- put *editor, top-of-screen:offset, top-of-screen -2731 no-movement?:bool <- equal old-top, top-of-screen -2732 return-if no-movement?, 0/don't-render -2733 ] -2734 -2735 # takes a pointer into the doubly-linked list, scans ahead at most 'max' -2736 # positions until the next newline -2737 # returns original if no next newline -2738 # beware: never return null pointer. -2739 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [ -2740 local-scope -2741 load-ingredients -2742 count:num <- copy 0 -2743 curr:&:duplex-list:char <- copy original -2744 # skip the initial newline if it exists -2745 { -2746 ¦ c:char <- get *curr, value:offset -2747 ¦ at-newline?:bool <- equal c, 10/newline -2748 ¦ break-unless at-newline? -2749 ¦ curr <- next curr -2750 ¦ count <- add count, 1 -2751 } -2752 { -2753 ¦ return-unless curr, original -2754 ¦ done?:bool <- greater-or-equal count, max -2755 ¦ break-if done? -2756 ¦ c:char <- get *curr, value:offset -2757 ¦ at-newline?:bool <- equal c, 10/newline -2758 ¦ break-if at-newline? -2759 ¦ curr <- next curr -2760 ¦ count <- add count, 1 -2761 ¦ loop -2762 } -2763 return-unless curr, original -2764 return curr -2765 ] -2766 -2767 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [ -2768 local-scope -2769 # screen has 1 line for menu + 3 lines -2770 assume-screen 10/width, 4/height -2771 # initialize editor with a long, wrapped line and more than a screen of -2772 # other lines -2773 s:text <- new [abcdef -2774 g -2775 h -2776 i] -2777 e:&:editor <- new-editor s, 0/left, 5/right -2778 editor-render screen, e -2779 screen-should-contain [ -2780 ¦ . . -2781 ¦ .abcd↩ . -2782 ¦ .ef . -2783 ¦ .g . -2784 ] -2785 # position cursor at last line, then try to move further down -2786 assume-console [ -2787 ¦ left-click 3, 0 -2788 ¦ press down-arrow -2789 ] -2790 run [ -2791 ¦ editor-event-loop screen, console, e -2792 ] -2793 # screen shows partial wrapped line -2794 screen-should-contain [ -2795 ¦ . . -2796 ¦ .ef . -2797 ¦ .g . -2798 ¦ .h . -2799 ] -2800 ] -2801 -2802 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [ -2803 local-scope -2804 # screen has 1 line for menu + 3 lines -2805 assume-screen 10/width, 4/height -2806 # editor starts with a long line wrapping twice -2807 s:text <- new [abcdefghij -2808 k -2809 l -2810 m] -2811 e:&:editor <- new-editor s, 0/left, 5/right -2812 # position cursor at last line, then try to move further down -2813 assume-console [ -2814 ¦ left-click 3, 0 -2815 ¦ press down-arrow -2816 ] -2817 run [ -2818 ¦ editor-event-loop screen, console, e -2819 ] -2820 # screen shows partial wrapped line containing a wrap icon -2821 screen-should-contain [ -2822 ¦ . . -2823 ¦ .efgh↩ . -2824 ¦ .ij . -2825 ¦ .k . -2826 ] -2827 # scroll down again -2828 assume-console [ -2829 ¦ press down-arrow -2830 ] -2831 run [ -2832 ¦ editor-event-loop screen, console, e -2833 ] -2834 # screen shows partial wrapped line -2835 screen-should-contain [ -2836 ¦ . . -2837 ¦ .ij . -2838 ¦ .k . -2839 ¦ .l . -2840 ] -2841 ] -2842 -2843 scenario editor-scrolls-down-when-line-wraps [ -2844 local-scope -2845 # screen has 1 line for menu + 3 lines -2846 assume-screen 5/width, 4/height -2847 # editor contains a long line in the third line -2848 s:text <- new [a -2849 b -2850 cdef] -2851 e:&:editor <- new-editor s, 0/left, 5/right -2852 # position cursor at end, type a character -2853 assume-console [ -2854 ¦ left-click 3, 4 -2855 ¦ type [g] -2856 ] -2857 run [ -2858 ¦ editor-event-loop screen, console, e -2859 ¦ 3:num/raw <- get *e, cursor-row:offset -2860 ¦ 4:num/raw <- get *e, cursor-column:offset -2861 ] -2862 # screen scrolls -2863 screen-should-contain [ -2864 ¦ . . -2865 ¦ .b . -2866 ¦ .cdef↩. -2867 ¦ .g . -2868 ] -2869 memory-should-contain [ -2870 ¦ 3 <- 3 -2871 ¦ 4 <- 1 -2872 ] -2873 ] -2874 -2875 scenario editor-scrolls-down-on-newline [ -2876 local-scope -2877 assume-screen 5/width, 4/height -2878 # position cursor after last line and type newline -2879 s:text <- new [a -2880 b -2881 c] -2882 e:&:editor <- new-editor s, 0/left, 5/right -2883 assume-console [ -2884 ¦ left-click 3, 4 -2885 ¦ type [ -2886 ] -2887 ] -2888 run [ -2889 ¦ editor-event-loop screen, console, e -2890 ¦ 3:num/raw <- get *e, cursor-row:offset -2891 ¦ 4:num/raw <- get *e, cursor-column:offset -2892 ] -2893 # screen scrolls -2894 screen-should-contain [ -2895 ¦ . . -2896 ¦ .b . -2897 ¦ .c . -2898 ¦ . . -2899 ] -2900 memory-should-contain [ -2901 ¦ 3 <- 3 -2902 ¦ 4 <- 0 -2903 ] -2904 ] -2905 -2906 scenario editor-scrolls-down-on-right-arrow [ -2907 local-scope -2908 # screen has 1 line for menu + 3 lines -2909 assume-screen 5/width, 4/height -2910 # editor contains a wrapped line -2911 s:text <- new [a -2912 b -2913 cdefgh] -2914 e:&:editor <- new-editor s, 0/left, 5/right -2915 # position cursor at end of screen and try to move right -2916 assume-console [ -2917 ¦ left-click 3, 3 -2918 ¦ press right-arrow +2690 assume-screen 10/width, 5/height +2691 s:text <- new [123 +2692 456] +2693 e:&:editor <- new-editor s, 0/left, 10/right +2694 editor-render screen, e +2695 $clear-trace +2696 # start past end of text +2697 assume-console [ +2698 ¦ left-click 2, 3 +2699 ¦ press ctrl-k +2700 ] +2701 run [ +2702 ¦ editor-event-loop screen, console, e +2703 ] +2704 # cursor deletes nothing +2705 screen-should-contain [ +2706 ¦ . . +2707 ¦ .123 . +2708 ¦ .456 . +2709 ¦ .╌╌╌╌╌╌╌╌╌╌. +2710 ¦ . . +2711 ] +2712 # no prints necessary +2713 check-trace-count-for-label 0, [print-character] +2714 ] +2715 +2716 scenario editor-deletes-to-end-of-wrapped-line-with-ctrl-k [ +2717 local-scope +2718 assume-screen 10/width, 5/height +2719 # create an editor with the first line wrapping to a second screen row +2720 s:text <- new [1234 +2721 567] +2722 e:&:editor <- new-editor s, 0/left, 4/right +2723 editor-render screen, e +2724 $clear-trace +2725 # delete all of the first wrapped line +2726 assume-console [ +2727 ¦ press ctrl-k +2728 ] +2729 run [ +2730 ¦ editor-event-loop screen, console, e +2731 ] +2732 # screen shows an empty unwrapped first line +2733 screen-should-contain [ +2734 ¦ . . +2735 ¦ . . +2736 ¦ .567 . +2737 ¦ .╌╌╌╌ . +2738 ¦ . . +2739 ] +2740 # entire screen is refreshed +2741 check-trace-count-for-label 16, [print-character] +2742 ] +2743 +2744 # scroll down if necessary +2745 +2746 scenario editor-can-scroll-down-using-arrow-keys [ +2747 local-scope +2748 # screen has 1 line for menu + 3 lines +2749 assume-screen 10/width, 4/height +2750 # initialize editor with >3 lines +2751 s:text <- new [a +2752 b +2753 c +2754 d] +2755 e:&:editor <- new-editor s, 0/left, 10/right +2756 editor-render screen, e +2757 screen-should-contain [ +2758 ¦ . . +2759 ¦ .a . +2760 ¦ .b . +2761 ¦ .c . +2762 ] +2763 # position cursor at last line, then try to move further down +2764 assume-console [ +2765 ¦ left-click 3, 0 +2766 ¦ press down-arrow +2767 ] +2768 run [ +2769 ¦ editor-event-loop screen, console, e +2770 ] +2771 # screen slides by one line +2772 screen-should-contain [ +2773 ¦ . . +2774 ¦ .b . +2775 ¦ .c . +2776 ¦ .d . +2777 ] +2778 ] +2779 +2780 after <scroll-down> [ +2781 trace 10, [app], [scroll down] +2782 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +2783 left:num <- get *editor, left:offset +2784 right:num <- get *editor, right:offset +2785 max:num <- subtract right, left +2786 old-top:&:duplex-list:char <- copy top-of-screen +2787 top-of-screen <- before-start-of-next-line top-of-screen, max +2788 *editor <- put *editor, top-of-screen:offset, top-of-screen +2789 no-movement?:bool <- equal old-top, top-of-screen +2790 return-if no-movement?, 0/don't-render +2791 ] +2792 +2793 # Takes a pointer into the doubly-linked list, scans ahead at most 'max' +2794 # positions until the next newline. +2795 # Returns original if no next newline. +2796 # Beware: never return null pointer. +2797 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [ +2798 local-scope +2799 load-ingredients +2800 count:num <- copy 0 +2801 curr:&:duplex-list:char <- copy original +2802 # skip the initial newline if it exists +2803 { +2804 ¦ c:char <- get *curr, value:offset +2805 ¦ at-newline?:bool <- equal c, 10/newline +2806 ¦ break-unless at-newline? +2807 ¦ curr <- next curr +2808 ¦ count <- add count, 1 +2809 } +2810 { +2811 ¦ return-unless curr, original +2812 ¦ done?:bool <- greater-or-equal count, max +2813 ¦ break-if done? +2814 ¦ c:char <- get *curr, value:offset +2815 ¦ at-newline?:bool <- equal c, 10/newline +2816 ¦ break-if at-newline? +2817 ¦ curr <- next curr +2818 ¦ count <- add count, 1 +2819 ¦ loop +2820 } +2821 return-unless curr, original +2822 return curr +2823 ] +2824 +2825 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [ +2826 local-scope +2827 # screen has 1 line for menu + 3 lines +2828 assume-screen 10/width, 4/height +2829 # initialize editor with a long, wrapped line and more than a screen of +2830 # other lines +2831 s:text <- new [abcdef +2832 g +2833 h +2834 i] +2835 e:&:editor <- new-editor s, 0/left, 5/right +2836 editor-render screen, e +2837 screen-should-contain [ +2838 ¦ . . +2839 ¦ .abcd↩ . +2840 ¦ .ef . +2841 ¦ .g . +2842 ] +2843 # position cursor at last line, then try to move further down +2844 assume-console [ +2845 ¦ left-click 3, 0 +2846 ¦ press down-arrow +2847 ] +2848 run [ +2849 ¦ editor-event-loop screen, console, e +2850 ] +2851 # screen shows partial wrapped line +2852 screen-should-contain [ +2853 ¦ . . +2854 ¦ .ef . +2855 ¦ .g . +2856 ¦ .h . +2857 ] +2858 ] +2859 +2860 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [ +2861 local-scope +2862 # screen has 1 line for menu + 3 lines +2863 assume-screen 10/width, 4/height +2864 # editor starts with a long line wrapping twice +2865 s:text <- new [abcdefghij +2866 k +2867 l +2868 m] +2869 e:&:editor <- new-editor s, 0/left, 5/right +2870 # position cursor at last line, then try to move further down +2871 assume-console [ +2872 ¦ left-click 3, 0 +2873 ¦ press down-arrow +2874 ] +2875 run [ +2876 ¦ editor-event-loop screen, console, e +2877 ] +2878 # screen shows partial wrapped line containing a wrap icon +2879 screen-should-contain [ +2880 ¦ . . +2881 ¦ .efgh↩ . +2882 ¦ .ij . +2883 ¦ .k . +2884 ] +2885 # scroll down again +2886 assume-console [ +2887 ¦ press down-arrow +2888 ] +2889 run [ +2890 ¦ editor-event-loop screen, console, e +2891 ] +2892 # screen shows partial wrapped line +2893 screen-should-contain [ +2894 ¦ . . +2895 ¦ .ij . +2896 ¦ .k . +2897 ¦ .l . +2898 ] +2899 ] +2900 +2901 scenario editor-scrolls-down-when-line-wraps [ +2902 local-scope +2903 # screen has 1 line for menu + 3 lines +2904 assume-screen 5/width, 4/height +2905 # editor contains a long line in the third line +2906 s:text <- new [a +2907 b +2908 cdef] +2909 e:&:editor <- new-editor s, 0/left, 5/right +2910 # position cursor at end, type a character +2911 assume-console [ +2912 ¦ left-click 3, 4 +2913 ¦ type [g] +2914 ] +2915 run [ +2916 ¦ editor-event-loop screen, console, e +2917 ¦ 3:num/raw <- get *e, cursor-row:offset +2918 ¦ 4:num/raw <- get *e, cursor-column:offset 2919 ] -2920 run [ -2921 ¦ editor-event-loop screen, console, e -2922 ¦ 3:num/raw <- get *e, cursor-row:offset -2923 ¦ 4:num/raw <- get *e, cursor-column:offset -2924 ] -2925 # screen scrolls -2926 screen-should-contain [ -2927 ¦ . . -2928 ¦ .b . -2929 ¦ .cdef↩. -2930 ¦ .gh . -2931 ] -2932 memory-should-contain [ -2933 ¦ 3 <- 3 -2934 ¦ 4 <- 0 -2935 ] -2936 ] -2937 -2938 scenario editor-scrolls-down-on-right-arrow-2 [ -2939 local-scope -2940 # screen has 1 line for menu + 3 lines -2941 assume-screen 5/width, 4/height -2942 # editor contains more lines than can fit on screen -2943 s:text <- new [a -2944 b -2945 c -2946 d] -2947 e:&:editor <- new-editor s, 0/left, 5/right -2948 # position cursor at end of screen and try to move right +2920 # screen scrolls +2921 screen-should-contain [ +2922 ¦ . . +2923 ¦ .b . +2924 ¦ .cdef↩. +2925 ¦ .g . +2926 ] +2927 memory-should-contain [ +2928 ¦ 3 <- 3 +2929 ¦ 4 <- 1 +2930 ] +2931 ] +2932 +2933 scenario editor-stops-scrolling-once-bottom-is-visible [ +2934 local-scope +2935 # screen has 1 line for menu + 3 lines +2936 assume-screen 10/width, 4/height +2937 # initialize editor with 2 lines +2938 s:text <- new [a +2939 b] +2940 e:&:editor <- new-editor s, 0/left, 10/right +2941 editor-render screen, e +2942 screen-should-contain [ +2943 ¦ . . +2944 ¦ .a . +2945 ¦ .b . +2946 ¦ .╌╌╌╌╌╌╌╌╌╌. +2947 ] +2948 # position cursor at last line, then try to move further down 2949 assume-console [ -2950 ¦ left-click 3, 3 -2951 ¦ press right-arrow +2950 ¦ left-click 3, 0 +2951 ¦ press down-arrow 2952 ] 2953 run [ 2954 ¦ editor-event-loop screen, console, e -2955 ¦ 3:num/raw <- get *e, cursor-row:offset -2956 ¦ 4:num/raw <- get *e, cursor-column:offset -2957 ] -2958 # screen scrolls -2959 screen-should-contain [ -2960 ¦ . . -2961 ¦ .b . -2962 ¦ .c . -2963 ¦ .d . -2964 ] -2965 memory-should-contain [ -2966 ¦ 3 <- 3 -2967 ¦ 4 <- 0 -2968 ] -2969 ] -2970 -2971 scenario editor-scrolls-at-end-on-down-arrow [ -2972 local-scope -2973 assume-screen 10/width, 5/height -2974 s:text <- new [abc -2975 de] -2976 e:&:editor <- new-editor s, 0/left, 10/right -2977 editor-render screen, e -2978 $clear-trace -2979 # try to move down past end of text -2980 assume-console [ -2981 ¦ left-click 2, 0 -2982 ¦ press down-arrow -2983 ] -2984 run [ -2985 ¦ editor-event-loop screen, console, e -2986 ¦ 3:num/raw <- get *e, cursor-row:offset -2987 ¦ 4:num/raw <- get *e, cursor-column:offset -2988 ] -2989 # screen should scroll, moving cursor to end of text +2955 ] +2956 # no change since the bottom border was already visible +2957 screen-should-contain [ +2958 ¦ . . +2959 ¦ .a . +2960 ¦ .b . +2961 ¦ .╌╌╌╌╌╌╌╌╌╌. +2962 ] +2963 ] +2964 +2965 scenario editor-scrolls-down-on-newline [ +2966 local-scope +2967 assume-screen 5/width, 4/height +2968 # position cursor after last line and type newline +2969 s:text <- new [a +2970 b +2971 c] +2972 e:&:editor <- new-editor s, 0/left, 5/right +2973 assume-console [ +2974 ¦ left-click 3, 4 +2975 ¦ type [ +2976 ] +2977 ] +2978 run [ +2979 ¦ editor-event-loop screen, console, e +2980 ¦ 3:num/raw <- get *e, cursor-row:offset +2981 ¦ 4:num/raw <- get *e, cursor-column:offset +2982 ] +2983 # screen scrolls +2984 screen-should-contain [ +2985 ¦ . . +2986 ¦ .b . +2987 ¦ .c . +2988 ¦ . . +2989 ] 2990 memory-should-contain [ -2991 ¦ 3 <- 1 -2992 ¦ 4 <- 2 +2991 ¦ 3 <- 3 +2992 ¦ 4 <- 0 2993 ] -2994 assume-console [ -2995 ¦ type [0] -2996 ] -2997 run [ -2998 ¦ editor-event-loop screen, console, e -2999 ] -3000 screen-should-contain [ -3001 ¦ . . -3002 ¦ .de0 . -3003 ¦ .╌╌╌╌╌╌╌╌╌╌. -3004 ¦ . . -3005 ] -3006 # try to move down again -3007 $clear-trace -3008 assume-console [ -3009 ¦ left-click 2, 0 -3010 ¦ press down-arrow -3011 ] -3012 run [ -3013 ¦ editor-event-loop screen, console, e -3014 ¦ 3:num/raw <- get *e, cursor-row:offset -3015 ¦ 4:num/raw <- get *e, cursor-column:offset -3016 ] -3017 # screen stops scrolling because cursor is already at top -3018 memory-should-contain [ -3019 ¦ 3 <- 1 -3020 ¦ 4 <- 3 +2994 ] +2995 +2996 scenario editor-scrolls-down-on-right-arrow [ +2997 local-scope +2998 # screen has 1 line for menu + 3 lines +2999 assume-screen 5/width, 4/height +3000 # editor contains a wrapped line +3001 s:text <- new [a +3002 b +3003 cdefgh] +3004 e:&:editor <- new-editor s, 0/left, 5/right +3005 # position cursor at end of screen and try to move right +3006 assume-console [ +3007 ¦ left-click 3, 3 +3008 ¦ press right-arrow +3009 ] +3010 run [ +3011 ¦ editor-event-loop screen, console, e +3012 ¦ 3:num/raw <- get *e, cursor-row:offset +3013 ¦ 4:num/raw <- get *e, cursor-column:offset +3014 ] +3015 # screen scrolls +3016 screen-should-contain [ +3017 ¦ . . +3018 ¦ .b . +3019 ¦ .cdef↩. +3020 ¦ .gh . 3021 ] -3022 check-trace-count-for-label 0, [print-character] -3023 assume-console [ -3024 ¦ type [1] +3022 memory-should-contain [ +3023 ¦ 3 <- 3 +3024 ¦ 4 <- 0 3025 ] -3026 run [ -3027 ¦ editor-event-loop screen, console, e -3028 ] -3029 screen-should-contain [ -3030 ¦ . . -3031 ¦ .de01 . -3032 ¦ .╌╌╌╌╌╌╌╌╌╌. -3033 ¦ . . -3034 ] -3035 ] -3036 -3037 scenario editor-combines-page-and-line-scroll [ -3038 local-scope -3039 # screen has 1 line for menu + 3 lines -3040 assume-screen 10/width, 4/height -3041 # initialize editor with a few pages of lines -3042 s:text <- new [a -3043 b -3044 c -3045 d -3046 e -3047 f -3048 g] -3049 e:&:editor <- new-editor s, 0/left, 5/right -3050 editor-render screen, e -3051 # scroll down one page and one line -3052 assume-console [ -3053 ¦ press page-down -3054 ¦ left-click 3, 0 -3055 ¦ press down-arrow -3056 ] -3057 run [ -3058 ¦ editor-event-loop screen, console, e -3059 ] -3060 # screen scrolls down 3 lines -3061 screen-should-contain [ -3062 ¦ . . -3063 ¦ .d . -3064 ¦ .e . -3065 ¦ .f . -3066 ] -3067 ] -3068 -3069 # cursor-up can scroll if necessary -3070 -3071 scenario editor-can-scroll-up-using-arrow-keys [ -3072 local-scope -3073 # screen has 1 line for menu + 3 lines -3074 assume-screen 10/width, 4/height -3075 # initialize editor with >3 lines -3076 s:text <- new [a -3077 b -3078 c -3079 d] -3080 e:&:editor <- new-editor s, 0/left, 10/right -3081 editor-render screen, e -3082 screen-should-contain [ -3083 ¦ . . -3084 ¦ .a . -3085 ¦ .b . -3086 ¦ .c . -3087 ] -3088 # position cursor at top of second page, then try to move up -3089 assume-console [ -3090 ¦ press page-down -3091 ¦ press up-arrow -3092 ] -3093 run [ -3094 ¦ editor-event-loop screen, console, e -3095 ] -3096 # screen slides by one line -3097 screen-should-contain [ -3098 ¦ . . -3099 ¦ .b . -3100 ¦ .c . -3101 ¦ .d . -3102 ] -3103 ] -3104 -3105 after <scroll-up> [ -3106 trace 10, [app], [scroll up] -3107 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3108 old-top:&:duplex-list:char <- copy top-of-screen -3109 top-of-screen <- before-previous-screen-line top-of-screen, editor -3110 *editor <- put *editor, top-of-screen:offset, top-of-screen -3111 no-movement?:bool <- equal old-top, top-of-screen -3112 return-if no-movement?, 0/don't-render -3113 ] -3114 -3115 # takes a pointer into the doubly-linked list, scans back to before start of -3116 # previous *wrapped* line -3117 # returns original if no next newline -3118 # beware: never return null pointer -3119 def before-previous-screen-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [ -3120 local-scope -3121 load-ingredients -3122 curr:&:duplex-list:char <- copy in -3123 c:char <- get *curr, value:offset -3124 # compute max, number of characters to skip -3125 # 1 + len%(width-1) -3126 # except rotate second term to vary from 1 to width-1 rather than 0 to width-2 -3127 left:num <- get *editor, left:offset -3128 right:num <- get *editor, right:offset -3129 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon -3130 sentinel:&:duplex-list:char <- get *editor, data:offset -3131 len:num <- previous-line-length curr, sentinel -3132 { -3133 ¦ break-if len -3134 ¦ # empty line; just skip this newline -3135 ¦ prev:&:duplex-list:char <- prev curr -3136 ¦ return-unless prev, curr -3137 ¦ return prev -3138 } -3139 _, max:num <- divide-with-remainder len, max-line-length -3140 # remainder 0 => scan one width-worth -3141 { -3142 ¦ break-if max -3143 ¦ max <- copy max-line-length -3144 } -3145 max <- add max, 1 -3146 count:num <- copy 0 -3147 # skip 'max' characters -3148 { -3149 ¦ done?:bool <- greater-or-equal count, max -3150 ¦ break-if done? -3151 ¦ prev:&:duplex-list:char <- prev curr -3152 ¦ break-unless prev -3153 ¦ curr <- copy prev -3154 ¦ count <- add count, 1 -3155 ¦ loop -3156 } -3157 return curr -3158 ] -3159 -3160 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [ -3161 local-scope -3162 # screen has 1 line for menu + 3 lines -3163 assume-screen 10/width, 4/height -3164 # initialize editor with a long, wrapped line and more than a screen of -3165 # other lines -3166 s:text <- new [abcdef -3167 g -3168 h -3169 i] -3170 e:&:editor <- new-editor s, 0/left, 5/right -3171 editor-render screen, e -3172 screen-should-contain [ -3173 ¦ . . -3174 ¦ .abcd↩ . -3175 ¦ .ef . -3176 ¦ .g . -3177 ] -3178 # position cursor at top of second page, just below wrapped line -3179 assume-console [ -3180 ¦ press page-down -3181 ] -3182 run [ -3183 ¦ editor-event-loop screen, console, e -3184 ] -3185 screen-should-contain [ -3186 ¦ . . -3187 ¦ .g . -3188 ¦ .h . -3189 ¦ .i . -3190 ] -3191 # now move up one line -3192 assume-console [ -3193 ¦ press up-arrow -3194 ] -3195 run [ -3196 ¦ editor-event-loop screen, console, e -3197 ] -3198 # screen shows partial wrapped line -3199 screen-should-contain [ -3200 ¦ . . -3201 ¦ .ef . -3202 ¦ .g . -3203 ¦ .h . -3204 ] -3205 ] -3206 -3207 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [ -3208 local-scope -3209 # screen has 1 line for menu + 4 lines -3210 assume-screen 10/width, 5/height -3211 # editor starts with a long line wrapping twice, occupying 3 of the 4 lines -3212 s:text <- new [abcdefghij -3213 k -3214 l -3215 m] -3216 e:&:editor <- new-editor s, 0/left, 5/right -3217 editor-render screen, e -3218 # position cursor at top of second page -3219 assume-console [ -3220 ¦ press page-down -3221 ] -3222 run [ -3223 ¦ editor-event-loop screen, console, e -3224 ] -3225 screen-should-contain [ -3226 ¦ . . -3227 ¦ .k . -3228 ¦ .l . -3229 ¦ .m . -3230 ¦ .╌╌╌╌╌ . -3231 ] -3232 # move up one line -3233 assume-console [ -3234 ¦ press up-arrow -3235 ] -3236 run [ -3237 ¦ editor-event-loop screen, console, e -3238 ] -3239 # screen shows partial wrapped line -3240 screen-should-contain [ -3241 ¦ . . -3242 ¦ .ij . -3243 ¦ .k . -3244 ¦ .l . -3245 ¦ .m . +3026 ] +3027 +3028 scenario editor-scrolls-down-on-right-arrow-2 [ +3029 local-scope +3030 # screen has 1 line for menu + 3 lines +3031 assume-screen 5/width, 4/height +3032 # editor contains more lines than can fit on screen +3033 s:text <- new [a +3034 b +3035 c +3036 d] +3037 e:&:editor <- new-editor s, 0/left, 5/right +3038 # position cursor at end of screen and try to move right +3039 assume-console [ +3040 ¦ left-click 3, 3 +3041 ¦ press right-arrow +3042 ] +3043 run [ +3044 ¦ editor-event-loop screen, console, e +3045 ¦ 3:num/raw <- get *e, cursor-row:offset +3046 ¦ 4:num/raw <- get *e, cursor-column:offset +3047 ] +3048 # screen scrolls +3049 screen-should-contain [ +3050 ¦ . . +3051 ¦ .b . +3052 ¦ .c . +3053 ¦ .d . +3054 ] +3055 memory-should-contain [ +3056 ¦ 3 <- 3 +3057 ¦ 4 <- 0 +3058 ] +3059 ] +3060 +3061 scenario editor-scrolls-at-end-on-down-arrow [ +3062 local-scope +3063 assume-screen 10/width, 5/height +3064 s:text <- new [abc +3065 de] +3066 e:&:editor <- new-editor s, 0/left, 10/right +3067 editor-render screen, e +3068 $clear-trace +3069 # try to move down past end of text +3070 assume-console [ +3071 ¦ left-click 2, 0 +3072 ¦ press down-arrow +3073 ] +3074 run [ +3075 ¦ editor-event-loop screen, console, e +3076 ¦ 3:num/raw <- get *e, cursor-row:offset +3077 ¦ 4:num/raw <- get *e, cursor-column:offset +3078 ] +3079 # no change +3080 memory-should-contain [ +3081 ¦ 3 <- 2 +3082 ¦ 4 <- 0 +3083 ] +3084 ] +3085 +3086 scenario editor-combines-page-and-line-scroll [ +3087 local-scope +3088 # screen has 1 line for menu + 3 lines +3089 assume-screen 10/width, 4/height +3090 # initialize editor with a few pages of lines +3091 s:text <- new [a +3092 b +3093 c +3094 d +3095 e +3096 f +3097 g] +3098 e:&:editor <- new-editor s, 0/left, 5/right +3099 editor-render screen, e +3100 # scroll down one page and one line +3101 assume-console [ +3102 ¦ press page-down +3103 ¦ left-click 3, 0 +3104 ¦ press down-arrow +3105 ] +3106 run [ +3107 ¦ editor-event-loop screen, console, e +3108 ] +3109 # screen scrolls down 3 lines +3110 screen-should-contain [ +3111 ¦ . . +3112 ¦ .d . +3113 ¦ .e . +3114 ¦ .f . +3115 ] +3116 ] +3117 +3118 # scroll up if necessary +3119 +3120 scenario editor-can-scroll-up-using-arrow-keys [ +3121 local-scope +3122 # screen has 1 line for menu + 3 lines +3123 assume-screen 10/width, 4/height +3124 # initialize editor with >3 lines +3125 s:text <- new [a +3126 b +3127 c +3128 d] +3129 e:&:editor <- new-editor s, 0/left, 10/right +3130 editor-render screen, e +3131 screen-should-contain [ +3132 ¦ . . +3133 ¦ .a . +3134 ¦ .b . +3135 ¦ .c . +3136 ] +3137 # position cursor at top of second page, then try to move up +3138 assume-console [ +3139 ¦ press page-down +3140 ¦ press up-arrow +3141 ] +3142 run [ +3143 ¦ editor-event-loop screen, console, e +3144 ] +3145 # screen slides by one line +3146 screen-should-contain [ +3147 ¦ . . +3148 ¦ .b . +3149 ¦ .c . +3150 ¦ .d . +3151 ] +3152 ] +3153 +3154 after <scroll-up> [ +3155 trace 10, [app], [scroll up] +3156 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3157 old-top:&:duplex-list:char <- copy top-of-screen +3158 top-of-screen <- before-previous-screen-line top-of-screen, editor +3159 *editor <- put *editor, top-of-screen:offset, top-of-screen +3160 no-movement?:bool <- equal old-top, top-of-screen +3161 return-if no-movement?, 0/don't-render +3162 ] +3163 +3164 # Takes a pointer into the doubly-linked list, scans back to before start of +3165 # previous *wrapped* line. +3166 # Returns original if no next newline. +3167 # Beware: never return null pointer. +3168 def before-previous-screen-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [ +3169 local-scope +3170 load-ingredients +3171 curr:&:duplex-list:char <- copy in +3172 c:char <- get *curr, value:offset +3173 # compute max, number of characters to skip +3174 # 1 + len%(width-1) +3175 # except rotate second term to vary from 1 to width-1 rather than 0 to width-2 +3176 left:num <- get *editor, left:offset +3177 right:num <- get *editor, right:offset +3178 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon +3179 sentinel:&:duplex-list:char <- get *editor, data:offset +3180 len:num <- previous-line-length curr, sentinel +3181 { +3182 ¦ break-if len +3183 ¦ # empty line; just skip this newline +3184 ¦ prev:&:duplex-list:char <- prev curr +3185 ¦ return-unless prev, curr +3186 ¦ return prev +3187 } +3188 _, max:num <- divide-with-remainder len, max-line-length +3189 # remainder 0 => scan one width-worth +3190 { +3191 ¦ break-if max +3192 ¦ max <- copy max-line-length +3193 } +3194 max <- add max, 1 +3195 count:num <- copy 0 +3196 # skip 'max' characters +3197 { +3198 ¦ done?:bool <- greater-or-equal count, max +3199 ¦ break-if done? +3200 ¦ prev:&:duplex-list:char <- prev curr +3201 ¦ break-unless prev +3202 ¦ curr <- copy prev +3203 ¦ count <- add count, 1 +3204 ¦ loop +3205 } +3206 return curr +3207 ] +3208 +3209 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [ +3210 local-scope +3211 # screen has 1 line for menu + 3 lines +3212 assume-screen 10/width, 4/height +3213 # initialize editor with a long, wrapped line and more than a screen of +3214 # other lines +3215 s:text <- new [abcdef +3216 g +3217 h +3218 i] +3219 e:&:editor <- new-editor s, 0/left, 5/right +3220 editor-render screen, e +3221 screen-should-contain [ +3222 ¦ . . +3223 ¦ .abcd↩ . +3224 ¦ .ef . +3225 ¦ .g . +3226 ] +3227 # position cursor at top of second page, just below wrapped line +3228 assume-console [ +3229 ¦ press page-down +3230 ] +3231 run [ +3232 ¦ editor-event-loop screen, console, e +3233 ] +3234 screen-should-contain [ +3235 ¦ . . +3236 ¦ .g . +3237 ¦ .h . +3238 ¦ .i . +3239 ] +3240 # now move up one line +3241 assume-console [ +3242 ¦ press up-arrow +3243 ] +3244 run [ +3245 ¦ editor-event-loop screen, console, e 3246 ] -3247 # move up a second line -3248 assume-console [ -3249 ¦ press up-arrow -3250 ] -3251 run [ -3252 ¦ editor-event-loop screen, console, e +3247 # screen shows partial wrapped line +3248 screen-should-contain [ +3249 ¦ . . +3250 ¦ .ef . +3251 ¦ .g . +3252 ¦ .h . 3253 ] -3254 # screen shows partial wrapped line -3255 screen-should-contain [ -3256 ¦ . . -3257 ¦ .efgh↩ . -3258 ¦ .ij . -3259 ¦ .k . -3260 ¦ .l . -3261 ] -3262 # move up a third line -3263 assume-console [ -3264 ¦ press up-arrow -3265 ] -3266 run [ -3267 ¦ editor-event-loop screen, console, e -3268 ] -3269 # screen shows partial wrapped line -3270 screen-should-contain [ -3271 ¦ . . -3272 ¦ .abcd↩ . -3273 ¦ .efgh↩ . -3274 ¦ .ij . -3275 ¦ .k . -3276 ] -3277 ] -3278 -3279 # same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length -3280 # slightly off, just to prevent over-training -3281 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [ -3282 local-scope -3283 # screen has 1 line for menu + 3 lines -3284 assume-screen 10/width, 4/height -3285 # initialize editor with a long, wrapped line and more than a screen of -3286 # other lines -3287 s:text <- new [abcdef -3288 g -3289 h -3290 i] -3291 e:&:editor <- new-editor s, 0/left, 6/right -3292 editor-render screen, e -3293 screen-should-contain [ -3294 ¦ . . -3295 ¦ .abcde↩ . -3296 ¦ .f . -3297 ¦ .g . -3298 ] -3299 # position cursor at top of second page, just below wrapped line -3300 assume-console [ -3301 ¦ press page-down +3254 ] +3255 +3256 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [ +3257 local-scope +3258 # screen has 1 line for menu + 4 lines +3259 assume-screen 10/width, 5/height +3260 # editor starts with a long line wrapping twice, occupying 3 of the 4 lines +3261 s:text <- new [abcdefghij +3262 k +3263 l +3264 m] +3265 e:&:editor <- new-editor s, 0/left, 5/right +3266 editor-render screen, e +3267 # position cursor at top of second page +3268 assume-console [ +3269 ¦ press page-down +3270 ] +3271 run [ +3272 ¦ editor-event-loop screen, console, e +3273 ] +3274 screen-should-contain [ +3275 ¦ . . +3276 ¦ .k . +3277 ¦ .l . +3278 ¦ .m . +3279 ¦ .╌╌╌╌╌ . +3280 ] +3281 # move up one line +3282 assume-console [ +3283 ¦ press up-arrow +3284 ] +3285 run [ +3286 ¦ editor-event-loop screen, console, e +3287 ] +3288 # screen shows partial wrapped line +3289 screen-should-contain [ +3290 ¦ . . +3291 ¦ .ij . +3292 ¦ .k . +3293 ¦ .l . +3294 ¦ .m . +3295 ] +3296 # move up a second line +3297 assume-console [ +3298 ¦ press up-arrow +3299 ] +3300 run [ +3301 ¦ editor-event-loop screen, console, e 3302 ] -3303 run [ -3304 ¦ editor-event-loop screen, console, e -3305 ] -3306 screen-should-contain [ -3307 ¦ . . -3308 ¦ .g . -3309 ¦ .h . -3310 ¦ .i . -3311 ] -3312 # now move up one line -3313 assume-console [ -3314 ¦ press up-arrow -3315 ] -3316 run [ -3317 ¦ editor-event-loop screen, console, e -3318 ] -3319 # screen shows partial wrapped line -3320 screen-should-contain [ -3321 ¦ . . -3322 ¦ .f . -3323 ¦ .g . -3324 ¦ .h . +3303 # screen shows partial wrapped line +3304 screen-should-contain [ +3305 ¦ . . +3306 ¦ .efgh↩ . +3307 ¦ .ij . +3308 ¦ .k . +3309 ¦ .l . +3310 ] +3311 # move up a third line +3312 assume-console [ +3313 ¦ press up-arrow +3314 ] +3315 run [ +3316 ¦ editor-event-loop screen, console, e +3317 ] +3318 # screen shows partial wrapped line +3319 screen-should-contain [ +3320 ¦ . . +3321 ¦ .abcd↩ . +3322 ¦ .efgh↩ . +3323 ¦ .ij . +3324 ¦ .k . 3325 ] 3326 ] 3327 -3328 # check empty lines -3329 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ -3330 local-scope -3331 assume-screen 10/width, 4/height -3332 # initialize editor with some lines around an empty line -3333 s:text <- new [a -3334 b -3335 -3336 c -3337 d -3338 e] -3339 e:&:editor <- new-editor s, 0/left, 6/right -3340 editor-render screen, e -3341 assume-console [ -3342 ¦ press page-down -3343 ] -3344 run [ -3345 ¦ editor-event-loop screen, console, e -3346 ] -3347 screen-should-contain [ -3348 ¦ . . -3349 ¦ . . -3350 ¦ .c . -3351 ¦ .d . -3352 ] -3353 assume-console [ -3354 ¦ press page-down -3355 ] -3356 run [ -3357 ¦ editor-event-loop screen, console, e -3358 ] -3359 screen-should-contain [ -3360 ¦ . . -3361 ¦ .d . -3362 ¦ .e . -3363 ¦ .╌╌╌╌╌╌ . +3328 # same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length +3329 # slightly off, just to prevent over-training +3330 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [ +3331 local-scope +3332 # screen has 1 line for menu + 3 lines +3333 assume-screen 10/width, 4/height +3334 # initialize editor with a long, wrapped line and more than a screen of +3335 # other lines +3336 s:text <- new [abcdef +3337 g +3338 h +3339 i] +3340 e:&:editor <- new-editor s, 0/left, 6/right +3341 editor-render screen, e +3342 screen-should-contain [ +3343 ¦ . . +3344 ¦ .abcde↩ . +3345 ¦ .f . +3346 ¦ .g . +3347 ] +3348 # position cursor at top of second page, just below wrapped line +3349 assume-console [ +3350 ¦ press page-down +3351 ] +3352 run [ +3353 ¦ editor-event-loop screen, console, e +3354 ] +3355 screen-should-contain [ +3356 ¦ . . +3357 ¦ .g . +3358 ¦ .h . +3359 ¦ .i . +3360 ] +3361 # now move up one line +3362 assume-console [ +3363 ¦ press up-arrow 3364 ] -3365 assume-console [ -3366 ¦ press page-up +3365 run [ +3366 ¦ editor-event-loop screen, console, e 3367 ] -3368 run [ -3369 ¦ editor-event-loop screen, console, e -3370 ] -3371 screen-should-contain [ -3372 ¦ . . -3373 ¦ . . -3374 ¦ .c . -3375 ¦ .d . -3376 ] -3377 ] -3378 -3379 scenario editor-scrolls-up-on-left-arrow [ -3380 local-scope -3381 # screen has 1 line for menu + 3 lines -3382 assume-screen 5/width, 4/height -3383 # editor contains >3 lines -3384 s:text <- new [a -3385 b -3386 c -3387 d -3388 e] -3389 e:&:editor <- new-editor s, 0/left, 5/right -3390 editor-render screen, e -3391 # position cursor at top of second page -3392 assume-console [ -3393 ¦ press page-down -3394 ] -3395 run [ -3396 ¦ editor-event-loop screen, console, e -3397 ] -3398 screen-should-contain [ -3399 ¦ . . -3400 ¦ .c . -3401 ¦ .d . -3402 ¦ .e . -3403 ] -3404 # now try to move left -3405 assume-console [ -3406 ¦ press left-arrow +3368 # screen shows partial wrapped line +3369 screen-should-contain [ +3370 ¦ . . +3371 ¦ .f . +3372 ¦ .g . +3373 ¦ .h . +3374 ] +3375 ] +3376 +3377 # check empty lines +3378 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ +3379 local-scope +3380 assume-screen 10/width, 4/height +3381 # initialize editor with some lines around an empty line +3382 s:text <- new [a +3383 b +3384 +3385 c +3386 d +3387 e] +3388 e:&:editor <- new-editor s, 0/left, 6/right +3389 editor-render screen, e +3390 assume-console [ +3391 ¦ press page-down +3392 ] +3393 run [ +3394 ¦ editor-event-loop screen, console, e +3395 ] +3396 screen-should-contain [ +3397 ¦ . . +3398 ¦ . . +3399 ¦ .c . +3400 ¦ .d . +3401 ] +3402 assume-console [ +3403 ¦ press page-down +3404 ] +3405 run [ +3406 ¦ editor-event-loop screen, console, e 3407 ] -3408 run [ -3409 ¦ editor-event-loop screen, console, e -3410 ¦ 3:num/raw <- get *e, cursor-row:offset -3411 ¦ 4:num/raw <- get *e, cursor-column:offset -3412 ] -3413 # screen scrolls -3414 screen-should-contain [ -3415 ¦ . . -3416 ¦ .b . -3417 ¦ .c . -3418 ¦ .d . +3408 screen-should-contain [ +3409 ¦ . . +3410 ¦ .d . +3411 ¦ .e . +3412 ¦ .╌╌╌╌╌╌ . +3413 ] +3414 assume-console [ +3415 ¦ press page-up +3416 ] +3417 run [ +3418 ¦ editor-event-loop screen, console, e 3419 ] -3420 memory-should-contain [ -3421 ¦ 3 <- 1 -3422 ¦ 4 <- 1 -3423 ] -3424 ] -3425 -3426 scenario editor-can-scroll-up-to-start-of-file [ -3427 local-scope -3428 # screen has 1 line for menu + 3 lines -3429 assume-screen 10/width, 4/height -3430 # initialize editor with >3 lines -3431 s:text <- new [a -3432 b -3433 c -3434 d] -3435 e:&:editor <- new-editor s, 0/left, 10/right -3436 editor-render screen, e -3437 screen-should-contain [ -3438 ¦ . . -3439 ¦ .a . -3440 ¦ .b . -3441 ¦ .c . -3442 ] -3443 # position cursor at top of second page, then try to move up to start of -3444 # text -3445 assume-console [ -3446 ¦ press page-down -3447 ¦ press up-arrow -3448 ¦ press up-arrow -3449 ] -3450 run [ -3451 ¦ editor-event-loop screen, console, e +3420 screen-should-contain [ +3421 ¦ . . +3422 ¦ . . +3423 ¦ .c . +3424 ¦ .d . +3425 ] +3426 ] +3427 +3428 scenario editor-scrolls-up-on-left-arrow [ +3429 local-scope +3430 # screen has 1 line for menu + 3 lines +3431 assume-screen 5/width, 4/height +3432 # editor contains >3 lines +3433 s:text <- new [a +3434 b +3435 c +3436 d +3437 e] +3438 e:&:editor <- new-editor s, 0/left, 5/right +3439 editor-render screen, e +3440 # position cursor at top of second page +3441 assume-console [ +3442 ¦ press page-down +3443 ] +3444 run [ +3445 ¦ editor-event-loop screen, console, e +3446 ] +3447 screen-should-contain [ +3448 ¦ . . +3449 ¦ .c . +3450 ¦ .d . +3451 ¦ .e . 3452 ] -3453 # screen slides by one line -3454 screen-should-contain [ -3455 ¦ . . -3456 ¦ .a . -3457 ¦ .b . -3458 ¦ .c . -3459 ] -3460 # try to move up again -3461 assume-console [ -3462 ¦ press up-arrow -3463 ] -3464 run [ -3465 ¦ editor-event-loop screen, console, e -3466 ] -3467 # screen remains unchanged -3468 screen-should-contain [ -3469 ¦ . . -3470 ¦ .a . -3471 ¦ .b . -3472 ¦ .c . -3473 ] -3474 ] -3475 -3476 # ctrl-f/page-down - render next page if it exists -3477 -3478 scenario editor-can-scroll [ -3479 local-scope -3480 assume-screen 10/width, 4/height -3481 s:text <- new [a -3482 b -3483 c -3484 d] -3485 e:&:editor <- new-editor s, 0/left, 10/right -3486 editor-render screen, e -3487 screen-should-contain [ -3488 ¦ . . -3489 ¦ .a . -3490 ¦ .b . -3491 ¦ .c . -3492 ] -3493 # scroll down +3453 # now try to move left +3454 assume-console [ +3455 ¦ press left-arrow +3456 ] +3457 run [ +3458 ¦ editor-event-loop screen, console, e +3459 ¦ 3:num/raw <- get *e, cursor-row:offset +3460 ¦ 4:num/raw <- get *e, cursor-column:offset +3461 ] +3462 # screen scrolls +3463 screen-should-contain [ +3464 ¦ . . +3465 ¦ .b . +3466 ¦ .c . +3467 ¦ .d . +3468 ] +3469 memory-should-contain [ +3470 ¦ 3 <- 1 +3471 ¦ 4 <- 1 +3472 ] +3473 ] +3474 +3475 scenario editor-can-scroll-up-to-start-of-file [ +3476 local-scope +3477 # screen has 1 line for menu + 3 lines +3478 assume-screen 10/width, 4/height +3479 # initialize editor with >3 lines +3480 s:text <- new [a +3481 b +3482 c +3483 d] +3484 e:&:editor <- new-editor s, 0/left, 10/right +3485 editor-render screen, e +3486 screen-should-contain [ +3487 ¦ . . +3488 ¦ .a . +3489 ¦ .b . +3490 ¦ .c . +3491 ] +3492 # position cursor at top of second page, then try to move up to start of +3493 # text 3494 assume-console [ -3495 ¦ press page-down -3496 ] -3497 run [ -3498 ¦ editor-event-loop screen, console, e -3499 ] -3500 # screen shows next page -3501 screen-should-contain [ -3502 ¦ . . -3503 ¦ .c . -3504 ¦ .d . -3505 ¦ .╌╌╌╌╌╌╌╌╌╌. -3506 ] -3507 ] -3508 -3509 after <handle-special-character> [ -3510 { -3511 ¦ page-down?:bool <- equal c, 6/ctrl-f -3512 ¦ break-unless page-down? -3513 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -3514 ¦ <move-cursor-begin> -3515 ¦ page-down editor -3516 ¦ undo-coalesce-tag:num <- copy 0/never -3517 ¦ <move-cursor-end> -3518 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3519 ¦ movement?:bool <- not-equal top-of-screen, old-top -3520 ¦ return movement?/go-render -3521 } -3522 ] -3523 -3524 after <handle-special-key> [ -3525 { -3526 ¦ page-down?:bool <- equal k, 65518/page-down -3527 ¦ break-unless page-down? -3528 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -3529 ¦ <move-cursor-begin> -3530 ¦ page-down editor -3531 ¦ undo-coalesce-tag:num <- copy 0/never -3532 ¦ <move-cursor-end> -3533 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3534 ¦ movement?:bool <- not-equal top-of-screen, old-top -3535 ¦ return movement?/go-render -3536 } -3537 ] -3538 -3539 # page-down skips entire wrapped lines, so it can't scroll past lines -3540 # taking up the entire screen -3541 def page-down editor:&:editor -> editor:&:editor [ -3542 local-scope -3543 load-ingredients -3544 # if editor contents don't overflow screen, do nothing -3545 bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset -3546 return-unless bottom-of-screen -3547 # if not, position cursor at final character -3548 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -3549 before-cursor:&:duplex-list:char <- prev bottom-of-screen -3550 *editor <- put *editor, before-cursor:offset, before-cursor -3551 # keep one line in common with previous page -3552 { -3553 ¦ last:char <- get *before-cursor, value:offset -3554 ¦ newline?:bool <- equal last, 10/newline -3555 ¦ break-unless newline?:bool -3556 ¦ before-cursor <- prev before-cursor -3557 ¦ *editor <- put *editor, before-cursor:offset, before-cursor -3558 } -3559 # move cursor and top-of-screen to start of that line -3560 move-to-start-of-line editor -3561 before-cursor <- get *editor, before-cursor:offset -3562 *editor <- put *editor, top-of-screen:offset, before-cursor -3563 ] -3564 -3565 # jump to previous newline -3566 def move-to-start-of-line editor:&:editor -> editor:&:editor [ -3567 local-scope -3568 load-ingredients -3569 # update cursor column -3570 left:num <- get *editor, left:offset -3571 cursor-column:num <- copy left -3572 *editor <- put *editor, cursor-column:offset, cursor-column -3573 # update before-cursor -3574 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -3575 init:&:duplex-list:char <- get *editor, data:offset -3576 # while not at start of line, move -3577 { -3578 ¦ at-start-of-text?:bool <- equal before-cursor, init -3579 ¦ break-if at-start-of-text? -3580 ¦ prev:char <- get *before-cursor, value:offset -3581 ¦ at-start-of-line?:bool <- equal prev, 10/newline -3582 ¦ break-if at-start-of-line? -3583 ¦ before-cursor <- prev before-cursor -3584 ¦ *editor <- put *editor, before-cursor:offset, before-cursor -3585 ¦ assert before-cursor, [move-to-start-of-line tried to move before start of text] -3586 ¦ loop -3587 } -3588 ] -3589 -3590 scenario editor-does-not-scroll-past-end [ +3495 ¦ press page-down +3496 ¦ press up-arrow +3497 ¦ press up-arrow +3498 ] +3499 run [ +3500 ¦ editor-event-loop screen, console, e +3501 ] +3502 # screen slides by one line +3503 screen-should-contain [ +3504 ¦ . . +3505 ¦ .a . +3506 ¦ .b . +3507 ¦ .c . +3508 ] +3509 # try to move up again +3510 assume-console [ +3511 ¦ press up-arrow +3512 ] +3513 run [ +3514 ¦ editor-event-loop screen, console, e +3515 ] +3516 # screen remains unchanged +3517 screen-should-contain [ +3518 ¦ . . +3519 ¦ .a . +3520 ¦ .b . +3521 ¦ .c . +3522 ] +3523 ] +3524 +3525 # ctrl-f/page-down - render next page if it exists +3526 +3527 scenario editor-can-scroll [ +3528 local-scope +3529 assume-screen 10/width, 4/height +3530 s:text <- new [a +3531 b +3532 c +3533 d] +3534 e:&:editor <- new-editor s, 0/left, 10/right +3535 editor-render screen, e +3536 screen-should-contain [ +3537 ¦ . . +3538 ¦ .a . +3539 ¦ .b . +3540 ¦ .c . +3541 ] +3542 # scroll down +3543 assume-console [ +3544 ¦ press page-down +3545 ] +3546 run [ +3547 ¦ editor-event-loop screen, console, e +3548 ] +3549 # screen shows next page +3550 screen-should-contain [ +3551 ¦ . . +3552 ¦ .c . +3553 ¦ .d . +3554 ¦ .╌╌╌╌╌╌╌╌╌╌. +3555 ] +3556 ] +3557 +3558 after <handle-special-character> [ +3559 { +3560 ¦ page-down?:bool <- equal c, 6/ctrl-f +3561 ¦ break-unless page-down? +3562 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +3563 ¦ <move-cursor-begin> +3564 ¦ page-down editor +3565 ¦ undo-coalesce-tag:num <- copy 0/never +3566 ¦ <move-cursor-end> +3567 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3568 ¦ movement?:bool <- not-equal top-of-screen, old-top +3569 ¦ return movement?/go-render +3570 } +3571 ] +3572 +3573 after <handle-special-key> [ +3574 { +3575 ¦ page-down?:bool <- equal k, 65518/page-down +3576 ¦ break-unless page-down? +3577 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +3578 ¦ <move-cursor-begin> +3579 ¦ page-down editor +3580 ¦ undo-coalesce-tag:num <- copy 0/never +3581 ¦ <move-cursor-end> +3582 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3583 ¦ movement?:bool <- not-equal top-of-screen, old-top +3584 ¦ return movement?/go-render +3585 } +3586 ] +3587 +3588 # page-down skips entire wrapped lines, so it can't scroll past lines +3589 # taking up the entire screen +3590 def page-down editor:&:editor -> editor:&:editor [ 3591 local-scope -3592 assume-screen 10/width, 4/height -3593 s:text <- new [a -3594 b] -3595 e:&:editor <- new-editor s, 0/left, 10/right -3596 editor-render screen, e -3597 screen-should-contain [ -3598 ¦ . . -3599 ¦ .a . -3600 ¦ .b . -3601 ¦ .╌╌╌╌╌╌╌╌╌╌. -3602 ] -3603 # scroll down -3604 assume-console [ -3605 ¦ press page-down -3606 ] -3607 run [ -3608 ¦ editor-event-loop screen, console, e -3609 ] -3610 # screen remains unmodified -3611 screen-should-contain [ -3612 ¦ . . -3613 ¦ .a . -3614 ¦ .b . -3615 ¦ .╌╌╌╌╌╌╌╌╌╌. -3616 ] -3617 ] -3618 -3619 scenario editor-starts-next-page-at-start-of-wrapped-line [ -3620 local-scope -3621 # screen has 1 line for menu + 3 lines for text -3622 assume-screen 10/width, 4/height -3623 # editor contains a long last line -3624 s:text <- new [a -3625 b -3626 cdefgh] -3627 # editor screen triggers wrap of last line -3628 e:&:editor <- new-editor s, 0/left, 4/right -3629 editor-render screen, e -3630 # some part of last line is not displayed -3631 screen-should-contain [ -3632 ¦ . . -3633 ¦ .a . -3634 ¦ .b . -3635 ¦ .cde↩ . -3636 ] -3637 # scroll down -3638 assume-console [ -3639 ¦ press page-down -3640 ] -3641 run [ -3642 ¦ editor-event-loop screen, console, e -3643 ] -3644 # screen shows entire wrapped line -3645 screen-should-contain [ -3646 ¦ . . -3647 ¦ .cde↩ . -3648 ¦ .fgh . -3649 ¦ .╌╌╌╌ . -3650 ] -3651 ] -3652 -3653 scenario editor-starts-next-page-at-start-of-wrapped-line-2 [ -3654 local-scope -3655 # screen has 1 line for menu + 3 lines for text -3656 assume-screen 10/width, 4/height -3657 # editor contains a very long line that occupies last two lines of screen -3658 # and still has something left over -3659 s:text <- new [a -3660 bcdefgh] -3661 e:&:editor <- new-editor s, 0/left, 4/right -3662 editor-render screen, e -3663 # some part of last line is not displayed -3664 screen-should-contain [ -3665 ¦ . . -3666 ¦ .a . -3667 ¦ .bcd↩ . -3668 ¦ .efg↩ . -3669 ] -3670 # scroll down -3671 assume-console [ -3672 ¦ press page-down -3673 ] -3674 run [ -3675 ¦ editor-event-loop screen, console, e -3676 ] -3677 # screen shows entire wrapped line -3678 screen-should-contain [ -3679 ¦ . . -3680 ¦ .bcd↩ . -3681 ¦ .efg↩ . -3682 ¦ .h . -3683 ] -3684 ] -3685 -3686 # ctrl-b/page-up - render previous page if it exists -3687 -3688 scenario editor-can-scroll-up [ -3689 local-scope -3690 assume-screen 10/width, 4/height -3691 s:text <- new [a -3692 b -3693 c -3694 d] -3695 e:&:editor <- new-editor s, 0/left, 10/right -3696 editor-render screen, e -3697 screen-should-contain [ -3698 ¦ . . -3699 ¦ .a . -3700 ¦ .b . -3701 ¦ .c . -3702 ] -3703 # scroll down -3704 assume-console [ -3705 ¦ press page-down -3706 ] -3707 run [ -3708 ¦ editor-event-loop screen, console, e -3709 ] -3710 # screen shows next page -3711 screen-should-contain [ -3712 ¦ . . -3713 ¦ .c . -3714 ¦ .d . -3715 ¦ .╌╌╌╌╌╌╌╌╌╌. -3716 ] -3717 # scroll back up -3718 assume-console [ -3719 ¦ press page-up -3720 ] -3721 run [ -3722 ¦ editor-event-loop screen, console, e -3723 ] -3724 # screen shows original page again -3725 screen-should-contain [ -3726 ¦ . . -3727 ¦ .a . -3728 ¦ .b . -3729 ¦ .c . -3730 ] -3731 ] -3732 -3733 after <handle-special-character> [ -3734 { -3735 ¦ page-up?:bool <- equal c, 2/ctrl-b -3736 ¦ break-unless page-up? -3737 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -3738 ¦ <move-cursor-begin> -3739 ¦ editor <- page-up editor, screen-height -3740 ¦ undo-coalesce-tag:num <- copy 0/never -3741 ¦ <move-cursor-end> -3742 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3743 ¦ movement?:bool <- not-equal top-of-screen, old-top -3744 ¦ return movement?/go-render -3745 } -3746 ] -3747 -3748 after <handle-special-key> [ -3749 { -3750 ¦ page-up?:bool <- equal k, 65519/page-up -3751 ¦ break-unless page-up? -3752 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -3753 ¦ <move-cursor-begin> -3754 ¦ editor <- page-up editor, screen-height -3755 ¦ undo-coalesce-tag:num <- copy 0/never -3756 ¦ <move-cursor-end> -3757 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3758 ¦ movement?:bool <- not-equal top-of-screen, old-top -3759 ¦ # don't bother re-rendering if nothing changed. todo: test this -3760 ¦ return movement?/go-render -3761 } -3762 ] -3763 -3764 def page-up editor:&:editor, screen-height:num -> editor:&:editor [ -3765 local-scope -3766 load-ingredients -3767 max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line -3768 count:num <- copy 0 -3769 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -3770 { -3771 ¦ done?:bool <- greater-or-equal count, max -3772 ¦ break-if done? -3773 ¦ prev:&:duplex-list:char <- before-previous-screen-line top-of-screen, editor -3774 ¦ break-unless prev -3775 ¦ top-of-screen <- copy prev -3776 ¦ *editor <- put *editor, top-of-screen:offset, top-of-screen -3777 ¦ count <- add count, 1 -3778 ¦ loop -3779 } +3592 load-ingredients +3593 # if editor contents don't overflow screen, do nothing +3594 bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset +3595 return-unless bottom-of-screen +3596 # if not, position cursor at final character +3597 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +3598 before-cursor:&:duplex-list:char <- prev bottom-of-screen +3599 *editor <- put *editor, before-cursor:offset, before-cursor +3600 # keep one line in common with previous page +3601 { +3602 ¦ last:char <- get *before-cursor, value:offset +3603 ¦ newline?:bool <- equal last, 10/newline +3604 ¦ break-unless newline?:bool +3605 ¦ before-cursor <- prev before-cursor +3606 ¦ *editor <- put *editor, before-cursor:offset, before-cursor +3607 } +3608 # move cursor and top-of-screen to start of that line +3609 move-to-start-of-line editor +3610 before-cursor <- get *editor, before-cursor:offset +3611 *editor <- put *editor, top-of-screen:offset, before-cursor +3612 ] +3613 +3614 # jump to previous newline +3615 def move-to-start-of-line editor:&:editor -> editor:&:editor [ +3616 local-scope +3617 load-ingredients +3618 # update cursor column +3619 left:num <- get *editor, left:offset +3620 cursor-column:num <- copy left +3621 *editor <- put *editor, cursor-column:offset, cursor-column +3622 # update before-cursor +3623 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +3624 init:&:duplex-list:char <- get *editor, data:offset +3625 # while not at start of line, move +3626 { +3627 ¦ at-start-of-text?:bool <- equal before-cursor, init +3628 ¦ break-if at-start-of-text? +3629 ¦ prev:char <- get *before-cursor, value:offset +3630 ¦ at-start-of-line?:bool <- equal prev, 10/newline +3631 ¦ break-if at-start-of-line? +3632 ¦ before-cursor <- prev before-cursor +3633 ¦ *editor <- put *editor, before-cursor:offset, before-cursor +3634 ¦ assert before-cursor, [move-to-start-of-line tried to move before start of text] +3635 ¦ loop +3636 } +3637 ] +3638 +3639 scenario editor-does-not-scroll-past-end [ +3640 local-scope +3641 assume-screen 10/width, 4/height +3642 s:text <- new [a +3643 b] +3644 e:&:editor <- new-editor s, 0/left, 10/right +3645 editor-render screen, e +3646 screen-should-contain [ +3647 ¦ . . +3648 ¦ .a . +3649 ¦ .b . +3650 ¦ .╌╌╌╌╌╌╌╌╌╌. +3651 ] +3652 # scroll down +3653 assume-console [ +3654 ¦ press page-down +3655 ] +3656 run [ +3657 ¦ editor-event-loop screen, console, e +3658 ] +3659 # screen remains unmodified +3660 screen-should-contain [ +3661 ¦ . . +3662 ¦ .a . +3663 ¦ .b . +3664 ¦ .╌╌╌╌╌╌╌╌╌╌. +3665 ] +3666 ] +3667 +3668 scenario editor-starts-next-page-at-start-of-wrapped-line [ +3669 local-scope +3670 # screen has 1 line for menu + 3 lines for text +3671 assume-screen 10/width, 4/height +3672 # editor contains a long last line +3673 s:text <- new [a +3674 b +3675 cdefgh] +3676 # editor screen triggers wrap of last line +3677 e:&:editor <- new-editor s, 0/left, 4/right +3678 editor-render screen, e +3679 # some part of last line is not displayed +3680 screen-should-contain [ +3681 ¦ . . +3682 ¦ .a . +3683 ¦ .b . +3684 ¦ .cde↩ . +3685 ] +3686 # scroll down +3687 assume-console [ +3688 ¦ press page-down +3689 ] +3690 run [ +3691 ¦ editor-event-loop screen, console, e +3692 ] +3693 # screen shows entire wrapped line +3694 screen-should-contain [ +3695 ¦ . . +3696 ¦ .cde↩ . +3697 ¦ .fgh . +3698 ¦ .╌╌╌╌ . +3699 ] +3700 ] +3701 +3702 scenario editor-starts-next-page-at-start-of-wrapped-line-2 [ +3703 local-scope +3704 # screen has 1 line for menu + 3 lines for text +3705 assume-screen 10/width, 4/height +3706 # editor contains a very long line that occupies last two lines of screen +3707 # and still has something left over +3708 s:text <- new [a +3709 bcdefgh] +3710 e:&:editor <- new-editor s, 0/left, 4/right +3711 editor-render screen, e +3712 # some part of last line is not displayed +3713 screen-should-contain [ +3714 ¦ . . +3715 ¦ .a . +3716 ¦ .bcd↩ . +3717 ¦ .efg↩ . +3718 ] +3719 # scroll down +3720 assume-console [ +3721 ¦ press page-down +3722 ] +3723 run [ +3724 ¦ editor-event-loop screen, console, e +3725 ] +3726 # screen shows entire wrapped line +3727 screen-should-contain [ +3728 ¦ . . +3729 ¦ .bcd↩ . +3730 ¦ .efg↩ . +3731 ¦ .h . +3732 ] +3733 ] +3734 +3735 # ctrl-b/page-up - render previous page if it exists +3736 +3737 scenario editor-can-scroll-up [ +3738 local-scope +3739 assume-screen 10/width, 4/height +3740 s:text <- new [a +3741 b +3742 c +3743 d] +3744 e:&:editor <- new-editor s, 0/left, 10/right +3745 editor-render screen, e +3746 screen-should-contain [ +3747 ¦ . . +3748 ¦ .a . +3749 ¦ .b . +3750 ¦ .c . +3751 ] +3752 # scroll down +3753 assume-console [ +3754 ¦ press page-down +3755 ] +3756 run [ +3757 ¦ editor-event-loop screen, console, e +3758 ] +3759 # screen shows next page +3760 screen-should-contain [ +3761 ¦ . . +3762 ¦ .c . +3763 ¦ .d . +3764 ¦ .╌╌╌╌╌╌╌╌╌╌. +3765 ] +3766 # scroll back up +3767 assume-console [ +3768 ¦ press page-up +3769 ] +3770 run [ +3771 ¦ editor-event-loop screen, console, e +3772 ] +3773 # screen shows original page again +3774 screen-should-contain [ +3775 ¦ . . +3776 ¦ .a . +3777 ¦ .b . +3778 ¦ .c . +3779 ] 3780 ] 3781 -3782 scenario editor-can-scroll-up-multiple-pages [ -3783 local-scope -3784 # screen has 1 line for menu + 3 lines -3785 assume-screen 10/width, 4/height -3786 # initialize editor with 8 lines -3787 s:text <- new [a -3788 b -3789 c -3790 d -3791 e -3792 f -3793 g -3794 h] -3795 e:&:editor <- new-editor s, 0/left, 10/right -3796 editor-render screen, e -3797 screen-should-contain [ -3798 ¦ . . -3799 ¦ .a . -3800 ¦ .b . -3801 ¦ .c . -3802 ] -3803 # scroll down two pages -3804 assume-console [ -3805 ¦ press page-down -3806 ¦ press page-down -3807 ] -3808 run [ -3809 ¦ editor-event-loop screen, console, e -3810 ] -3811 # screen shows third page -3812 screen-should-contain [ -3813 ¦ . . -3814 ¦ .e . -3815 ¦ .f . -3816 ¦ .g . -3817 ] -3818 # scroll up -3819 assume-console [ -3820 ¦ press page-up -3821 ] -3822 run [ -3823 ¦ editor-event-loop screen, console, e -3824 ] -3825 # screen shows second page -3826 screen-should-contain [ -3827 ¦ . . -3828 ¦ .c . -3829 ¦ .d . -3830 ¦ .e . -3831 ] -3832 # scroll up again -3833 assume-console [ -3834 ¦ press page-up -3835 ] -3836 run [ -3837 ¦ editor-event-loop screen, console, e -3838 ] -3839 # screen shows original page again -3840 screen-should-contain [ -3841 ¦ . . -3842 ¦ .a . -3843 ¦ .b . -3844 ¦ .c . -3845 ] -3846 ] -3847 -3848 scenario editor-can-scroll-up-wrapped-lines [ -3849 local-scope -3850 # screen has 1 line for menu + 5 lines for text -3851 assume-screen 10/width, 6/height -3852 # editor contains a long line in the first page -3853 s:text <- new [a -3854 b -3855 cdefgh -3856 i -3857 j -3858 k -3859 l -3860 m -3861 n -3862 o] -3863 # editor screen triggers wrap of last line -3864 e:&:editor <- new-editor s, 0/left, 4/right -3865 editor-render screen, e -3866 # some part of last line is not displayed -3867 screen-should-contain [ -3868 ¦ . . -3869 ¦ .a . -3870 ¦ .b . -3871 ¦ .cde↩ . -3872 ¦ .fgh . -3873 ¦ .i . -3874 ] -3875 # scroll down a page and a line -3876 assume-console [ -3877 ¦ press page-down -3878 ¦ left-click 5, 0 -3879 ¦ press down-arrow +3782 after <handle-special-character> [ +3783 { +3784 ¦ page-up?:bool <- equal c, 2/ctrl-b +3785 ¦ break-unless page-up? +3786 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +3787 ¦ <move-cursor-begin> +3788 ¦ editor <- page-up editor, screen-height +3789 ¦ undo-coalesce-tag:num <- copy 0/never +3790 ¦ <move-cursor-end> +3791 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3792 ¦ movement?:bool <- not-equal top-of-screen, old-top +3793 ¦ return movement?/go-render +3794 } +3795 ] +3796 +3797 after <handle-special-key> [ +3798 { +3799 ¦ page-up?:bool <- equal k, 65519/page-up +3800 ¦ break-unless page-up? +3801 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +3802 ¦ <move-cursor-begin> +3803 ¦ editor <- page-up editor, screen-height +3804 ¦ undo-coalesce-tag:num <- copy 0/never +3805 ¦ <move-cursor-end> +3806 ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3807 ¦ movement?:bool <- not-equal top-of-screen, old-top +3808 ¦ # don't bother re-rendering if nothing changed. todo: test this +3809 ¦ return movement?/go-render +3810 } +3811 ] +3812 +3813 def page-up editor:&:editor, screen-height:num -> editor:&:editor [ +3814 local-scope +3815 load-ingredients +3816 max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line +3817 count:num <- copy 0 +3818 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +3819 { +3820 ¦ done?:bool <- greater-or-equal count, max +3821 ¦ break-if done? +3822 ¦ prev:&:duplex-list:char <- before-previous-screen-line top-of-screen, editor +3823 ¦ break-unless prev +3824 ¦ top-of-screen <- copy prev +3825 ¦ *editor <- put *editor, top-of-screen:offset, top-of-screen +3826 ¦ count <- add count, 1 +3827 ¦ loop +3828 } +3829 ] +3830 +3831 scenario editor-can-scroll-up-multiple-pages [ +3832 local-scope +3833 # screen has 1 line for menu + 3 lines +3834 assume-screen 10/width, 4/height +3835 # initialize editor with 8 lines +3836 s:text <- new [a +3837 b +3838 c +3839 d +3840 e +3841 f +3842 g +3843 h] +3844 e:&:editor <- new-editor s, 0/left, 10/right +3845 editor-render screen, e +3846 screen-should-contain [ +3847 ¦ . . +3848 ¦ .a . +3849 ¦ .b . +3850 ¦ .c . +3851 ] +3852 # scroll down two pages +3853 assume-console [ +3854 ¦ press page-down +3855 ¦ press page-down +3856 ] +3857 run [ +3858 ¦ editor-event-loop screen, console, e +3859 ] +3860 # screen shows third page +3861 screen-should-contain [ +3862 ¦ . . +3863 ¦ .e . +3864 ¦ .f . +3865 ¦ .g . +3866 ] +3867 # scroll up +3868 assume-console [ +3869 ¦ press page-up +3870 ] +3871 run [ +3872 ¦ editor-event-loop screen, console, e +3873 ] +3874 # screen shows second page +3875 screen-should-contain [ +3876 ¦ . . +3877 ¦ .c . +3878 ¦ .d . +3879 ¦ .e . 3880 ] -3881 run [ -3882 ¦ editor-event-loop screen, console, e -3883 ] -3884 # screen shows entire wrapped line -3885 screen-should-contain [ -3886 ¦ . . -3887 ¦ .j . -3888 ¦ .k . -3889 ¦ .l . -3890 ¦ .m . -3891 ¦ .n . -3892 ] -3893 # now scroll up one page -3894 assume-console [ -3895 ¦ press page-up -3896 ] -3897 run [ -3898 ¦ editor-event-loop screen, console, e -3899 ] -3900 # screen resets -3901 screen-should-contain [ -3902 ¦ . . -3903 ¦ .b . -3904 ¦ .cde↩ . -3905 ¦ .fgh . -3906 ¦ .i . -3907 ¦ .j . -3908 ] -3909 ] -3910 -3911 scenario editor-can-scroll-up-wrapped-lines-2 [ -3912 local-scope -3913 # screen has 1 line for menu + 3 lines for text -3914 assume-screen 10/width, 4/height -3915 # editor contains a very long line that occupies last two lines of screen -3916 # and still has something left over -3917 s:text <- new [a -3918 bcdefgh] -3919 e:&:editor <- new-editor s, 0/left, 4/right -3920 editor-render screen, e -3921 # some part of last line is not displayed -3922 screen-should-contain [ -3923 ¦ . . -3924 ¦ .a . -3925 ¦ .bcd↩ . -3926 ¦ .efg↩ . -3927 ] -3928 # scroll down -3929 assume-console [ -3930 ¦ press page-down -3931 ] -3932 run [ -3933 ¦ editor-event-loop screen, console, e -3934 ] -3935 # screen shows entire wrapped line -3936 screen-should-contain [ -3937 ¦ . . -3938 ¦ .bcd↩ . -3939 ¦ .efg↩ . -3940 ¦ .h . +3881 # scroll up again +3882 assume-console [ +3883 ¦ press page-up +3884 ] +3885 run [ +3886 ¦ editor-event-loop screen, console, e +3887 ] +3888 # screen shows original page again +3889 screen-should-contain [ +3890 ¦ . . +3891 ¦ .a . +3892 ¦ .b . +3893 ¦ .c . +3894 ] +3895 ] +3896 +3897 scenario editor-can-scroll-up-wrapped-lines [ +3898 local-scope +3899 # screen has 1 line for menu + 5 lines for text +3900 assume-screen 10/width, 6/height +3901 # editor contains a long line in the first page +3902 s:text <- new [a +3903 b +3904 cdefgh +3905 i +3906 j +3907 k +3908 l +3909 m +3910 n +3911 o] +3912 # editor screen triggers wrap of last line +3913 e:&:editor <- new-editor s, 0/left, 4/right +3914 editor-render screen, e +3915 # some part of last line is not displayed +3916 screen-should-contain [ +3917 ¦ . . +3918 ¦ .a . +3919 ¦ .b . +3920 ¦ .cde↩ . +3921 ¦ .fgh . +3922 ¦ .i . +3923 ] +3924 # scroll down a page and a line +3925 assume-console [ +3926 ¦ press page-down +3927 ¦ left-click 5, 0 +3928 ¦ press down-arrow +3929 ] +3930 run [ +3931 ¦ editor-event-loop screen, console, e +3932 ] +3933 # screen shows entire wrapped line +3934 screen-should-contain [ +3935 ¦ . . +3936 ¦ .j . +3937 ¦ .k . +3938 ¦ .l . +3939 ¦ .m . +3940 ¦ .n . 3941 ] -3942 # scroll back up +3942 # now scroll up one page 3943 assume-console [ -3944 ¦ press page-up +3944 ¦ press page-up 3945 ] 3946 run [ 3947 ¦ editor-event-loop screen, console, e @@ -4011,371 +4011,371 @@ if ('onhashchange' in window) { 3949 # screen resets 3950 screen-should-contain [ 3951 ¦ . . -3952 ¦ .a . -3953 ¦ .bcd↩ . -3954 ¦ .efg↩ . -3955 ] -3956 ] -3957 -3958 scenario editor-can-scroll-up-past-nonempty-lines [ -3959 local-scope -3960 assume-screen 10/width, 4/height -3961 # text with empty line in second screen -3962 s:text <- new [axx -3963 bxx -3964 cxx -3965 dxx -3966 exx -3967 fxx -3968 gxx -3969 hxx -3970 ] -3971 e:&:editor <- new-editor s, 0/left, 4/right -3972 editor-render screen, e -3973 screen-should-contain [ -3974 ¦ . . -3975 ¦ .axx . -3976 ¦ .bxx . -3977 ¦ .cxx . -3978 ] -3979 assume-console [ -3980 ¦ press page-down -3981 ] -3982 run [ -3983 ¦ editor-event-loop screen, console, e -3984 ] +3952 ¦ .b . +3953 ¦ .cde↩ . +3954 ¦ .fgh . +3955 ¦ .i . +3956 ¦ .j . +3957 ] +3958 ] +3959 +3960 scenario editor-can-scroll-up-wrapped-lines-2 [ +3961 local-scope +3962 # screen has 1 line for menu + 3 lines for text +3963 assume-screen 10/width, 4/height +3964 # editor contains a very long line that occupies last two lines of screen +3965 # and still has something left over +3966 s:text <- new [a +3967 bcdefgh] +3968 e:&:editor <- new-editor s, 0/left, 4/right +3969 editor-render screen, e +3970 # some part of last line is not displayed +3971 screen-should-contain [ +3972 ¦ . . +3973 ¦ .a . +3974 ¦ .bcd↩ . +3975 ¦ .efg↩ . +3976 ] +3977 # scroll down +3978 assume-console [ +3979 ¦ press page-down +3980 ] +3981 run [ +3982 ¦ editor-event-loop screen, console, e +3983 ] +3984 # screen shows entire wrapped line 3985 screen-should-contain [ 3986 ¦ . . -3987 ¦ .cxx . -3988 ¦ .dxx . -3989 ¦ .exx . +3987 ¦ .bcd↩ . +3988 ¦ .efg↩ . +3989 ¦ .h . 3990 ] -3991 assume-console [ -3992 ¦ press page-down -3993 ] -3994 run [ -3995 ¦ editor-event-loop screen, console, e -3996 ] -3997 screen-should-contain [ -3998 ¦ . . -3999 ¦ .exx . -4000 ¦ .fxx . -4001 ¦ .gxx . -4002 ] -4003 # scroll back up past empty line -4004 assume-console [ -4005 ¦ press page-up -4006 ] -4007 run [ -4008 ¦ editor-event-loop screen, console, e -4009 ] -4010 screen-should-contain [ -4011 ¦ . . -4012 ¦ .cxx . -4013 ¦ .dxx . -4014 ¦ .exx . -4015 ] -4016 ] -4017 -4018 scenario editor-can-scroll-up-past-empty-lines [ -4019 local-scope -4020 assume-screen 10/width, 4/height -4021 # text with empty line in second screen -4022 s:text <- new [axy -4023 bxy -4024 cxy -4025 -4026 dxy -4027 exy -4028 fxy -4029 gxy -4030 ] -4031 e:&:editor <- new-editor s, 0/left, 4/right -4032 editor-render screen, e -4033 screen-should-contain [ -4034 ¦ . . -4035 ¦ .axy . -4036 ¦ .bxy . -4037 ¦ .cxy . -4038 ] -4039 assume-console [ -4040 ¦ press page-down -4041 ] -4042 run [ -4043 ¦ editor-event-loop screen, console, e -4044 ] -4045 screen-should-contain [ -4046 ¦ . . -4047 ¦ .cxy . -4048 ¦ . . -4049 ¦ .dxy . -4050 ] -4051 assume-console [ -4052 ¦ press page-down -4053 ] -4054 run [ -4055 ¦ editor-event-loop screen, console, e -4056 ] -4057 screen-should-contain [ -4058 ¦ . . -4059 ¦ .dxy . -4060 ¦ .exy . -4061 ¦ .fxy . -4062 ] -4063 # scroll back up past empty line -4064 assume-console [ -4065 ¦ press page-up -4066 ] -4067 run [ -4068 ¦ editor-event-loop screen, console, e -4069 ] -4070 screen-should-contain [ -4071 ¦ . . -4072 ¦ .cxy . -4073 ¦ . . -4074 ¦ .dxy . -4075 ] -4076 ] -4077 -4078 # ctrl-s - scroll up by one line -4079 # todo: scenarios -4080 -4081 after <handle-special-character> [ -4082 { -4083 ¦ scroll-up?:bool <- equal c, 19/ctrl-s -4084 ¦ break-unless scroll-up? -4085 ¦ <move-cursor-begin> -4086 ¦ go-render?:bool, editor <- line-up editor, screen-height -4087 ¦ undo-coalesce-tag:num <- copy 5/line-up -4088 ¦ <move-cursor-end> -4089 ¦ return go-render? -4090 } -4091 ] -4092 -4093 def line-up editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ -4094 local-scope -4095 load-ingredients -4096 left:num <- get *editor, left:offset -4097 right:num <- get *editor, right:offset -4098 max:num <- subtract right, left -4099 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -4100 new-top:&:duplex-list:char <- before-start-of-next-line old-top, max -4101 movement?:bool <- not-equal old-top, new-top -4102 { -4103 ¦ break-unless movement? -4104 ¦ *editor <- put *editor, top-of-screen:offset, new-top -4105 } -4106 return movement? -4107 ] -4108 -4109 # ctrl-x - scroll down by one line -4110 # todo: scenarios -4111 -4112 after <handle-special-character> [ -4113 { -4114 ¦ scroll-down?:bool <- equal c, 24/ctrl-x -4115 ¦ break-unless scroll-down? -4116 ¦ <move-cursor-begin> -4117 ¦ go-render?:bool, editor <- line-down editor, screen-height -4118 ¦ undo-coalesce-tag:num <- copy 6/line-down -4119 ¦ <move-cursor-end> -4120 ¦ return go-render? -4121 } -4122 ] -4123 -4124 def line-down editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ -4125 local-scope -4126 load-ingredients -4127 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -4128 new-top:&:duplex-list:char <- before-previous-screen-line old-top, editor -4129 movement?:bool <- not-equal old-top, new-top -4130 { -4131 ¦ break-unless movement? -4132 ¦ *editor <- put *editor, top-of-screen:offset, new-top -4133 } -4134 return movement? -4135 ] -4136 -4137 # ctrl-t - move current line to top of screen -4138 # todo: scenarios -4139 -4140 after <handle-special-character> [ -4141 { -4142 ¦ scroll-down?:bool <- equal c, 20/ctrl-t -4143 ¦ break-unless scroll-down? -4144 ¦ <move-cursor-begin> -4145 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset -4146 ¦ cursor:&:duplex-list:char <- get *editor, before-cursor:offset -4147 ¦ cursor <- next cursor -4148 ¦ new-top:&:duplex-list:char <- before-previous-screen-line cursor, editor -4149 ¦ *editor <- put *editor, top-of-screen:offset, new-top -4150 ¦ *editor <- put *editor, cursor-row:offset, 1 -4151 ¦ go-render?:bool <- not-equal new-top, old-top -4152 ¦ undo-coalesce-tag:num <- copy 0/never -4153 ¦ <move-cursor-end> -4154 ¦ return go-render? -4155 } +3991 # scroll back up +3992 assume-console [ +3993 ¦ press page-up +3994 ] +3995 run [ +3996 ¦ editor-event-loop screen, console, e +3997 ] +3998 # screen resets +3999 screen-should-contain [ +4000 ¦ . . +4001 ¦ .a . +4002 ¦ .bcd↩ . +4003 ¦ .efg↩ . +4004 ] +4005 ] +4006 +4007 scenario editor-can-scroll-up-past-nonempty-lines [ +4008 local-scope +4009 assume-screen 10/width, 4/height +4010 # text with empty line in second screen +4011 s:text <- new [axx +4012 bxx +4013 cxx +4014 dxx +4015 exx +4016 fxx +4017 gxx +4018 hxx +4019 ] +4020 e:&:editor <- new-editor s, 0/left, 4/right +4021 editor-render screen, e +4022 screen-should-contain [ +4023 ¦ . . +4024 ¦ .axx . +4025 ¦ .bxx . +4026 ¦ .cxx . +4027 ] +4028 assume-console [ +4029 ¦ press page-down +4030 ] +4031 run [ +4032 ¦ editor-event-loop screen, console, e +4033 ] +4034 screen-should-contain [ +4035 ¦ . . +4036 ¦ .cxx . +4037 ¦ .dxx . +4038 ¦ .exx . +4039 ] +4040 assume-console [ +4041 ¦ press page-down +4042 ] +4043 run [ +4044 ¦ editor-event-loop screen, console, e +4045 ] +4046 screen-should-contain [ +4047 ¦ . . +4048 ¦ .exx . +4049 ¦ .fxx . +4050 ¦ .gxx . +4051 ] +4052 # scroll back up past empty line +4053 assume-console [ +4054 ¦ press page-up +4055 ] +4056 run [ +4057 ¦ editor-event-loop screen, console, e +4058 ] +4059 screen-should-contain [ +4060 ¦ . . +4061 ¦ .cxx . +4062 ¦ .dxx . +4063 ¦ .exx . +4064 ] +4065 ] +4066 +4067 scenario editor-can-scroll-up-past-empty-lines [ +4068 local-scope +4069 assume-screen 10/width, 4/height +4070 # text with empty line in second screen +4071 s:text <- new [axy +4072 bxy +4073 cxy +4074 +4075 dxy +4076 exy +4077 fxy +4078 gxy +4079 ] +4080 e:&:editor <- new-editor s, 0/left, 4/right +4081 editor-render screen, e +4082 screen-should-contain [ +4083 ¦ . . +4084 ¦ .axy . +4085 ¦ .bxy . +4086 ¦ .cxy . +4087 ] +4088 assume-console [ +4089 ¦ press page-down +4090 ] +4091 run [ +4092 ¦ editor-event-loop screen, console, e +4093 ] +4094 screen-should-contain [ +4095 ¦ . . +4096 ¦ .cxy . +4097 ¦ . . +4098 ¦ .dxy . +4099 ] +4100 assume-console [ +4101 ¦ press page-down +4102 ] +4103 run [ +4104 ¦ editor-event-loop screen, console, e +4105 ] +4106 screen-should-contain [ +4107 ¦ . . +4108 ¦ .dxy . +4109 ¦ .exy . +4110 ¦ .fxy . +4111 ] +4112 # scroll back up past empty line +4113 assume-console [ +4114 ¦ press page-up +4115 ] +4116 run [ +4117 ¦ editor-event-loop screen, console, e +4118 ] +4119 screen-should-contain [ +4120 ¦ . . +4121 ¦ .cxy . +4122 ¦ . . +4123 ¦ .dxy . +4124 ] +4125 ] +4126 +4127 # ctrl-s - scroll up by one line +4128 # todo: scenarios +4129 +4130 after <handle-special-character> [ +4131 { +4132 ¦ scroll-up?:bool <- equal c, 19/ctrl-s +4133 ¦ break-unless scroll-up? +4134 ¦ <move-cursor-begin> +4135 ¦ go-render?:bool, editor <- line-up editor, screen-height +4136 ¦ undo-coalesce-tag:num <- copy 5/line-up +4137 ¦ <move-cursor-end> +4138 ¦ return go-render? +4139 } +4140 ] +4141 +4142 def line-up editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ +4143 local-scope +4144 load-ingredients +4145 left:num <- get *editor, left:offset +4146 right:num <- get *editor, right:offset +4147 max:num <- subtract right, left +4148 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +4149 new-top:&:duplex-list:char <- before-start-of-next-line old-top, max +4150 movement?:bool <- not-equal old-top, new-top +4151 { +4152 ¦ break-unless movement? +4153 ¦ *editor <- put *editor, top-of-screen:offset, new-top +4154 } +4155 return movement? 4156 ] 4157 -4158 # ctrl-/ - comment/uncomment current line -4159 -4160 after <handle-special-character> [ -4161 { -4162 ¦ comment-toggle?:bool <- equal c, 31/ctrl-slash -4163 ¦ break-unless comment-toggle? -4164 ¦ cursor-column:num <- get *editor, cursor-column:offset -4165 ¦ data:&:duplex-list:char <- get *editor, data:offset -4166 ¦ <insert-character-begin> -4167 ¦ before-line-start:&:duplex-list:char <- before-start-of-screen-line editor -4168 ¦ line-start:&:duplex-list:char <- next before-line-start -4169 ¦ commented-out?:bool <- match line-start, [#? ] # comment prefix -4170 ¦ { -4171 ¦ ¦ break-unless commented-out? -4172 ¦ ¦ # uncomment -4173 ¦ ¦ data <- remove line-start, 3/length-comment-prefix, data -4174 ¦ ¦ cursor-column <- subtract cursor-column, 3/length-comment-prefix -4175 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column -4176 ¦ ¦ go-render? <- render-line-from-start screen, editor, 3/size-of-comment-leader -4177 ¦ } -4178 ¦ { -4179 ¦ ¦ break-if commented-out? -4180 ¦ ¦ # comment -4181 ¦ ¦ insert before-line-start, [#? ] -4182 ¦ ¦ cursor-column <- add cursor-column, 3/length-comment-prefix -4183 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column -4184 ¦ ¦ go-render? <- render-line-from-start screen, editor, 0 -4185 ¦ } -4186 ¦ <insert-character-end> -4187 ¦ return -4188 } -4189 ] -4190 -4191 # Render just from the start of the current line, and only if it wasn't -4192 # wrapping before (include margin) and isn't wrapping now. Otherwise just tell -4193 # the caller to go-render? the entire screen. -4194 def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num -> go-render?:bool, screen:&:screen [ -4195 local-scope -4196 load-ingredients -4197 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor -4198 line-start:&:duplex-list:char <- next before-line-start -4199 color:num <- copy 7/white -4200 left:num <- get *editor, left:offset -4201 cursor-row:num <- get *editor, cursor-row:offset -4202 screen <- move-cursor screen, cursor-row, left -4203 right:num <- get *editor, right:offset -4204 end:num <- subtract right, right-margin -4205 i:num <- copy 0 -4206 curr:&:duplex-list:char <- copy line-start -4207 { -4208 ¦ render-all?:bool <- greater-or-equal i, end -4209 ¦ return-if render-all?, 1/go-render -4210 ¦ break-unless curr -4211 ¦ c:char <- get *curr, value:offset -4212 ¦ newline?:bool <- equal c, 10/newline -4213 ¦ break-if newline? -4214 ¦ color <- get-color color, c -4215 ¦ print screen, c, color -4216 ¦ curr <- next curr -4217 ¦ i <- add i, 1 -4218 ¦ loop -4219 } -4220 clear-line-until screen, right -4221 return 0/dont-render -4222 ] -4223 -4224 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [ -4225 local-scope -4226 load-ingredients -4227 cursor:&:duplex-list:char <- get *editor, before-cursor:offset -4228 { -4229 ¦ next:&:duplex-list:char <- next cursor -4230 ¦ break-unless next -4231 ¦ cursor <- copy next -4232 } -4233 result <- before-previous-screen-line cursor, editor -4234 ] -4235 -4236 scenario editor-comments-empty-line [ -4237 local-scope -4238 assume-screen 10/width, 5/height -4239 e:&:editor <- new-editor [], 0/left, 5/right -4240 editor-render screen, e -4241 $clear-trace -4242 assume-console [ -4243 ¦ press ctrl-slash -4244 ] -4245 run [ -4246 ¦ editor-event-loop screen, console, e -4247 ¦ 4:num/raw <- get *e, cursor-row:offset -4248 ¦ 5:num/raw <- get *e, cursor-column:offset -4249 ] -4250 screen-should-contain [ -4251 ¦ . . -4252 ¦ .#? . -4253 ¦ .╌╌╌╌╌ . -4254 ¦ . . -4255 ] -4256 memory-should-contain [ -4257 ¦ 4 <- 1 -4258 ¦ 5 <- 3 -4259 ] -4260 check-trace-count-for-label 5, [print-character] -4261 ] -4262 -4263 scenario editor-comments-at-start-of-contents [ -4264 local-scope -4265 assume-screen 10/width, 5/height -4266 e:&:editor <- new-editor [ab], 0/left, 10/right -4267 editor-render screen, e -4268 $clear-trace -4269 assume-console [ -4270 ¦ press ctrl-slash -4271 ] -4272 run [ -4273 ¦ editor-event-loop screen, console, e -4274 ¦ 4:num/raw <- get *e, cursor-row:offset -4275 ¦ 5:num/raw <- get *e, cursor-column:offset -4276 ] -4277 screen-should-contain [ -4278 ¦ . . -4279 ¦ .#? ab . -4280 ¦ .╌╌╌╌╌╌╌╌╌╌. -4281 ¦ . . -4282 ] -4283 memory-should-contain [ -4284 ¦ 4 <- 1 -4285 ¦ 5 <- 3 -4286 ] -4287 check-trace-count-for-label 10, [print-character] -4288 ] -4289 -4290 scenario editor-comments-at-end-of-contents [ -4291 local-scope -4292 assume-screen 10/width, 5/height -4293 e:&:editor <- new-editor [ab], 0/left, 10/right -4294 editor-render screen, e -4295 $clear-trace -4296 assume-console [ -4297 ¦ left-click 1, 7 -4298 ¦ press ctrl-slash -4299 ] -4300 run [ -4301 ¦ editor-event-loop screen, console, e -4302 ¦ 4:num/raw <- get *e, cursor-row:offset -4303 ¦ 5:num/raw <- get *e, cursor-column:offset +4158 # ctrl-x - scroll down by one line +4159 # todo: scenarios +4160 +4161 after <handle-special-character> [ +4162 { +4163 ¦ scroll-down?:bool <- equal c, 24/ctrl-x +4164 ¦ break-unless scroll-down? +4165 ¦ <move-cursor-begin> +4166 ¦ go-render?:bool, editor <- line-down editor, screen-height +4167 ¦ undo-coalesce-tag:num <- copy 6/line-down +4168 ¦ <move-cursor-end> +4169 ¦ return go-render? +4170 } +4171 ] +4172 +4173 def line-down editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [ +4174 local-scope +4175 load-ingredients +4176 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +4177 new-top:&:duplex-list:char <- before-previous-screen-line old-top, editor +4178 movement?:bool <- not-equal old-top, new-top +4179 { +4180 ¦ break-unless movement? +4181 ¦ *editor <- put *editor, top-of-screen:offset, new-top +4182 } +4183 return movement? +4184 ] +4185 +4186 # ctrl-t - move current line to top of screen +4187 # todo: scenarios +4188 +4189 after <handle-special-character> [ +4190 { +4191 ¦ scroll-down?:bool <- equal c, 20/ctrl-t +4192 ¦ break-unless scroll-down? +4193 ¦ <move-cursor-begin> +4194 ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset +4195 ¦ cursor:&:duplex-list:char <- get *editor, before-cursor:offset +4196 ¦ cursor <- next cursor +4197 ¦ new-top:&:duplex-list:char <- before-previous-screen-line cursor, editor +4198 ¦ *editor <- put *editor, top-of-screen:offset, new-top +4199 ¦ *editor <- put *editor, cursor-row:offset, 1 +4200 ¦ go-render?:bool <- not-equal new-top, old-top +4201 ¦ undo-coalesce-tag:num <- copy 0/never +4202 ¦ <move-cursor-end> +4203 ¦ return go-render? +4204 } +4205 ] +4206 +4207 # ctrl-/ - comment/uncomment current line +4208 +4209 after <handle-special-character> [ +4210 { +4211 ¦ comment-toggle?:bool <- equal c, 31/ctrl-slash +4212 ¦ break-unless comment-toggle? +4213 ¦ cursor-column:num <- get *editor, cursor-column:offset +4214 ¦ data:&:duplex-list:char <- get *editor, data:offset +4215 ¦ <insert-character-begin> +4216 ¦ before-line-start:&:duplex-list:char <- before-start-of-screen-line editor +4217 ¦ line-start:&:duplex-list:char <- next before-line-start +4218 ¦ commented-out?:bool <- match line-start, [#? ] # comment prefix +4219 ¦ { +4220 ¦ ¦ break-unless commented-out? +4221 ¦ ¦ # uncomment +4222 ¦ ¦ data <- remove line-start, 3/length-comment-prefix, data +4223 ¦ ¦ cursor-column <- subtract cursor-column, 3/length-comment-prefix +4224 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column +4225 ¦ ¦ go-render? <- render-line-from-start screen, editor, 3/size-of-comment-leader +4226 ¦ } +4227 ¦ { +4228 ¦ ¦ break-if commented-out? +4229 ¦ ¦ # comment +4230 ¦ ¦ insert before-line-start, [#? ] +4231 ¦ ¦ cursor-column <- add cursor-column, 3/length-comment-prefix +4232 ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column +4233 ¦ ¦ go-render? <- render-line-from-start screen, editor, 0 +4234 ¦ } +4235 ¦ <insert-character-end> +4236 ¦ return +4237 } +4238 ] +4239 +4240 # Render just from the start of the current line, and only if it wasn't +4241 # wrapping before (include margin) and isn't wrapping now. Otherwise just tell +4242 # the caller to go-render? the entire screen. +4243 def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num -> go-render?:bool, screen:&:screen [ +4244 local-scope +4245 load-ingredients +4246 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor +4247 line-start:&:duplex-list:char <- next before-line-start +4248 color:num <- copy 7/white +4249 left:num <- get *editor, left:offset +4250 cursor-row:num <- get *editor, cursor-row:offset +4251 screen <- move-cursor screen, cursor-row, left +4252 right:num <- get *editor, right:offset +4253 end:num <- subtract right, right-margin +4254 i:num <- copy 0 +4255 curr:&:duplex-list:char <- copy line-start +4256 { +4257 ¦ render-all?:bool <- greater-or-equal i, end +4258 ¦ return-if render-all?, 1/go-render +4259 ¦ break-unless curr +4260 ¦ c:char <- get *curr, value:offset +4261 ¦ newline?:bool <- equal c, 10/newline +4262 ¦ break-if newline? +4263 ¦ color <- get-color color, c +4264 ¦ print screen, c, color +4265 ¦ curr <- next curr +4266 ¦ i <- add i, 1 +4267 ¦ loop +4268 } +4269 clear-line-until screen, right +4270 return 0/dont-render +4271 ] +4272 +4273 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [ +4274 local-scope +4275 load-ingredients +4276 cursor:&:duplex-list:char <- get *editor, before-cursor:offset +4277 { +4278 ¦ next:&:duplex-list:char <- next cursor +4279 ¦ break-unless next +4280 ¦ cursor <- copy next +4281 } +4282 result <- before-previous-screen-line cursor, editor +4283 ] +4284 +4285 scenario editor-comments-empty-line [ +4286 local-scope +4287 assume-screen 10/width, 5/height +4288 e:&:editor <- new-editor [], 0/left, 5/right +4289 editor-render screen, e +4290 $clear-trace +4291 assume-console [ +4292 ¦ press ctrl-slash +4293 ] +4294 run [ +4295 ¦ editor-event-loop screen, console, e +4296 ¦ 4:num/raw <- get *e, cursor-row:offset +4297 ¦ 5:num/raw <- get *e, cursor-column:offset +4298 ] +4299 screen-should-contain [ +4300 ¦ . . +4301 ¦ .#? . +4302 ¦ .╌╌╌╌╌ . +4303 ¦ . . 4304 ] -4305 screen-should-contain [ -4306 ¦ . . -4307 ¦ .#? ab . -4308 ¦ .╌╌╌╌╌╌╌╌╌╌. -4309 ¦ . . -4310 ] -4311 memory-should-contain [ -4312 ¦ 4 <- 1 -4313 ¦ 5 <- 5 -4314 ] -4315 check-trace-count-for-label 10, [print-character] -4316 # toggle to uncomment +4305 memory-should-contain [ +4306 ¦ 4 <- 1 +4307 ¦ 5 <- 3 +4308 ] +4309 check-trace-count-for-label 5, [print-character] +4310 ] +4311 +4312 scenario editor-comments-at-start-of-contents [ +4313 local-scope +4314 assume-screen 10/width, 5/height +4315 e:&:editor <- new-editor [ab], 0/left, 10/right +4316 editor-render screen, e 4317 $clear-trace 4318 assume-console [ 4319 ¦ press ctrl-slash @@ -4387,72 +4387,121 @@ if ('onhashchange' in window) { 4325 ] 4326 screen-should-contain [ 4327 ¦ . . -4328 ¦ .ab . +4328 ¦ .#? ab . 4329 ¦ .╌╌╌╌╌╌╌╌╌╌. 4330 ¦ . . 4331 ] -4332 check-trace-count-for-label 10, [print-character] -4333 ] -4334 -4335 scenario editor-comments-almost-wrapping-line [ -4336 local-scope -4337 assume-screen 10/width, 5/height -4338 # editor starts out with a non-wrapping line -4339 e:&:editor <- new-editor [abcd], 0/left, 5/right -4340 editor-render screen, e -4341 screen-should-contain [ -4342 ¦ . . -4343 ¦ .abcd . -4344 ¦ .╌╌╌╌╌ . -4345 ¦ . . -4346 ] -4347 $clear-trace -4348 # on commenting the line is now wrapped -4349 assume-console [ -4350 ¦ left-click 1, 7 -4351 ¦ press ctrl-slash -4352 ] -4353 run [ -4354 ¦ editor-event-loop screen, console, e -4355 ] -4356 screen-should-contain [ -4357 ¦ . . -4358 ¦ .#? a↩ . -4359 ¦ .bcd . -4360 ¦ .╌╌╌╌╌ . -4361 ¦ . . -4362 ] -4363 ] -4364 -4365 scenario editor-uncomments-just-wrapping-line [ -4366 local-scope -4367 assume-screen 10/width, 5/height -4368 # editor starts out with a comment that wraps the line -4369 e:&:editor <- new-editor [#? ab], 0/left, 5/right -4370 editor-render screen, e -4371 screen-should-contain [ -4372 ¦ . . -4373 ¦ .#? a↩ . -4374 ¦ .b . -4375 ¦ .╌╌╌╌╌ . +4332 memory-should-contain [ +4333 ¦ 4 <- 1 +4334 ¦ 5 <- 3 +4335 ] +4336 check-trace-count-for-label 10, [print-character] +4337 ] +4338 +4339 scenario editor-comments-at-end-of-contents [ +4340 local-scope +4341 assume-screen 10/width, 5/height +4342 e:&:editor <- new-editor [ab], 0/left, 10/right +4343 editor-render screen, e +4344 $clear-trace +4345 assume-console [ +4346 ¦ left-click 1, 7 +4347 ¦ press ctrl-slash +4348 ] +4349 run [ +4350 ¦ editor-event-loop screen, console, e +4351 ¦ 4:num/raw <- get *e, cursor-row:offset +4352 ¦ 5:num/raw <- get *e, cursor-column:offset +4353 ] +4354 screen-should-contain [ +4355 ¦ . . +4356 ¦ .#? ab . +4357 ¦ .╌╌╌╌╌╌╌╌╌╌. +4358 ¦ . . +4359 ] +4360 memory-should-contain [ +4361 ¦ 4 <- 1 +4362 ¦ 5 <- 5 +4363 ] +4364 check-trace-count-for-label 10, [print-character] +4365 # toggle to uncomment +4366 $clear-trace +4367 assume-console [ +4368 ¦ press ctrl-slash +4369 ] +4370 run [ +4371 ¦ editor-event-loop screen, console, e +4372 ¦ 4:num/raw <- get *e, cursor-row:offset +4373 ¦ 5:num/raw <- get *e, cursor-column:offset +4374 ] +4375 screen-should-contain [ 4376 ¦ . . -4377 ] -4378 $clear-trace -4379 # on uncommenting the line is no longer wrapped -4380 assume-console [ -4381 ¦ left-click 1, 7 -4382 ¦ press ctrl-slash -4383 ] -4384 run [ -4385 ¦ editor-event-loop screen, console, e -4386 ] -4387 screen-should-contain [ -4388 ¦ . . -4389 ¦ .ab . -4390 ¦ .╌╌╌╌╌ . +4377 ¦ .ab . +4378 ¦ .╌╌╌╌╌╌╌╌╌╌. +4379 ¦ . . +4380 ] +4381 check-trace-count-for-label 10, [print-character] +4382 ] +4383 +4384 scenario editor-comments-almost-wrapping-line [ +4385 local-scope +4386 assume-screen 10/width, 5/height +4387 # editor starts out with a non-wrapping line +4388 e:&:editor <- new-editor [abcd], 0/left, 5/right +4389 editor-render screen, e +4390 screen-should-contain [ 4391 ¦ . . -4392 ] -4393 ] +4392 ¦ .abcd . +4393 ¦ .╌╌╌╌╌ . +4394 ¦ . . +4395 ] +4396 $clear-trace +4397 # on commenting the line is now wrapped +4398 assume-console [ +4399 ¦ left-click 1, 7 +4400 ¦ press ctrl-slash +4401 ] +4402 run [ +4403 ¦ editor-event-loop screen, console, e +4404 ] +4405 screen-should-contain [ +4406 ¦ . . +4407 ¦ .#? a↩ . +4408 ¦ .bcd . +4409 ¦ .╌╌╌╌╌ . +4410 ¦ . . +4411 ] +4412 ] +4413 +4414 scenario editor-uncomments-just-wrapping-line [ +4415 local-scope +4416 assume-screen 10/width, 5/height +4417 # editor starts out with a comment that wraps the line +4418 e:&:editor <- new-editor [#? ab], 0/left, 5/right +4419 editor-render screen, e +4420 screen-should-contain [ +4421 ¦ . . +4422 ¦ .#? a↩ . +4423 ¦ .b . +4424 ¦ .╌╌╌╌╌ . +4425 ¦ . . +4426 ] +4427 $clear-trace +4428 # on uncommenting the line is no longer wrapped +4429 assume-console [ +4430 ¦ left-click 1, 7 +4431 ¦ press ctrl-slash +4432 ] +4433 run [ +4434 ¦ editor-event-loop screen, console, e +4435 ] +4436 screen-should-contain [ +4437 ¦ . . +4438 ¦ .ab . +4439 ¦ .╌╌╌╌╌ . +4440 ¦ . . +4441 ] +4442 ] diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html index 00672e46..3adf365a 100644 --- a/html/edit/005-sandbox.mu.html +++ b/html/edit/005-sandbox.mu.html @@ -353,7 +353,7 @@ if ('onhashchange' in window) { 290 ¦ row <- add row, 1 291 ¦ screen <- move-cursor screen, row, left 292 ¦ sandbox-data:text <- get *sandbox, data:offset - 293 ¦ row, screen <- render-code screen, sandbox-data, left, right, row + 293 ¦ row, screen <- render-code screen, sandbox-data, left, right, row 294 ¦ *sandbox <- put *sandbox, code-ending-row-on-screen:offset, row 295 ¦ # render sandbox warnings, screen or response, in that order 296 ¦ sandbox-response:text <- get *sandbox, response:offset @@ -817,521 +817,431 @@ if ('onhashchange' in window) { 754 ] 755 ] 756 - 757 # we'll not use the recipe-editor's 'bottom' element directly, because later - 758 # layers will add other stuff to the left side below the editor (error messages) - 759 - 760 container environment [ - 761 recipe-bottom:num - 762 ] - 763 - 764 after <render-recipe-components-end> [ - 765 *env <- put *env, recipe-bottom:offset, row - 766 ] - 767 - 768 after <global-keypress> [ - 769 { - 770 ¦ break-if sandbox-in-focus? - 771 ¦ down-arrow?:bool <- equal k, 65516/down-arrow - 772 ¦ break-unless down-arrow? - 773 ¦ recipe-editor:&:editor <- get *env, recipes:offset - 774 ¦ recipe-cursor-row:num <- get *recipe-editor, cursor-row:offset - 775 ¦ recipe-editor-bottom:num <- get *recipe-editor, bottom:offset - 776 ¦ at-bottom-of-editor?:bool <- greater-or-equal recipe-cursor-row, recipe-editor-bottom - 777 ¦ break-unless at-bottom-of-editor? - 778 ¦ more-to-scroll?:bool <- more-to-scroll? env, screen - 779 ¦ break-if more-to-scroll? - 780 ¦ loop +next-event - 781 } - 782 { - 783 ¦ break-if sandbox-in-focus? - 784 ¦ page-down?:bool <- equal k, 65518/page-down - 785 ¦ break-unless page-down? - 786 ¦ more-to-scroll?:bool <- more-to-scroll? env, screen - 787 ¦ break-if more-to-scroll? - 788 ¦ loop +next-event - 789 } - 790 ] - 791 - 792 after <global-type> [ - 793 { - 794 ¦ break-if sandbox-in-focus? - 795 ¦ page-down?:bool <- equal k, 6/ctrl-f - 796 ¦ break-unless page-down? - 797 ¦ more-to-scroll?:bool <- more-to-scroll? env, screen - 798 ¦ break-if more-to-scroll? - 799 ¦ loop +next-event - 800 } - 801 ] - 802 - 803 def more-to-scroll? env:&:environment, screen:&:screen -> result:bool [ - 804 local-scope - 805 load-ingredients - 806 recipe-bottom:num <- get *env, recipe-bottom:offset - 807 height:num <- screen-height screen - 808 result <- greater-or-equal recipe-bottom, height - 809 ] - 810 - 811 scenario scrolling-down-past-bottom-of-recipe-editor-2 [ - 812 local-scope - 813 trace-until 100/app - 814 assume-screen 100/width, 10/height - 815 assume-resources [ - 816 ] - 817 env:&:environment <- new-programming-environment resources, screen, [] - 818 render-all screen, env, render - 819 assume-console [ - 820 ¦ # add a line - 821 ¦ press enter - 822 ¦ # cursor back to top line - 823 ¦ press up-arrow - 824 ¦ # try to scroll - 825 ¦ press page-down # or ctrl-f - 826 ] - 827 event-loop screen, console, env, resources - 828 # no scroll, and cursor remains at top line - 829 screen-should-contain [ - 830 ¦ . run (F4) . - 831 ¦ . ╎ . - 832 ¦ . ╎─────────────────────────────────────────────────. - 833 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . - 834 ¦ . ╎ . - 835 ] - 836 ] - 837 - 838 scenario scrolling-down-past-bottom-of-recipe-editor-3 [ - 839 local-scope - 840 trace-until 100/app - 841 assume-screen 100/width, 10/height - 842 assume-resources [ - 843 ] - 844 env:&:environment <- new-programming-environment resources, screen, [ab - 845 cd] - 846 render-all screen, env, render - 847 assume-console [ - 848 ¦ # add a line - 849 ¦ press enter - 850 ¦ # switch to sandbox - 851 ¦ press ctrl-n - 852 ¦ # move cursor - 853 ¦ press down-arrow - 854 ] - 855 event-loop screen, console, env, resources - 856 cursor:char <- copy 9251/␣ - 857 print screen, cursor - 858 # no scroll on recipe side, cursor moves on sandbox side - 859 screen-should-contain [ - 860 ¦ . run (F4) . - 861 ¦ . ╎ab . - 862 ¦ . ╎␣d . - 863 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. - 864 ¦ . ╎ . - 865 ] - 866 ] - 867 - 868 # scrolling through sandboxes - 869 - 870 scenario scrolling-down-past-bottom-of-sandbox-editor [ - 871 local-scope - 872 trace-until 100/app # trace too long - 873 assume-screen 100/width, 10/height - 874 # initialize - 875 assume-resources [ - 876 ] - 877 env:&:environment <- new-programming-environment resources, screen, [add 2, 2] - 878 render-all screen, env, render - 879 assume-console [ - 880 ¦ # create a sandbox - 881 ¦ press F4 - 882 ] - 883 event-loop screen, console, env, resources - 884 screen-should-contain [ - 885 ¦ . run (F4) . - 886 ¦ . ╎ . - 887 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. - 888 ¦ . ╎0 edit copy to recipe delete . - 889 ¦ . ╎add 2, 2 . - 890 ] - 891 # switch to sandbox window and hit 'page-down' - 892 assume-console [ - 893 ¦ press ctrl-n - 894 ¦ press page-down - 895 ] - 896 run [ - 897 ¦ event-loop screen, console, env, resources - 898 ¦ cursor:char <- copy 9251/␣ - 899 ¦ print screen, cursor - 900 ] - 901 # sandbox editor hidden; first sandbox displayed - 902 # cursor moves to first sandbox - 903 screen-should-contain [ - 904 ¦ . run (F4) . - 905 ¦ . ╎─────────────────────────────────────────────────. - 906 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete . - 907 ¦ . ╎add 2, 2 . - 908 ¦ . ╎4 . - 909 ] - 910 # hit 'page-up' - 911 assume-console [ - 912 ¦ press page-up - 913 ] - 914 run [ - 915 ¦ event-loop screen, console, env, resources - 916 ¦ cursor:char <- copy 9251/␣ - 917 ¦ print screen, cursor - 918 ] - 919 # sandbox editor displays again, cursor is in editor - 920 screen-should-contain [ - 921 ¦ . run (F4) . - 922 ¦ . ╎␣ . - 923 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. - 924 ¦ . ╎0 edit copy to recipe delete . - 925 ¦ . ╎add 2, 2 . - 926 ] + 757 scenario scrolling-down-past-bottom-of-recipe-editor-2 [ + 758 local-scope + 759 trace-until 100/app + 760 assume-screen 100/width, 10/height + 761 assume-resources [ + 762 ] + 763 env:&:environment <- new-programming-environment resources, screen, [] + 764 render-all screen, env, render + 765 assume-console [ + 766 ¦ # add a line + 767 ¦ press enter + 768 ¦ # cursor back to top line + 769 ¦ press up-arrow + 770 ¦ # try to scroll + 771 ¦ press page-down # or ctrl-f + 772 ] + 773 event-loop screen, console, env, resources + 774 # no scroll, and cursor remains at top line + 775 screen-should-contain [ + 776 ¦ . run (F4) . + 777 ¦ . ╎ . + 778 ¦ . ╎─────────────────────────────────────────────────. + 779 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . + 780 ¦ . ╎ . + 781 ] + 782 ] + 783 + 784 scenario scrolling-down-past-bottom-of-recipe-editor-3 [ + 785 local-scope + 786 trace-until 100/app + 787 assume-screen 100/width, 10/height + 788 assume-resources [ + 789 ] + 790 env:&:environment <- new-programming-environment resources, screen, [ab + 791 cd] + 792 render-all screen, env, render + 793 assume-console [ + 794 ¦ # add a line + 795 ¦ press enter + 796 ¦ # switch to sandbox + 797 ¦ press ctrl-n + 798 ¦ # move cursor + 799 ¦ press down-arrow + 800 ] + 801 event-loop screen, console, env, resources + 802 cursor:char <- copy 9251/␣ + 803 print screen, cursor + 804 # no scroll on recipe side, cursor moves on sandbox side + 805 screen-should-contain [ + 806 ¦ . run (F4) . + 807 ¦ . ╎ab . + 808 ¦ . ╎␣d . + 809 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. + 810 ¦ . ╎ . + 811 ] + 812 ] + 813 + 814 # scrolling through sandboxes + 815 + 816 scenario scrolling-down-past-bottom-of-sandbox-editor [ + 817 local-scope + 818 trace-until 100/app # trace too long + 819 assume-screen 100/width, 10/height + 820 # initialize + 821 assume-resources [ + 822 ] + 823 env:&:environment <- new-programming-environment resources, screen, [add 2, 2] + 824 render-all screen, env, render + 825 assume-console [ + 826 ¦ # create a sandbox + 827 ¦ press F4 + 828 ] + 829 event-loop screen, console, env, resources + 830 screen-should-contain [ + 831 ¦ . run (F4) . + 832 ¦ . ╎ . + 833 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. + 834 ¦ . ╎0 edit copy to recipe delete . + 835 ¦ . ╎add 2, 2 . + 836 ] + 837 # switch to sandbox window and hit 'page-down' + 838 assume-console [ + 839 ¦ press ctrl-n + 840 ¦ press page-down + 841 ] + 842 run [ + 843 ¦ event-loop screen, console, env, resources + 844 ¦ cursor:char <- copy 9251/␣ + 845 ¦ print screen, cursor + 846 ] + 847 # sandbox editor hidden; first sandbox displayed + 848 # cursor moves to first sandbox + 849 screen-should-contain [ + 850 ¦ . run (F4) . + 851 ¦ . ╎─────────────────────────────────────────────────. + 852 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete . + 853 ¦ . ╎add 2, 2 . + 854 ¦ . ╎4 . + 855 ] + 856 # hit 'page-up' + 857 assume-console [ + 858 ¦ press page-up + 859 ] + 860 run [ + 861 ¦ event-loop screen, console, env, resources + 862 ¦ cursor:char <- copy 9251/␣ + 863 ¦ print screen, cursor + 864 ] + 865 # sandbox editor displays again, cursor is in editor + 866 screen-should-contain [ + 867 ¦ . run (F4) . + 868 ¦ . ╎␣ . + 869 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. + 870 ¦ . ╎0 edit copy to recipe delete . + 871 ¦ . ╎add 2, 2 . + 872 ] + 873 ] + 874 + 875 # page-down on sandbox side updates render-from to scroll sandboxes + 876 after <global-keypress> [ + 877 { + 878 ¦ break-unless sandbox-in-focus? + 879 ¦ page-down?:bool <- equal k, 65518/page-down + 880 ¦ break-unless page-down? + 881 ¦ sandbox:&:sandbox <- get *env, sandbox:offset + 882 ¦ break-unless sandbox + 883 ¦ # slide down if possible + 884 ¦ { + 885 ¦ ¦ render-from:num <- get *env, render-from:offset + 886 ¦ ¦ number-of-sandboxes:num <- get *env, number-of-sandboxes:offset + 887 ¦ ¦ max:num <- subtract number-of-sandboxes, 1 + 888 ¦ ¦ at-end?:bool <- greater-or-equal render-from, max + 889 ¦ ¦ loop-if at-end?, +next-event # render nothing + 890 ¦ ¦ render-from <- add render-from, 1 + 891 ¦ ¦ *env <- put *env, render-from:offset, render-from + 892 ¦ } + 893 ¦ screen <- render-sandbox-side screen, env, render + 894 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 895 ¦ loop +next-event + 896 } + 897 ] + 898 + 899 # update-cursor takes render-from into account + 900 after <update-cursor-special-cases> [ + 901 { + 902 ¦ break-unless sandbox-in-focus? + 903 ¦ render-from:num <- get *env, render-from:offset + 904 ¦ scrolling?:bool <- greater-or-equal render-from, 0 + 905 ¦ break-unless scrolling? + 906 ¦ cursor-column:num <- get *current-sandbox, left:offset + 907 ¦ screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2 + 908 ¦ return + 909 } + 910 ] + 911 + 912 # 'page-up' on sandbox side is like 'page-down': updates render-from when necessary + 913 after <global-keypress> [ + 914 { + 915 ¦ break-unless sandbox-in-focus? + 916 ¦ page-up?:bool <- equal k, 65519/page-up + 917 ¦ break-unless page-up? + 918 ¦ render-from:num <- get *env, render-from:offset + 919 ¦ at-beginning?:bool <- equal render-from, -1 + 920 ¦ break-if at-beginning? + 921 ¦ render-from <- subtract render-from, 1 + 922 ¦ *env <- put *env, render-from:offset, render-from + 923 ¦ screen <- render-sandbox-side screen, env, render + 924 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 925 ¦ loop +next-event + 926 } 927 ] 928 - 929 # page-down on sandbox side updates render-from to scroll sandboxes - 930 after <global-keypress> [ - 931 { - 932 ¦ break-unless sandbox-in-focus? - 933 ¦ page-down?:bool <- equal k, 65518/page-down - 934 ¦ break-unless page-down? - 935 ¦ sandbox:&:sandbox <- get *env, sandbox:offset - 936 ¦ break-unless sandbox - 937 ¦ # slide down if possible - 938 ¦ { - 939 ¦ ¦ render-from:num <- get *env, render-from:offset - 940 ¦ ¦ number-of-sandboxes:num <- get *env, number-of-sandboxes:offset - 941 ¦ ¦ max:num <- subtract number-of-sandboxes, 1 - 942 ¦ ¦ at-end?:bool <- greater-or-equal render-from, max - 943 ¦ ¦ loop-if at-end?, +next-event # render nothing - 944 ¦ ¦ render-from <- add render-from, 1 - 945 ¦ ¦ *env <- put *env, render-from:offset, render-from - 946 ¦ } - 947 ¦ screen <- render-sandbox-side screen, env, render - 948 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env - 949 ¦ loop +next-event - 950 } - 951 ] - 952 - 953 # update-cursor takes render-from into account - 954 after <update-cursor-special-cases> [ - 955 { - 956 ¦ break-unless sandbox-in-focus? - 957 ¦ render-from:num <- get *env, render-from:offset - 958 ¦ scrolling?:bool <- greater-or-equal render-from, 0 - 959 ¦ break-unless scrolling? - 960 ¦ cursor-column:num <- get *current-sandbox, left:offset - 961 ¦ screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2 - 962 ¦ return - 963 } - 964 ] - 965 - 966 # 'page-up' on sandbox side is like 'page-down': updates render-from when necessary - 967 after <global-keypress> [ - 968 { - 969 ¦ break-unless sandbox-in-focus? - 970 ¦ page-up?:bool <- equal k, 65519/page-up - 971 ¦ break-unless page-up? - 972 ¦ render-from:num <- get *env, render-from:offset - 973 ¦ at-beginning?:bool <- equal render-from, -1 - 974 ¦ break-if at-beginning? - 975 ¦ render-from <- subtract render-from, 1 - 976 ¦ *env <- put *env, render-from:offset, render-from - 977 ¦ screen <- render-sandbox-side screen, env, render - 978 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env - 979 ¦ loop +next-event - 980 } - 981 ] - 982 - 983 # sandbox belonging to 'env' whose next-sandbox is 'in' - 984 # return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox - 985 def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [ - 986 local-scope - 987 load-ingredients - 988 curr:&:sandbox <- get *env, sandbox:offset - 989 return-unless curr, 0/nil - 990 next:&:sandbox <- get *curr, next-sandbox:offset - 991 { - 992 ¦ return-unless next, 0/nil - 993 ¦ found?:bool <- equal next, in - 994 ¦ break-if found? - 995 ¦ curr <- copy next - 996 ¦ next <- get *curr, next-sandbox:offset - 997 ¦ loop - 998 } - 999 return curr -1000 ] -1001 -1002 scenario scrolling-down-past-bottom-on-recipe-side [ -1003 local-scope -1004 trace-until 100/app # trace too long -1005 assume-screen 100/width, 10/height -1006 # initialize sandbox side and create a sandbox -1007 assume-resources [ -1008 ¦ [lesson/recipes.mu] <- [ -1009 ¦ ¦ || # file containing just a newline -1010 ¦ ] -1011 ] -1012 # create a sandbox -1013 env:&:environment <- new-programming-environment resources, screen, [add 2, 2] -1014 render-all screen, env, render -1015 assume-console [ -1016 ¦ press F4 -1017 ] -1018 event-loop screen, console, env, resources -1019 # hit 'down' in recipe editor + 929 # sandbox belonging to 'env' whose next-sandbox is 'in' + 930 # return 0 if there's no such sandbox, either because 'in' doesn't exist in 'env', or because it's the first sandbox + 931 def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [ + 932 local-scope + 933 load-ingredients + 934 curr:&:sandbox <- get *env, sandbox:offset + 935 return-unless curr, 0/nil + 936 next:&:sandbox <- get *curr, next-sandbox:offset + 937 { + 938 ¦ return-unless next, 0/nil + 939 ¦ found?:bool <- equal next, in + 940 ¦ break-if found? + 941 ¦ curr <- copy next + 942 ¦ next <- get *curr, next-sandbox:offset + 943 ¦ loop + 944 } + 945 return curr + 946 ] + 947 + 948 scenario scrolling-through-multiple-sandboxes [ + 949 local-scope + 950 trace-until 100/app # trace too long + 951 assume-screen 100/width, 10/height + 952 # initialize environment + 953 assume-resources [ + 954 ] + 955 env:&:environment <- new-programming-environment resources, screen, [] + 956 render-all screen, env, render + 957 # create 2 sandboxes + 958 assume-console [ + 959 ¦ press ctrl-n + 960 ¦ type [add 2, 2] + 961 ¦ press F4 + 962 ¦ type [add 1, 1] + 963 ¦ press F4 + 964 ] + 965 event-loop screen, console, env, resources + 966 cursor:char <- copy 9251/␣ + 967 print screen, cursor + 968 screen-should-contain [ + 969 ¦ . run (F4) . + 970 ¦ . ╎␣ . + 971 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. + 972 ¦ . ╎0 edit copy to recipe delete . + 973 ¦ . ╎add 1, 1 . + 974 ¦ . ╎2 . + 975 ¦ . ╎─────────────────────────────────────────────────. + 976 ¦ . ╎1 edit copy to recipe delete . + 977 ¦ . ╎add 2, 2 . + 978 ¦ . ╎4 . + 979 ] + 980 # hit 'page-down' + 981 assume-console [ + 982 ¦ press page-down + 983 ] + 984 run [ + 985 ¦ event-loop screen, console, env, resources + 986 ¦ cursor:char <- copy 9251/␣ + 987 ¦ print screen, cursor + 988 ] + 989 # sandbox editor hidden; first sandbox displayed + 990 # cursor moves to first sandbox + 991 screen-should-contain [ + 992 ¦ . run (F4) . + 993 ¦ . ╎─────────────────────────────────────────────────. + 994 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete . + 995 ¦ . ╎add 1, 1 . + 996 ¦ . ╎2 . + 997 ¦ . ╎─────────────────────────────────────────────────. + 998 ¦ . ╎1 edit copy to recipe delete . + 999 ¦ . ╎add 2, 2 . +1000 ¦ . ╎4 . +1001 ] +1002 # hit 'page-down' again +1003 assume-console [ +1004 ¦ press page-down +1005 ] +1006 run [ +1007 ¦ event-loop screen, console, env, resources +1008 ] +1009 # just second sandbox displayed +1010 screen-should-contain [ +1011 ¦ . run (F4) . +1012 ¦ . ╎─────────────────────────────────────────────────. +1013 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete . +1014 ¦ . ╎add 2, 2 . +1015 ¦ . ╎4 . +1016 ¦ . ╎─────────────────────────────────────────────────. +1017 ¦ . ╎ . +1018 ] +1019 # hit 'page-down' again 1020 assume-console [ -1021 ¦ press page-down +1021 ¦ press page-down 1022 ] 1023 run [ 1024 ¦ event-loop screen, console, env, resources -1025 ¦ cursor:char <- copy 9251/␣ -1026 ¦ print screen, cursor -1027 ] -1028 # cursor doesn't move when the end is already on-screen -1029 screen-should-contain [ -1030 ¦ . run (F4) . -1031 ¦ .␣ ╎ . -1032 ¦ . ╎─────────────────────────────────────────────────. -1033 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . -1034 ¦ . ╎add 2, 2 . +1025 ] +1026 # no change +1027 screen-should-contain [ +1028 ¦ . run (F4) . +1029 ¦ . ╎─────────────────────────────────────────────────. +1030 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete . +1031 ¦ . ╎add 2, 2 . +1032 ¦ . ╎4 . +1033 ¦ . ╎─────────────────────────────────────────────────. +1034 ¦ . ╎ . 1035 ] -1036 ] -1037 -1038 scenario scrolling-through-multiple-sandboxes [ -1039 local-scope -1040 trace-until 100/app # trace too long -1041 assume-screen 100/width, 10/height -1042 # initialize environment -1043 assume-resources [ -1044 ] -1045 env:&:environment <- new-programming-environment resources, screen, [] -1046 render-all screen, env, render -1047 # create 2 sandboxes -1048 assume-console [ -1049 ¦ press ctrl-n -1050 ¦ type [add 2, 2] -1051 ¦ press F4 -1052 ¦ type [add 1, 1] -1053 ¦ press F4 +1036 # hit 'page-up' +1037 assume-console [ +1038 ¦ press page-up +1039 ] +1040 run [ +1041 ¦ event-loop screen, console, env, resources +1042 ] +1043 # back to displaying both sandboxes without editor +1044 screen-should-contain [ +1045 ¦ . run (F4) . +1046 ¦ . ╎─────────────────────────────────────────────────. +1047 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . +1048 ¦ . ╎add 1, 1 . +1049 ¦ . ╎2 . +1050 ¦ . ╎─────────────────────────────────────────────────. +1051 ¦ . ╎1 edit copy to recipe delete . +1052 ¦ . ╎add 2, 2 . +1053 ¦ . ╎4 . 1054 ] -1055 event-loop screen, console, env, resources -1056 cursor:char <- copy 9251/␣ -1057 print screen, cursor -1058 screen-should-contain [ -1059 ¦ . run (F4) . -1060 ¦ . ╎␣ . -1061 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -1062 ¦ . ╎0 edit copy to recipe delete . -1063 ¦ . ╎add 1, 1 . -1064 ¦ . ╎2 . -1065 ¦ . ╎─────────────────────────────────────────────────. -1066 ¦ . ╎1 edit copy to recipe delete . -1067 ¦ . ╎add 2, 2 . -1068 ¦ . ╎4 . -1069 ] -1070 # hit 'page-down' -1071 assume-console [ -1072 ¦ press page-down -1073 ] -1074 run [ -1075 ¦ event-loop screen, console, env, resources -1076 ¦ cursor:char <- copy 9251/␣ -1077 ¦ print screen, cursor -1078 ] -1079 # sandbox editor hidden; first sandbox displayed -1080 # cursor moves to first sandbox -1081 screen-should-contain [ -1082 ¦ . run (F4) . -1083 ¦ . ╎─────────────────────────────────────────────────. -1084 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete . -1085 ¦ . ╎add 1, 1 . -1086 ¦ . ╎2 . -1087 ¦ . ╎─────────────────────────────────────────────────. -1088 ¦ . ╎1 edit copy to recipe delete . -1089 ¦ . ╎add 2, 2 . -1090 ¦ . ╎4 . -1091 ] -1092 # hit 'page-down' again -1093 assume-console [ -1094 ¦ press page-down -1095 ] -1096 run [ -1097 ¦ event-loop screen, console, env, resources +1055 # hit 'page-up' again +1056 assume-console [ +1057 ¦ press page-up +1058 ] +1059 run [ +1060 ¦ event-loop screen, console, env, resources +1061 ¦ cursor:char <- copy 9251/␣ +1062 ¦ print screen, cursor +1063 ] +1064 # back to displaying both sandboxes as well as editor +1065 screen-should-contain [ +1066 ¦ . run (F4) . +1067 ¦ . ╎␣ . +1068 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +1069 ¦ . ╎0 edit copy to recipe delete . +1070 ¦ . ╎add 1, 1 . +1071 ¦ . ╎2 . +1072 ¦ . ╎─────────────────────────────────────────────────. +1073 ¦ . ╎1 edit copy to recipe delete . +1074 ¦ . ╎add 2, 2 . +1075 ¦ . ╎4 . +1076 ] +1077 # hit 'page-up' again +1078 assume-console [ +1079 ¦ press page-up +1080 ] +1081 run [ +1082 ¦ event-loop screen, console, env, resources +1083 ¦ cursor:char <- copy 9251/␣ +1084 ¦ print screen, cursor +1085 ] +1086 # no change +1087 screen-should-contain [ +1088 ¦ . run (F4) . +1089 ¦ . ╎␣ . +1090 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +1091 ¦ . ╎0 edit copy to recipe delete . +1092 ¦ . ╎add 1, 1 . +1093 ¦ . ╎2 . +1094 ¦ . ╎─────────────────────────────────────────────────. +1095 ¦ . ╎1 edit copy to recipe delete . +1096 ¦ . ╎add 2, 2 . +1097 ¦ . ╎4 . 1098 ] -1099 # just second sandbox displayed -1100 screen-should-contain [ -1101 ¦ . run (F4) . -1102 ¦ . ╎─────────────────────────────────────────────────. -1103 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete . -1104 ¦ . ╎add 2, 2 . -1105 ¦ . ╎4 . -1106 ¦ . ╎─────────────────────────────────────────────────. -1107 ¦ . ╎ . -1108 ] -1109 # hit 'page-down' again -1110 assume-console [ -1111 ¦ press page-down -1112 ] -1113 run [ -1114 ¦ event-loop screen, console, env, resources +1099 ] +1100 +1101 scenario scrolling-manages-sandbox-index-correctly [ +1102 local-scope +1103 trace-until 100/app # trace too long +1104 assume-screen 100/width, 10/height +1105 # initialize environment +1106 assume-resources [ +1107 ] +1108 env:&:environment <- new-programming-environment resources, screen, [] +1109 render-all screen, env, render +1110 # create a sandbox +1111 assume-console [ +1112 ¦ press ctrl-n +1113 ¦ type [add 1, 1] +1114 ¦ press F4 1115 ] -1116 # no change +1116 event-loop screen, console, env, resources 1117 screen-should-contain [ 1118 ¦ . run (F4) . -1119 ¦ . ╎─────────────────────────────────────────────────. -1120 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete . -1121 ¦ . ╎add 2, 2 . -1122 ¦ . ╎4 . -1123 ¦ . ╎─────────────────────────────────────────────────. -1124 ¦ . ╎ . -1125 ] -1126 # hit 'page-up' -1127 assume-console [ -1128 ¦ press page-up -1129 ] -1130 run [ -1131 ¦ event-loop screen, console, env, resources -1132 ] -1133 # back to displaying both sandboxes without editor -1134 screen-should-contain [ -1135 ¦ . run (F4) . -1136 ¦ . ╎─────────────────────────────────────────────────. -1137 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . -1138 ¦ . ╎add 1, 1 . -1139 ¦ . ╎2 . -1140 ¦ . ╎─────────────────────────────────────────────────. -1141 ¦ . ╎1 edit copy to recipe delete . -1142 ¦ . ╎add 2, 2 . -1143 ¦ . ╎4 . +1119 ¦ . ╎ . +1120 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +1121 ¦ . ╎0 edit copy to recipe delete . +1122 ¦ . ╎add 1, 1 . +1123 ¦ . ╎2 . +1124 ¦ . ╎─────────────────────────────────────────────────. +1125 ¦ . ╎ . +1126 ] +1127 # hit 'page-down' and 'page-up' a couple of times. sandbox index should be stable +1128 assume-console [ +1129 ¦ press page-down +1130 ] +1131 run [ +1132 ¦ event-loop screen, console, env, resources +1133 ] +1134 # sandbox editor hidden; first sandbox displayed +1135 # cursor moves to first sandbox +1136 screen-should-contain [ +1137 ¦ . run (F4) . +1138 ¦ . ╎─────────────────────────────────────────────────. +1139 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . +1140 ¦ . ╎add 1, 1 . +1141 ¦ . ╎2 . +1142 ¦ . ╎─────────────────────────────────────────────────. +1143 ¦ . ╎ . 1144 ] 1145 # hit 'page-up' again 1146 assume-console [ -1147 ¦ press page-up +1147 ¦ press page-up 1148 ] 1149 run [ 1150 ¦ event-loop screen, console, env, resources -1151 ¦ cursor:char <- copy 9251/␣ -1152 ¦ print screen, cursor -1153 ] -1154 # back to displaying both sandboxes as well as editor -1155 screen-should-contain [ -1156 ¦ . run (F4) . -1157 ¦ . ╎␣ . -1158 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -1159 ¦ . ╎0 edit copy to recipe delete . -1160 ¦ . ╎add 1, 1 . -1161 ¦ . ╎2 . -1162 ¦ . ╎─────────────────────────────────────────────────. -1163 ¦ . ╎1 edit copy to recipe delete . -1164 ¦ . ╎add 2, 2 . -1165 ¦ . ╎4 . +1151 ] +1152 # back to displaying both sandboxes as well as editor +1153 screen-should-contain [ +1154 ¦ . run (F4) . +1155 ¦ . ╎ . +1156 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +1157 ¦ . ╎0 edit copy to recipe delete . +1158 ¦ . ╎add 1, 1 . +1159 ¦ . ╎2 . +1160 ¦ . ╎─────────────────────────────────────────────────. +1161 ¦ . ╎ . +1162 ] +1163 # hit 'page-down' +1164 assume-console [ +1165 ¦ press page-down 1166 ] -1167 # hit 'page-up' again -1168 assume-console [ -1169 ¦ press page-up -1170 ] -1171 run [ -1172 ¦ event-loop screen, console, env, resources -1173 ¦ cursor:char <- copy 9251/␣ -1174 ¦ print screen, cursor -1175 ] -1176 # no change -1177 screen-should-contain [ -1178 ¦ . run (F4) . -1179 ¦ . ╎␣ . -1180 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -1181 ¦ . ╎0 edit copy to recipe delete . -1182 ¦ . ╎add 1, 1 . -1183 ¦ . ╎2 . -1184 ¦ . ╎─────────────────────────────────────────────────. -1185 ¦ . ╎1 edit copy to recipe delete . -1186 ¦ . ╎add 2, 2 . -1187 ¦ . ╎4 . -1188 ] -1189 ] -1190 -1191 scenario scrolling-manages-sandbox-index-correctly [ -1192 local-scope -1193 trace-until 100/app # trace too long -1194 assume-screen 100/width, 10/height -1195 # initialize environment -1196 assume-resources [ -1197 ] -1198 env:&:environment <- new-programming-environment resources, screen, [] -1199 render-all screen, env, render -1200 # create a sandbox -1201 assume-console [ -1202 ¦ press ctrl-n -1203 ¦ type [add 1, 1] -1204 ¦ press F4 -1205 ] -1206 event-loop screen, console, env, resources -1207 screen-should-contain [ -1208 ¦ . run (F4) . -1209 ¦ . ╎ . -1210 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -1211 ¦ . ╎0 edit copy to recipe delete . -1212 ¦ . ╎add 1, 1 . -1213 ¦ . ╎2 . -1214 ¦ . ╎─────────────────────────────────────────────────. -1215 ¦ . ╎ . -1216 ] -1217 # hit 'page-down' and 'page-up' a couple of times. sandbox index should be stable -1218 assume-console [ -1219 ¦ press page-down -1220 ] -1221 run [ -1222 ¦ event-loop screen, console, env, resources -1223 ] -1224 # sandbox editor hidden; first sandbox displayed -1225 # cursor moves to first sandbox -1226 screen-should-contain [ -1227 ¦ . run (F4) . -1228 ¦ . ╎─────────────────────────────────────────────────. -1229 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . -1230 ¦ . ╎add 1, 1 . -1231 ¦ . ╎2 . -1232 ¦ . ╎─────────────────────────────────────────────────. -1233 ¦ . ╎ . -1234 ] -1235 # hit 'page-up' again -1236 assume-console [ -1237 ¦ press page-up -1238 ] -1239 run [ -1240 ¦ event-loop screen, console, env, resources -1241 ] -1242 # back to displaying both sandboxes as well as editor -1243 screen-should-contain [ -1244 ¦ . run (F4) . -1245 ¦ . ╎ . -1246 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -1247 ¦ . ╎0 edit copy to recipe delete . -1248 ¦ . ╎add 1, 1 . -1249 ¦ . ╎2 . -1250 ¦ . ╎─────────────────────────────────────────────────. -1251 ¦ . ╎ . -1252 ] -1253 # hit 'page-down' -1254 assume-console [ -1255 ¦ press page-down -1256 ] -1257 run [ -1258 ¦ event-loop screen, console, env, resources -1259 ] -1260 # sandbox editor hidden; first sandbox displayed -1261 # cursor moves to first sandbox -1262 screen-should-contain [ -1263 ¦ . run (F4) . -1264 ¦ . ╎─────────────────────────────────────────────────. -1265 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . -1266 ¦ . ╎add 1, 1 . -1267 ¦ . ╎2 . -1268 ¦ . ╎─────────────────────────────────────────────────. -1269 ¦ . ╎ . -1270 ] -1271 ] +1167 run [ +1168 ¦ event-loop screen, console, env, resources +1169 ] +1170 # sandbox editor hidden; first sandbox displayed +1171 # cursor moves to first sandbox +1172 screen-should-contain [ +1173 ¦ . run (F4) . +1174 ¦ . ╎─────────────────────────────────────────────────. +1175 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete . +1176 ¦ . ╎add 1, 1 . +1177 ¦ . ╎2 . +1178 ¦ . ╎─────────────────────────────────────────────────. +1179 ¦ . ╎ . +1180 ] +1181 ] diff --git a/html/edit/007-sandbox-delete.mu.html b/html/edit/007-sandbox-delete.mu.html index a51492f8..0a41fc07 100644 --- a/html/edit/007-sandbox-delete.mu.html +++ b/html/edit/007-sandbox-delete.mu.html @@ -225,7 +225,7 @@ if ('onhashchange' in window) { 163 ¦ press F4 164 ¦ type [add 1, 1] 165 ¦ press F4 -166 ¦ press page-down +166 ¦ press page-down 167 ] 168 event-loop screen, console, env, resources 169 screen-should-contain [ @@ -272,7 +272,7 @@ if ('onhashchange' in window) { 210 ¦ press F4 211 ¦ type [add 1, 1] 212 ¦ press F4 -213 ¦ press page-down +213 ¦ press page-down 214 ] 215 event-loop screen, console, env, resources 216 screen-should-contain [ @@ -319,8 +319,8 @@ if ('onhashchange' in window) { 257 ¦ press F4 258 ¦ type [add 1, 1] 259 ¦ press F4 -260 ¦ press page-down -261 ¦ press page-down +260 ¦ press page-down +261 ¦ press page-down 262 ] 263 event-loop screen, console, env, resources 264 screen-should-contain [ @@ -385,8 +385,8 @@ if ('onhashchange' in window) { 323 # delete the second sandbox, then try to scroll down twice 324 assume-console [ 325 ¦ left-click 3, 99 -326 ¦ press page-down -327 ¦ press page-down +326 ¦ press page-down +327 ¦ press page-down 328 ] 329 run [ 330 ¦ event-loop screen, console, env, resources diff --git a/html/edit/008-sandbox-edit.mu.html b/html/edit/008-sandbox-edit.mu.html index 0103fb55..bfa85e12 100644 --- a/html/edit/008-sandbox-edit.mu.html +++ b/html/edit/008-sandbox-edit.mu.html @@ -281,8 +281,8 @@ if ('onhashchange' in window) { 219 ¦ press F4 220 ¦ type [add 1, 1] 221 ¦ press F4 -222 ¦ press page-down -223 ¦ press page-down +222 ¦ press page-down +223 ¦ press page-down 224 ] 225 event-loop screen, console, env, resources 226 screen-should-contain [ @@ -367,9 +367,9 @@ if ('onhashchange' in window) { 305 ] 306 # now try to scroll past end 307 assume-console [ -308 ¦ press page-down -309 ¦ press page-down -310 ¦ press page-down +308 ¦ press page-down +309 ¦ press page-down +310 ¦ press page-down 311 ] 312 run [ 313 ¦ event-loop screen, console, env, resources diff --git a/html/edit/011-errors.mu.html b/html/edit/011-errors.mu.html index 85778a7a..b01219ba 100644 --- a/html/edit/011-errors.mu.html +++ b/html/edit/011-errors.mu.html @@ -93,7 +93,7 @@ if ('onhashchange' in window) { 30 ¦ recipes:&:editor <- get *env, recipes:offset 31 ¦ left:num <- get *recipes, left:offset 32 ¦ right:num <- get *recipes, right:offset - 33 ¦ row:num <- get *env, recipe-bottom:offset + 33 ¦ row:num <- get *recipes, bottom:offset 34 ¦ row, screen <- render-text screen, recipe-errors, left, right, 1/red, row 35 ¦ # draw dotted line after recipes 36 ¦ draw-horizontal screen, row, left, right, 9480/horizontal-dotted @@ -209,198 +209,198 @@ if ('onhashchange' in window) { 146 ¦ .recipe foo [ ╎foo . 147 ¦ . get 123:num, foo:offset ╎─────────────────────────────────────────────────. 148 ¦ .] ╎ . -149 ¦ . ╎ . -150 ¦ .foo: unknown element 'foo' in container 'number' ╎ . -151 ¦ .foo: first ingredient of 'get' should be a contai↩╎ . -152 ¦ .ner, but got '123:num' ╎ . -153 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -154 ¦ . ╎ . -155 ] -156 screen-should-contain-in-color 1/red, [ -157 ¦ . errors found . +149 ¦ .foo: unknown element 'foo' in container 'number' ╎ . +150 ¦ .foo: first ingredient of 'get' should be a contai↩╎ . +151 ¦ .ner, but got '123:num' ╎ . +152 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +153 ¦ . ╎ . +154 ] +155 screen-should-contain-in-color 1/red, [ +156 ¦ . errors found . +157 ¦ . . 158 ¦ . . 159 ¦ . . -160 ¦ . . -161 ¦ . . -162 ¦ .foo: unknown element 'foo' in container 'number' . -163 ¦ .foo: first ingredient of 'get' should be a contai . -164 ¦ .ner, but got '123:num' . -165 ¦ . . -166 ] -167 ] -168 -169 scenario run-updates-status-with-first-erroneous-sandbox [ -170 local-scope -171 trace-until 100/app # trace too long -172 assume-screen 100/width, 15/height -173 assume-resources [ -174 ] -175 env:&:environment <- new-programming-environment resources, screen, [] -176 render-all screen, env, render -177 assume-console [ -178 ¦ left-click 3, 80 -179 ¦ # create invalid sandbox 1 -180 ¦ type [get foo, x:offset] -181 ¦ press F4 -182 ¦ # create invalid sandbox 0 -183 ¦ type [get foo, x:offset] -184 ¦ press F4 -185 ] -186 run [ -187 ¦ event-loop screen, console, env, resources -188 ] -189 # status line shows that error is in first sandbox -190 screen-should-contain [ -191 ¦ . errors found (0) run (F4) . -192 ] -193 ] -194 -195 scenario run-updates-status-with-first-erroneous-sandbox-2 [ -196 local-scope -197 trace-until 100/app # trace too long -198 assume-screen 100/width, 15/height -199 assume-resources [ -200 ] -201 env:&:environment <- new-programming-environment resources, screen, [] -202 render-all screen, env, render -203 assume-console [ -204 ¦ left-click 3, 80 -205 ¦ # create invalid sandbox 2 -206 ¦ type [get foo, x:offset] -207 ¦ press F4 -208 ¦ # create invalid sandbox 1 -209 ¦ type [get foo, x:offset] -210 ¦ press F4 -211 ¦ # create valid sandbox 0 -212 ¦ type [add 2, 2] -213 ¦ press F4 -214 ] -215 run [ -216 ¦ event-loop screen, console, env, resources -217 ] -218 # status line shows that error is in second sandbox -219 screen-should-contain [ -220 ¦ . errors found (1) run (F4) . -221 ] -222 ] -223 -224 scenario run-hides-errors-from-past-sandboxes [ -225 local-scope -226 trace-until 100/app # trace too long -227 assume-screen 100/width, 15/height -228 assume-resources [ -229 ] -230 env:&:environment <- new-programming-environment resources, screen, [get foo, x:offset] # invalid -231 render-all screen, env, render -232 assume-console [ -233 ¦ press F4 # generate error -234 ] -235 event-loop screen, console, env, resources -236 assume-console [ -237 ¦ left-click 3, 58 -238 ¦ press ctrl-k -239 ¦ type [add 2, 2] # valid code -240 ¦ press F4 # update sandbox -241 ] -242 run [ -243 ¦ event-loop screen, console, env, resources -244 ] -245 # error should disappear -246 screen-should-contain [ -247 ¦ . run (F4) . -248 ¦ . ╎ . -249 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -250 ¦ . ╎0 edit copy to recipe delete . -251 ¦ . ╎add 2, 2 . -252 ¦ . ╎4 . -253 ¦ . ╎─────────────────────────────────────────────────. -254 ¦ . ╎ . -255 ] -256 ] -257 -258 scenario run-updates-errors-for-shape-shifting-recipes [ -259 local-scope -260 trace-until 100/app # trace too long -261 assume-screen 100/width, 15/height -262 # define a shape-shifting recipe with an error -263 assume-resources [ -264 ¦ [lesson/recipes.mu] <- [ -265 ¦ ¦ |recipe foo x:_elem -> z:_elem [| -266 ¦ ¦ | local-scope| -267 ¦ ¦ | load-ingredients| -268 ¦ ¦ | y:&:num <- copy 0| -269 ¦ ¦ | z <- add x, y| -270 ¦ ¦ |]| -271 ¦ ] -272 ] -273 env:&:environment <- new-programming-environment resources, screen, [foo 2] -274 render-all screen, env, render -275 assume-console [ -276 ¦ press F4 -277 ] -278 event-loop screen, console, env, resources -279 screen-should-contain [ -280 ¦ . errors found (0) run (F4) . -281 ¦ .recipe foo x:_elem -> z:_elem [ ╎ . -282 ¦ . local-scope ╎─────────────────────────────────────────────────. -283 ¦ . load-ingredients ╎0 edit copy to recipe delete . -284 ¦ . y:&:num <- copy 0 ╎foo 2 . -285 ¦ . z <- add x, y ╎foo_2: 'add' requires number ingredients, but go↩. -286 ¦ .] ╎t 'y' . -287 ¦ . ╎─────────────────────────────────────────────────. -288 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -289 ¦ . ╎ . -290 ] -291 # now rerun everything -292 assume-console [ -293 ¦ press F4 -294 ] -295 run [ -296 ¦ event-loop screen, console, env, resources -297 ] -298 # error should remain unchanged -299 screen-should-contain [ -300 ¦ . errors found (0) run (F4) . -301 ¦ .recipe foo x:_elem -> z:_elem [ ╎ . -302 ¦ . local-scope ╎─────────────────────────────────────────────────. -303 ¦ . load-ingredients ╎0 edit copy to recipe delete . -304 ¦ . y:&:num <- copy 0 ╎foo 2 . -305 ¦ . z <- add x, y ╎foo_3: 'add' requires number ingredients, but go↩. -306 ¦ .] ╎t 'y' . -307 ¦ . ╎─────────────────────────────────────────────────. -308 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -309 ¦ . ╎ . -310 ] -311 ] -312 -313 scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [ -314 local-scope -315 trace-until 100/app # trace too long -316 assume-screen 100/width, 15/height -317 # overload a well-known shape-shifting recipe -318 assume-resources [ -319 ¦ [lesson/recipes.mu] <- [ -320 ¦ ¦ |recipe length l:&:list:_elem -> n:num [| -321 ¦ ¦ |]| -322 ¦ ] -323 ] -324 # call code that uses other variants of it, but not it itself -325 test-sandbox:text <- new [x:&:list:num <- copy 0 -326 to-text x] -327 env:&:environment <- new-programming-environment resources, screen, test-sandbox -328 render-all screen, env, render -329 # run it once -330 assume-console [ -331 ¦ press F4 -332 ] -333 event-loop screen, console, env, resources -334 # no errors anywhere on screen (can't check anything else, since to-text will return an address) -335 screen-should-contain-in-color 1/red, [ +160 ¦ .foo: unknown element 'foo' in container 'number' . +161 ¦ .foo: first ingredient of 'get' should be a contai . +162 ¦ .ner, but got '123:num' . +163 ¦ . . +164 ] +165 ] +166 +167 scenario run-updates-status-with-first-erroneous-sandbox [ +168 local-scope +169 trace-until 100/app # trace too long +170 assume-screen 100/width, 15/height +171 assume-resources [ +172 ] +173 env:&:environment <- new-programming-environment resources, screen, [] +174 render-all screen, env, render +175 assume-console [ +176 ¦ left-click 3, 80 +177 ¦ # create invalid sandbox 1 +178 ¦ type [get foo, x:offset] +179 ¦ press F4 +180 ¦ # create invalid sandbox 0 +181 ¦ type [get foo, x:offset] +182 ¦ press F4 +183 ] +184 run [ +185 ¦ event-loop screen, console, env, resources +186 ] +187 # status line shows that error is in first sandbox +188 screen-should-contain [ +189 ¦ . errors found (0) run (F4) . +190 ] +191 ] +192 +193 scenario run-updates-status-with-first-erroneous-sandbox-2 [ +194 local-scope +195 trace-until 100/app # trace too long +196 assume-screen 100/width, 15/height +197 assume-resources [ +198 ] +199 env:&:environment <- new-programming-environment resources, screen, [] +200 render-all screen, env, render +201 assume-console [ +202 ¦ left-click 3, 80 +203 ¦ # create invalid sandbox 2 +204 ¦ type [get foo, x:offset] +205 ¦ press F4 +206 ¦ # create invalid sandbox 1 +207 ¦ type [get foo, x:offset] +208 ¦ press F4 +209 ¦ # create valid sandbox 0 +210 ¦ type [add 2, 2] +211 ¦ press F4 +212 ] +213 run [ +214 ¦ event-loop screen, console, env, resources +215 ] +216 # status line shows that error is in second sandbox +217 screen-should-contain [ +218 ¦ . errors found (1) run (F4) . +219 ] +220 ] +221 +222 scenario run-hides-errors-from-past-sandboxes [ +223 local-scope +224 trace-until 100/app # trace too long +225 assume-screen 100/width, 15/height +226 assume-resources [ +227 ] +228 env:&:environment <- new-programming-environment resources, screen, [get foo, x:offset] # invalid +229 render-all screen, env, render +230 assume-console [ +231 ¦ press F4 # generate error +232 ] +233 event-loop screen, console, env, resources +234 assume-console [ +235 ¦ left-click 3, 58 +236 ¦ press ctrl-k +237 ¦ type [add 2, 2] # valid code +238 ¦ press F4 # update sandbox +239 ] +240 run [ +241 ¦ event-loop screen, console, env, resources +242 ] +243 # error should disappear +244 screen-should-contain [ +245 ¦ . run (F4) . +246 ¦ . ╎ . +247 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +248 ¦ . ╎0 edit copy to recipe delete . +249 ¦ . ╎add 2, 2 . +250 ¦ . ╎4 . +251 ¦ . ╎─────────────────────────────────────────────────. +252 ¦ . ╎ . +253 ] +254 ] +255 +256 scenario run-updates-errors-for-shape-shifting-recipes [ +257 local-scope +258 trace-until 100/app # trace too long +259 assume-screen 100/width, 15/height +260 # define a shape-shifting recipe with an error +261 assume-resources [ +262 ¦ [lesson/recipes.mu] <- [ +263 ¦ ¦ |recipe foo x:_elem -> z:_elem [| +264 ¦ ¦ | local-scope| +265 ¦ ¦ | load-ingredients| +266 ¦ ¦ | y:&:num <- copy 0| +267 ¦ ¦ | z <- add x, y| +268 ¦ ¦ |]| +269 ¦ ] +270 ] +271 env:&:environment <- new-programming-environment resources, screen, [foo 2] +272 render-all screen, env, render +273 assume-console [ +274 ¦ press F4 +275 ] +276 event-loop screen, console, env, resources +277 screen-should-contain [ +278 ¦ . errors found (0) run (F4) . +279 ¦ .recipe foo x:_elem -> z:_elem [ ╎ . +280 ¦ . local-scope ╎─────────────────────────────────────────────────. +281 ¦ . load-ingredients ╎0 edit copy to recipe delete . +282 ¦ . y:&:num <- copy 0 ╎foo 2 . +283 ¦ . z <- add x, y ╎foo_2: 'add' requires number ingredients, but go↩. +284 ¦ .] ╎t 'y' . +285 ¦ . ╎─────────────────────────────────────────────────. +286 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +287 ¦ . ╎ . +288 ] +289 # now rerun everything +290 assume-console [ +291 ¦ press F4 +292 ] +293 run [ +294 ¦ event-loop screen, console, env, resources +295 ] +296 # error should remain unchanged +297 screen-should-contain [ +298 ¦ . errors found (0) run (F4) . +299 ¦ .recipe foo x:_elem -> z:_elem [ ╎ . +300 ¦ . local-scope ╎─────────────────────────────────────────────────. +301 ¦ . load-ingredients ╎0 edit copy to recipe delete . +302 ¦ . y:&:num <- copy 0 ╎foo 2 . +303 ¦ . z <- add x, y ╎foo_3: 'add' requires number ingredients, but go↩. +304 ¦ .] ╎t 'y' . +305 ¦ . ╎─────────────────────────────────────────────────. +306 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +307 ¦ . ╎ . +308 ] +309 ] +310 +311 scenario run-avoids-spurious-errors-on-reloading-shape-shifting-recipes [ +312 local-scope +313 trace-until 100/app # trace too long +314 assume-screen 100/width, 15/height +315 # overload a well-known shape-shifting recipe +316 assume-resources [ +317 ¦ [lesson/recipes.mu] <- [ +318 ¦ ¦ |recipe length l:&:list:_elem -> n:num [| +319 ¦ ¦ |]| +320 ¦ ] +321 ] +322 # call code that uses other variants of it, but not it itself +323 test-sandbox:text <- new [x:&:list:num <- copy 0 +324 to-text x] +325 env:&:environment <- new-programming-environment resources, screen, test-sandbox +326 render-all screen, env, render +327 # run it once +328 assume-console [ +329 ¦ press F4 +330 ] +331 event-loop screen, console, env, resources +332 # no errors anywhere on screen (can't check anything else, since to-text will return an address) +333 screen-should-contain-in-color 1/red, [ +334 ¦ . . +335 ¦ . . 336 ¦ . . 337 ¦ . . -338 ¦ . . +338 ¦ . <- . 339 ¦ . . -340 ¦ . <- . +340 ¦ . . 341 ¦ . . 342 ¦ . . 343 ¦ . . @@ -409,23 +409,23 @@ if ('onhashchange' in window) { 346 ¦ . . 347 ¦ . . 348 ¦ . . -349 ¦ . . -350 ¦ . . -351 ] -352 # rerun everything -353 assume-console [ -354 ¦ press F4 -355 ] -356 run [ -357 ¦ event-loop screen, console, env, resources -358 ] -359 # still no errors -360 screen-should-contain-in-color 1/red, [ +349 ] +350 # rerun everything +351 assume-console [ +352 ¦ press F4 +353 ] +354 run [ +355 ¦ event-loop screen, console, env, resources +356 ] +357 # still no errors +358 screen-should-contain-in-color 1/red, [ +359 ¦ . . +360 ¦ . . 361 ¦ . . 362 ¦ . . -363 ¦ . . +363 ¦ . <- . 364 ¦ . . -365 ¦ . <- . +365 ¦ . . 366 ¦ . . 367 ¦ . . 368 ¦ . . @@ -434,388 +434,380 @@ if ('onhashchange' in window) { 371 ¦ . . 372 ¦ . . 373 ¦ . . -374 ¦ . . -375 ¦ . . -376 ] -377 ] -378 -379 scenario run-shows-missing-type-errors [ -380 local-scope -381 trace-until 100/app # trace too long -382 assume-screen 100/width, 15/height -383 assume-resources [ -384 ¦ [lesson/recipes.mu] <- [ -385 ¦ ¦ |recipe foo [| -386 ¦ ¦ | x <- copy 0| -387 ¦ ¦ |]| -388 ¦ ] -389 ] -390 env:&:environment <- new-programming-environment resources, screen, [foo] -391 render-all screen, env, render -392 assume-console [ -393 ¦ press F4 -394 ] -395 run [ -396 ¦ event-loop screen, console, env, resources -397 ] -398 screen-should-contain [ -399 ¦ . errors found run (F4) . -400 ¦ .recipe foo [ ╎foo . -401 ¦ . x <- copy 0 ╎─────────────────────────────────────────────────. -402 ¦ .] ╎ . -403 ¦ . ╎ . -404 ¦ .foo: missing type for 'x' in 'x <- copy 0' ╎ . -405 ¦ .foo: can't copy '0' to 'x'; types don't match ╎ . -406 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -407 ¦ . ╎ . -408 ] -409 ] -410 -411 scenario run-shows-unbalanced-bracket-errors [ -412 local-scope -413 trace-until 100/app # trace too long -414 assume-screen 100/width, 15/height -415 # recipe is incomplete (unbalanced '[') -416 assume-resources [ -417 ¦ [lesson/recipes.mu] <- [ -418 ¦ ¦ |recipe foo \\\[| -419 ¦ ¦ | x <- copy 0| -420 ¦ ] -421 ] -422 env:&:environment <- new-programming-environment resources, screen, [foo] -423 render-all screen, env, render -424 assume-console [ -425 ¦ press F4 +374 ] +375 ] +376 +377 scenario run-shows-missing-type-errors [ +378 local-scope +379 trace-until 100/app # trace too long +380 assume-screen 100/width, 15/height +381 assume-resources [ +382 ¦ [lesson/recipes.mu] <- [ +383 ¦ ¦ |recipe foo [| +384 ¦ ¦ | x <- copy 0| +385 ¦ ¦ |]| +386 ¦ ] +387 ] +388 env:&:environment <- new-programming-environment resources, screen, [foo] +389 render-all screen, env, render +390 assume-console [ +391 ¦ press F4 +392 ] +393 run [ +394 ¦ event-loop screen, console, env, resources +395 ] +396 screen-should-contain [ +397 ¦ . errors found run (F4) . +398 ¦ .recipe foo [ ╎foo . +399 ¦ . x <- copy 0 ╎─────────────────────────────────────────────────. +400 ¦ .] ╎ . +401 ¦ .foo: missing type for 'x' in 'x <- copy 0' ╎ . +402 ¦ .foo: can't copy '0' to 'x'; types don't match ╎ . +403 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +404 ¦ . ╎ . +405 ] +406 ] +407 +408 scenario run-shows-unbalanced-bracket-errors [ +409 local-scope +410 trace-until 100/app # trace too long +411 assume-screen 100/width, 15/height +412 # recipe is incomplete (unbalanced '[') +413 assume-resources [ +414 ¦ [lesson/recipes.mu] <- [ +415 ¦ ¦ |recipe foo \\\[| +416 ¦ ¦ | x <- copy 0| +417 ¦ ] +418 ] +419 env:&:environment <- new-programming-environment resources, screen, [foo] +420 render-all screen, env, render +421 assume-console [ +422 ¦ press F4 +423 ] +424 run [ +425 ¦ event-loop screen, console, env, resources 426 ] -427 run [ -428 ¦ event-loop screen, console, env, resources -429 ] -430 screen-should-contain [ -431 ¦ . errors found run (F4) . -432 ¦ .recipe foo \\[ ╎foo . -433 ¦ . x <- copy 0 ╎─────────────────────────────────────────────────. -434 ¦ . ╎ . -435 ¦ .9: unbalanced '\\[' for recipe ╎ . -436 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -437 ¦ . ╎ . -438 ] -439 ] -440 -441 scenario run-shows-get-on-non-container-errors [ -442 local-scope -443 trace-until 100/app # trace too long -444 assume-screen 100/width, 15/height -445 assume-resources [ -446 ¦ [lesson/recipes.mu] <- [ -447 ¦ ¦ |recipe foo [| -448 ¦ ¦ | local-scope| -449 ¦ ¦ | x:&:point <- new point:type| -450 ¦ ¦ | get x:&:point, 1:offset| -451 ¦ ¦ |]| -452 ¦ ] -453 ] -454 env:&:environment <- new-programming-environment resources, screen, [foo] -455 render-all screen, env, render -456 assume-console [ -457 ¦ press F4 -458 ] -459 run [ -460 ¦ event-loop screen, console, env, resources -461 ] -462 screen-should-contain [ -463 ¦ . errors found run (F4) . -464 ¦ .recipe foo [ ╎foo . -465 ¦ . local-scope ╎─────────────────────────────────────────────────. -466 ¦ . x:&:point <- new point:type ╎ . -467 ¦ . get x:&:point, 1:offset ╎ . -468 ¦ .] ╎ . -469 ¦ . ╎ . -470 ¦ .foo: first ingredient of 'get' should be a contai↩╎ . -471 ¦ .ner, but got 'x:&:point' ╎ . -472 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -473 ¦ . ╎ . -474 ] -475 ] -476 -477 scenario run-shows-non-literal-get-argument-errors [ -478 local-scope -479 trace-until 100/app # trace too long -480 assume-screen 100/width, 15/height -481 assume-resources [ -482 ¦ [lesson/recipes.mu] <- [ -483 ¦ ¦ |recipe foo [| -484 ¦ ¦ | local-scope| -485 ¦ ¦ | x:num <- copy 0| -486 ¦ ¦ | y:&:point <- new point:type| -487 ¦ ¦ | get *y:&:point, x:num| -488 ¦ ¦ |]| -489 ¦ ] +427 screen-should-contain [ +428 ¦ . errors found run (F4) . +429 ¦ .recipe foo \\[ ╎foo . +430 ¦ . x <- copy 0 ╎─────────────────────────────────────────────────. +431 ¦ .9: unbalanced '\\[' for recipe ╎ . +432 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +433 ¦ . ╎ . +434 ] +435 ] +436 +437 scenario run-shows-get-on-non-container-errors [ +438 local-scope +439 trace-until 100/app # trace too long +440 assume-screen 100/width, 15/height +441 assume-resources [ +442 ¦ [lesson/recipes.mu] <- [ +443 ¦ ¦ |recipe foo [| +444 ¦ ¦ | local-scope| +445 ¦ ¦ | x:&:point <- new point:type| +446 ¦ ¦ | get x:&:point, 1:offset| +447 ¦ ¦ |]| +448 ¦ ] +449 ] +450 env:&:environment <- new-programming-environment resources, screen, [foo] +451 render-all screen, env, render +452 assume-console [ +453 ¦ press F4 +454 ] +455 run [ +456 ¦ event-loop screen, console, env, resources +457 ] +458 screen-should-contain [ +459 ¦ . errors found run (F4) . +460 ¦ .recipe foo [ ╎foo . +461 ¦ . local-scope ╎─────────────────────────────────────────────────. +462 ¦ . x:&:point <- new point:type ╎ . +463 ¦ . get x:&:point, 1:offset ╎ . +464 ¦ .] ╎ . +465 ¦ .foo: first ingredient of 'get' should be a contai↩╎ . +466 ¦ .ner, but got 'x:&:point' ╎ . +467 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +468 ¦ . ╎ . +469 ] +470 ] +471 +472 scenario run-shows-non-literal-get-argument-errors [ +473 local-scope +474 trace-until 100/app # trace too long +475 assume-screen 100/width, 15/height +476 assume-resources [ +477 ¦ [lesson/recipes.mu] <- [ +478 ¦ ¦ |recipe foo [| +479 ¦ ¦ | local-scope| +480 ¦ ¦ | x:num <- copy 0| +481 ¦ ¦ | y:&:point <- new point:type| +482 ¦ ¦ | get *y:&:point, x:num| +483 ¦ ¦ |]| +484 ¦ ] +485 ] +486 env:&:environment <- new-programming-environment resources, screen, [foo] +487 render-all screen, env, render +488 assume-console [ +489 ¦ press F4 490 ] -491 env:&:environment <- new-programming-environment resources, screen, [foo] -492 render-all screen, env, render -493 assume-console [ -494 ¦ press F4 -495 ] -496 run [ -497 ¦ event-loop screen, console, env, resources -498 ] -499 screen-should-contain [ -500 ¦ . errors found run (F4) . -501 ¦ .recipe foo [ ╎foo . -502 ¦ . local-scope ╎─────────────────────────────────────────────────. -503 ¦ . x:num <- copy 0 ╎ . -504 ¦ . y:&:point <- new point:type ╎ . -505 ¦ . get *y:&:point, x:num ╎ . -506 ¦ .] ╎ . -507 ¦ . ╎ . -508 ¦ .foo: second ingredient of 'get' should have type ↩╎ . -509 ¦ .'offset', but got 'x:num' ╎ . -510 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -511 ¦ . ╎ . -512 ] -513 ] -514 -515 scenario run-shows-errors-everytime [ -516 local-scope -517 trace-until 100/app # trace too long -518 assume-screen 100/width, 15/height -519 # try to run a file with an error -520 assume-resources [ -521 ¦ [lesson/recipes.mu] <- [ -522 ¦ ¦ |recipe foo [| -523 ¦ ¦ | local-scope| -524 ¦ ¦ | x:num <- copy y:num| -525 ¦ ¦ |]| -526 ¦ ] -527 ] -528 env:&:environment <- new-programming-environment resources, screen, [foo] -529 render-all screen, env, render -530 assume-console [ -531 ¦ press F4 -532 ] -533 event-loop screen, console, env, resources -534 screen-should-contain [ -535 ¦ . errors found run (F4) . -536 ¦ .recipe foo [ ╎foo . -537 ¦ . local-scope ╎─────────────────────────────────────────────────. -538 ¦ . x:num <- copy y:num ╎ . -539 ¦ .] ╎ . -540 ¦ . ╎ . -541 ¦ .foo: tried to read ingredient 'y' in 'x:num <- co↩╎ . -542 ¦ .py y:num' but it hasn't been written to yet ╎ . -543 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -544 ¦ . ╎ . +491 run [ +492 ¦ event-loop screen, console, env, resources +493 ] +494 screen-should-contain [ +495 ¦ . errors found run (F4) . +496 ¦ .recipe foo [ ╎foo . +497 ¦ . local-scope ╎─────────────────────────────────────────────────. +498 ¦ . x:num <- copy 0 ╎ . +499 ¦ . y:&:point <- new point:type ╎ . +500 ¦ . get *y:&:point, x:num ╎ . +501 ¦ .] ╎ . +502 ¦ .foo: second ingredient of 'get' should have type ↩╎ . +503 ¦ .'offset', but got 'x:num' ╎ . +504 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +505 ¦ . ╎ . +506 ] +507 ] +508 +509 scenario run-shows-errors-everytime [ +510 local-scope +511 trace-until 100/app # trace too long +512 assume-screen 100/width, 15/height +513 # try to run a file with an error +514 assume-resources [ +515 ¦ [lesson/recipes.mu] <- [ +516 ¦ ¦ |recipe foo [| +517 ¦ ¦ | local-scope| +518 ¦ ¦ | x:num <- copy y:num| +519 ¦ ¦ |]| +520 ¦ ] +521 ] +522 env:&:environment <- new-programming-environment resources, screen, [foo] +523 render-all screen, env, render +524 assume-console [ +525 ¦ press F4 +526 ] +527 event-loop screen, console, env, resources +528 screen-should-contain [ +529 ¦ . errors found run (F4) . +530 ¦ .recipe foo [ ╎foo . +531 ¦ . local-scope ╎─────────────────────────────────────────────────. +532 ¦ . x:num <- copy y:num ╎ . +533 ¦ .] ╎ . +534 ¦ .foo: tried to read ingredient 'y' in 'x:num <- co↩╎ . +535 ¦ .py y:num' but it hasn't been written to yet ╎ . +536 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +537 ¦ . ╎ . +538 ] +539 # rerun the file, check for the same error +540 assume-console [ +541 ¦ press F4 +542 ] +543 run [ +544 ¦ event-loop screen, console, env, resources 545 ] -546 # rerun the file, check for the same error -547 assume-console [ -548 ¦ press F4 -549 ] -550 run [ -551 ¦ event-loop screen, console, env, resources -552 ] -553 screen-should-contain [ -554 ¦ . errors found run (F4) . -555 ¦ .recipe foo [ ╎foo . -556 ¦ . local-scope ╎─────────────────────────────────────────────────. -557 ¦ . x:num <- copy y:num ╎ . -558 ¦ .] ╎ . -559 ¦ . ╎ . -560 ¦ .foo: tried to read ingredient 'y' in 'x:num <- co↩╎ . -561 ¦ .py y:num' but it hasn't been written to yet ╎ . -562 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -563 ¦ . ╎ . +546 screen-should-contain [ +547 ¦ . errors found run (F4) . +548 ¦ .recipe foo [ ╎foo . +549 ¦ . local-scope ╎─────────────────────────────────────────────────. +550 ¦ . x:num <- copy y:num ╎ . +551 ¦ .] ╎ . +552 ¦ .foo: tried to read ingredient 'y' in 'x:num <- co↩╎ . +553 ¦ .py y:num' but it hasn't been written to yet ╎ . +554 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +555 ¦ . ╎ . +556 ] +557 ] +558 +559 scenario run-instruction-and-print-errors [ +560 local-scope +561 trace-until 100/app # trace too long +562 assume-screen 100/width, 10/height +563 assume-resources [ 564 ] -565 ] -566 -567 scenario run-instruction-and-print-errors [ -568 local-scope -569 trace-until 100/app # trace too long -570 assume-screen 100/width, 10/height -571 assume-resources [ -572 ] -573 # sandbox editor contains an illegal instruction -574 env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset] -575 render-all screen, env, render -576 assume-console [ -577 ¦ press F4 -578 ] -579 run [ -580 ¦ event-loop screen, console, env, resources -581 ] -582 # check that screen prints error message in red -583 screen-should-contain [ -584 ¦ . errors found (0) run (F4) . +565 # sandbox editor contains an illegal instruction +566 env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset] +567 render-all screen, env, render +568 assume-console [ +569 ¦ press F4 +570 ] +571 run [ +572 ¦ event-loop screen, console, env, resources +573 ] +574 # check that screen prints error message in red +575 screen-should-contain [ +576 ¦ . errors found (0) run (F4) . +577 ¦ . ╎ . +578 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +579 ¦ . ╎0 edit copy to recipe delete . +580 ¦ . ╎get 1234:num, foo:offset . +581 ¦ . ╎unknown element 'foo' in container 'number' . +582 ¦ . ╎first ingredient of 'get' should be a container,↩. +583 ¦ . ╎ but got '1234:num' . +584 ¦ . ╎─────────────────────────────────────────────────. 585 ¦ . ╎ . -586 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -587 ¦ . ╎0 edit copy to recipe delete . -588 ¦ . ╎get 1234:num, foo:offset . -589 ¦ . ╎unknown element 'foo' in container 'number' . -590 ¦ . ╎first ingredient of 'get' should be a container,↩. -591 ¦ . ╎ but got '1234:num' . -592 ¦ . ╎─────────────────────────────────────────────────. -593 ¦ . ╎ . -594 ] -595 screen-should-contain-in-color 7/white, [ -596 ¦ . . -597 ¦ . . -598 ¦ . . +586 ] +587 screen-should-contain-in-color 7/white, [ +588 ¦ . . +589 ¦ . . +590 ¦ . . +591 ¦ . . +592 ¦ . get 1234:num, foo:offset . +593 ¦ . . +594 ¦ . . +595 ¦ . . +596 ] +597 screen-should-contain-in-color 1/red, [ +598 ¦ . errors found (0) . 599 ¦ . . -600 ¦ . get 1234:num, foo:offset . +600 ¦ . . 601 ¦ . . 602 ¦ . . -603 ¦ . . -604 ] -605 screen-should-contain-in-color 1/red, [ -606 ¦ . errors found (0) . -607 ¦ . . -608 ¦ . . +603 ¦ . unknown element 'foo' in container 'number' . +604 ¦ . first ingredient of 'get' should be a container, . +605 ¦ . but got '1234:num' . +606 ¦ . . +607 ] +608 screen-should-contain-in-color 245/grey, [ 609 ¦ . . -610 ¦ . . -611 ¦ . unknown element 'foo' in container 'number' . -612 ¦ . first ingredient of 'get' should be a container, . -613 ¦ . but got '1234:num' . -614 ¦ . . -615 ] -616 screen-should-contain-in-color 245/grey, [ -617 ¦ . . +610 ¦ . ╎ . +611 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +612 ¦ . ╎ . +613 ¦ . ╎ . +614 ¦ . ╎ . +615 ¦ . ╎ ↩. +616 ¦ . ╎ . +617 ¦ . ╎─────────────────────────────────────────────────. 618 ¦ . ╎ . -619 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -620 ¦ . ╎ . -621 ¦ . ╎ . -622 ¦ . ╎ . -623 ¦ . ╎ ↩. -624 ¦ . ╎ . -625 ¦ . ╎─────────────────────────────────────────────────. -626 ¦ . ╎ . +619 ] +620 ] +621 +622 scenario run-instruction-and-print-errors-only-once [ +623 local-scope +624 trace-until 100/app # trace too long +625 assume-screen 100/width, 10/height +626 assume-resources [ 627 ] -628 ] -629 -630 scenario run-instruction-and-print-errors-only-once [ -631 local-scope -632 trace-until 100/app # trace too long -633 assume-screen 100/width, 10/height -634 assume-resources [ +628 # sandbox editor contains an illegal instruction +629 env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset] +630 render-all screen, env, render +631 # run the code in the editors multiple times +632 assume-console [ +633 ¦ press F4 +634 ¦ press F4 635 ] -636 # sandbox editor contains an illegal instruction -637 env:&:environment <- new-programming-environment resources, screen, [get 1234:num, foo:offset] -638 render-all screen, env, render -639 # run the code in the editors multiple times -640 assume-console [ -641 ¦ press F4 -642 ¦ press F4 -643 ] -644 run [ -645 ¦ event-loop screen, console, env, resources -646 ] -647 # check that screen prints error message just once -648 screen-should-contain [ -649 ¦ . errors found (0) run (F4) . +636 run [ +637 ¦ event-loop screen, console, env, resources +638 ] +639 # check that screen prints error message just once +640 screen-should-contain [ +641 ¦ . errors found (0) run (F4) . +642 ¦ . ╎ . +643 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. +644 ¦ . ╎0 edit copy to recipe delete . +645 ¦ . ╎get 1234:num, foo:offset . +646 ¦ . ╎unknown element 'foo' in container 'number' . +647 ¦ . ╎first ingredient of 'get' should be a container,↩. +648 ¦ . ╎ but got '1234:num' . +649 ¦ . ╎─────────────────────────────────────────────────. 650 ¦ . ╎ . -651 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────. -652 ¦ . ╎0 edit copy to recipe delete . -653 ¦ . ╎get 1234:num, foo:offset . -654 ¦ . ╎unknown element 'foo' in container 'number' . -655 ¦ . ╎first ingredient of 'get' should be a container,↩. -656 ¦ . ╎ but got '1234:num' . -657 ¦ . ╎─────────────────────────────────────────────────. -658 ¦ . ╎ . -659 ] -660 ] -661 -662 scenario sandbox-can-handle-infinite-loop [ -663 local-scope -664 trace-until 100/app # trace too long -665 assume-screen 100/width, 20/height -666 # sandbox editor will trigger an infinite loop -667 assume-resources [ -668 ¦ [lesson/recipes.mu] <- [ -669 ¦ ¦ |recipe foo [| -670 ¦ ¦ | {| -671 ¦ ¦ | loop| -672 ¦ ¦ | }| -673 ¦ ¦ |]| -674 ¦ ] -675 ] -676 env:&:environment <- new-programming-environment resources, screen, [foo] -677 render-all screen, env, render -678 # run the sandbox -679 assume-console [ -680 ¦ press F4 -681 ] -682 run [ -683 ¦ event-loop screen, console, env, resources -684 ] -685 screen-should-contain [ -686 ¦ . errors found (0) run (F4) . -687 ¦ .recipe foo [ ╎ . -688 ¦ . { ╎─────────────────────────────────────────────────. -689 ¦ . loop ╎0 edit copy to recipe delete . -690 ¦ . } ╎foo . -691 ¦ .] ╎took too long! . -692 ¦ . ╎─────────────────────────────────────────────────. -693 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -694 ¦ . ╎ . -695 ] -696 ] -697 -698 scenario sandbox-with-errors-shows-trace [ -699 local-scope -700 trace-until 100/app # trace too long -701 assume-screen 100/width, 10/height -702 # generate a stash and a error -703 assume-resources [ -704 ¦ [lesson/recipes.mu] <- [ -705 ¦ ¦ |recipe foo [| -706 ¦ ¦ | local-scope| -707 ¦ ¦ | a:num <- next-ingredient| -708 ¦ ¦ | b:num <- next-ingredient| -709 ¦ ¦ | stash [dividing by], b| -710 ¦ ¦ | _, c:num <- divide-with-remainder a, b| -711 ¦ ¦ | reply b| -712 ¦ ¦ |]| -713 ¦ ] -714 ] -715 env:&:environment <- new-programming-environment resources, screen, [foo 4, 0] -716 render-all screen, env, render -717 # run -718 assume-console [ -719 ¦ press F4 -720 ] -721 event-loop screen, console, env, resources -722 # screen prints error message -723 screen-should-contain [ -724 ¦ . errors found (0) run (F4) . -725 ¦ .recipe foo [ ╎ . -726 ¦ . local-scope ╎─────────────────────────────────────────────────. -727 ¦ . a:num <- next-ingredient ╎0 edit copy to recipe delete . -728 ¦ . b:num <- next-ingredient ╎foo 4, 0 . -729 ¦ . stash [dividing by], b ╎foo: divide by zero in '_, c:num <- divide-with-↩. -730 ¦ . _, c:num <- divide-with-remainder a, b ╎remainder a, b' . -731 ¦ . reply b ╎─────────────────────────────────────────────────. -732 ¦ .] ╎ . -733 ¦ . ╎ . -734 ] -735 # click on the call in the sandbox -736 assume-console [ -737 ¦ left-click 4, 55 -738 ] -739 run [ -740 ¦ event-loop screen, console, env, resources -741 ] -742 # screen should expand trace -743 screen-should-contain [ -744 ¦ . errors found (0) run (F4) . -745 ¦ .recipe foo [ ╎ . -746 ¦ . local-scope ╎─────────────────────────────────────────────────. -747 ¦ . a:num <- next-ingredient ╎0 edit copy to recipe delete . -748 ¦ . b:num <- next-ingredient ╎foo 4, 0 . -749 ¦ . stash [dividing by], b ╎dividing by 0 . -750 ¦ . _, c:num <- divide-with-remainder a, b ╎14 instructions run . -751 ¦ . reply b ╎foo: divide by zero in '_, c:num <- divide-with-↩. -752 ¦ .] ╎remainder a, b' . -753 ¦ . ╎─────────────────────────────────────────────────. -754 ] -755 ] +651 ] +652 ] +653 +654 scenario sandbox-can-handle-infinite-loop [ +655 local-scope +656 trace-until 100/app # trace too long +657 assume-screen 100/width, 20/height +658 # sandbox editor will trigger an infinite loop +659 assume-resources [ +660 ¦ [lesson/recipes.mu] <- [ +661 ¦ ¦ |recipe foo [| +662 ¦ ¦ | {| +663 ¦ ¦ | loop| +664 ¦ ¦ | }| +665 ¦ ¦ |]| +666 ¦ ] +667 ] +668 env:&:environment <- new-programming-environment resources, screen, [foo] +669 render-all screen, env, render +670 # run the sandbox +671 assume-console [ +672 ¦ press F4 +673 ] +674 run [ +675 ¦ event-loop screen, console, env, resources +676 ] +677 screen-should-contain [ +678 ¦ . errors found (0) run (F4) . +679 ¦ .recipe foo [ ╎ . +680 ¦ . { ╎─────────────────────────────────────────────────. +681 ¦ . loop ╎0 edit copy to recipe delete . +682 ¦ . } ╎foo . +683 ¦ .] ╎took too long! . +684 ¦ . ╎─────────────────────────────────────────────────. +685 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +686 ¦ . ╎ . +687 ] +688 ] +689 +690 scenario sandbox-with-errors-shows-trace [ +691 local-scope +692 trace-until 100/app # trace too long +693 assume-screen 100/width, 10/height +694 # generate a stash and a error +695 assume-resources [ +696 ¦ [lesson/recipes.mu] <- [ +697 ¦ ¦ |recipe foo [| +698 ¦ ¦ | local-scope| +699 ¦ ¦ | a:num <- next-ingredient| +700 ¦ ¦ | b:num <- next-ingredient| +701 ¦ ¦ | stash [dividing by], b| +702 ¦ ¦ | _, c:num <- divide-with-remainder a, b| +703 ¦ ¦ | reply b| +704 ¦ ¦ |]| +705 ¦ ] +706 ] +707 env:&:environment <- new-programming-environment resources, screen, [foo 4, 0] +708 render-all screen, env, render +709 # run +710 assume-console [ +711 ¦ press F4 +712 ] +713 event-loop screen, console, env, resources +714 # screen prints error message +715 screen-should-contain [ +716 ¦ . errors found (0) run (F4) . +717 ¦ .recipe foo [ ╎ . +718 ¦ . local-scope ╎─────────────────────────────────────────────────. +719 ¦ . a:num <- next-ingredient ╎0 edit copy to recipe delete . +720 ¦ . b:num <- next-ingredient ╎foo 4, 0 . +721 ¦ . stash [dividing by], b ╎foo: divide by zero in '_, c:num <- divide-with-↩. +722 ¦ . _, c:num <- divide-with-remainder a, b ╎remainder a, b' . +723 ¦ . reply b ╎─────────────────────────────────────────────────. +724 ¦ .] ╎ . +725 ¦ . ╎ . +726 ] +727 # click on the call in the sandbox +728 assume-console [ +729 ¦ left-click 4, 55 +730 ] +731 run [ +732 ¦ event-loop screen, console, env, resources +733 ] +734 # screen should expand trace +735 screen-should-contain [ +736 ¦ . errors found (0) run (F4) . +737 ¦ .recipe foo [ ╎ . +738 ¦ . local-scope ╎─────────────────────────────────────────────────. +739 ¦ . a:num <- next-ingredient ╎0 edit copy to recipe delete . +740 ¦ . b:num <- next-ingredient ╎foo 4, 0 . +741 ¦ . stash [dividing by], b ╎dividing by 0 . +742 ¦ . _, c:num <- divide-with-remainder a, b ╎14 instructions run . +743 ¦ . reply b ╎foo: divide by zero in '_, c:num <- divide-with-↩. +744 ¦ .] ╎remainder a, b' . +745 ¦ . ╎─────────────────────────────────────────────────. +746 ] +747 ] diff --git a/html/edit/012-editor-undo.mu.html b/html/edit/012-editor-undo.mu.html index 1f2ab3de..1dce71d9 100644 --- a/html/edit/012-editor-undo.mu.html +++ b/html/edit/012-editor-undo.mu.html @@ -1081,7 +1081,7 @@ if ('onhashchange' in window) { 1018 editor-render screen, e 1019 # scroll the page 1020 assume-console [ -1021 ¦ press page-down +1021 ¦ press page-down 1022 ] 1023 editor-event-loop screen, console, e 1024 # undo @@ -1115,7 +1115,7 @@ if ('onhashchange' in window) { 1052 editor-render screen, e 1053 # scroll the page down and up 1054 assume-console [ -1055 ¦ press page-down +1055 ¦ press page-down 1056 ¦ press ctrl-b 1057 ] 1058 editor-event-loop screen, console, e @@ -1150,8 +1150,8 @@ if ('onhashchange' in window) { 1087 editor-render screen, e 1088 # scroll the page down and up 1089 assume-console [ -1090 ¦ press page-down -1091 ¦ press page-up +1090 ¦ press page-down +1091 ¦ press page-up 1092 ] 1093 editor-event-loop screen, console, e 1094 # undo @@ -2031,10 +2031,10 @@ if ('onhashchange' in window) { 1968 ] 1969 ] 1970 -1971 after <delete-to-end-of-line-begin> [ +1971 after <delete-to-end-of-line-begin> [ 1972 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset 1973 ] -1974 before <delete-to-end-of-line-end> [ +1974 before <delete-to-end-of-line-end> [ 1975 { 1976 ¦ break-unless deleted-cells # delete failed; don't add an undo operation 1977 ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset @@ -2134,10 +2134,10 @@ if ('onhashchange' in window) { 2071 ] 2072 ] 2073 -2074 after <delete-to-start-of-line-begin> [ +2074 after <delete-to-start-of-line-begin> [ 2075 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset 2076 ] -2077 before <delete-to-start-of-line-end> [ +2077 before <delete-to-start-of-line-end> [ 2078 { 2079 ¦ break-unless deleted-cells # delete failed; don't add an undo operation 2080 ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset -- cgit 1.4.1-2-gfad0