about summary refs log tree commit diff stats
path: root/edit
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-06-08 10:16:32 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-06-08 10:16:32 -0700
commit46824f3ee296778a40ed6ee1864928f587d35f82 (patch)
tree1fffecc0840b3d410aab6c9d4aef472939190603 /edit
parentb9a78a84cfee93db9f5bc59dfda135f43e38a9b3 (diff)
downloadmu-46824f3ee296778a40ed6ee1864928f587d35f82.tar.gz
3038 - track down a long-standing bug
In some rare situations the editor would join a line with the next when
it should simply wrap to the next screen row. Thanks Caleb and Ella
Couch for finally running into a situation that was easy to reproduce.

The scenario diffs are misleading on this commit. I had to:

a) delete the obsolete 'editor-wraps-cursor-after-inserting-characters'
because it was written back when a line just large enough to fit in a
single line would not wrap:

   |     |  <-- screen boundary
    abcde

These days it will wrap after making room for the wrap indicator:

   |     |  <-- screen boundary
    abcd↩
    e

b) rename editor-wraps-cursor-after-inserting-characters-2 to
editor-wraps-cursor-after-inserting-characters-in-middle-of-line

c) create a new scenario demonstrating the bug:
editor-wraps-cursor-after-inserting-characters-at-end-of-line
Diffstat (limited to 'edit')
-rw-r--r--edit/002-typing.mu81
1 files changed, 56 insertions, 25 deletions
diff --git a/edit/002-typing.mu b/edit/002-typing.mu
index 47743404..effdf5ae 100644
--- a/edit/002-typing.mu
+++ b/edit/002-typing.mu
@@ -691,12 +691,40 @@ defg]
 after <insert-character-special-case> [
   # if the line wraps at the cursor, move cursor to start of next row
   {
-    # if we're at the column just before the wrap indicator
-    wrap-column:number <- subtract right, 1
+    # if either:
+    # a) we're at the end of the line and at the column of the wrap indicator, or
+    # b) we're not at end of line and just before the column of the wrap indicator
+    wrap-column:number <- copy right
+    before-wrap-column:number <- subtract wrap-column, 1
     at-wrap?:boolean <- greater-or-equal cursor-column, wrap-column
-    break-unless at-wrap?
-    cursor-column <- subtract cursor-column, wrap-column
-    cursor-column <- add cursor-column, left
+    just-before-wrap?:boolean <- greater-or-equal cursor-column, before-wrap-column
+    next:address:duplex-list:character <- next before-cursor
+    # at end of line? next == 0 || next.value == 10/newline
+    at-end-of-line?:boolean <- equal next, 0
+    {
+      break-if at-end-of-line?
+      next-character:character <- get *next, value:offset
+      at-end-of-line? <- equal next-character, 10/newline
+    }
+    # break unless ((eol? and at-wrap?) or (~eol? and just-before-wrap?))
+    move-cursor-to-next-line?:boolean <- copy 0/false
+    {
+      break-if at-end-of-line?
+      move-cursor-to-next-line? <- copy just-before-wrap?
+      # if we're moving the cursor because it's in the middle of a wrapping
+      # line, adjust it to left-most column
+      potential-new-cursor-column:number <- copy left
+    }
+    {
+      break-unless at-end-of-line?
+      move-cursor-to-next-line? <- copy at-wrap?
+      # if we're moving the cursor because it's at the end of a wrapping line,
+      # adjust it to one past the left-most column to make room for the
+      # newly-inserted wrap-indicator
+      potential-new-cursor-column:number <- add left, 1/make-room-for-wrap-indicator
+    }
+    break-unless move-cursor-to-next-line?
+    cursor-column <- copy potential-new-cursor-column
     *editor <- put *editor, cursor-column:offset, cursor-column
     cursor-row <- add cursor-row, 1
     *editor <- put *editor, cursor-row:offset, cursor-row
@@ -711,12 +739,12 @@ after <insert-character-special-case> [
   }
 ]
 
-scenario editor-wraps-cursor-after-inserting-characters [
+scenario editor-wraps-cursor-after-inserting-characters-in-middle-of-line [
   assume-screen 10/width, 5/height
   1:address:array:character <- new [abcde]
   2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
   assume-console [
-    left-click 1, 4  # line is full; no wrap icon yet
+    left-click 1, 3  # right before the wrap icon
     type [f]
   ]
   run [
@@ -726,40 +754,43 @@ scenario editor-wraps-cursor-after-inserting-characters [
   ]
   screen-should-contain [
     .          .
-    .abcd↩     .
-    .fe        .
+    .abcf↩     .
+    .de        .
     .┈┈┈┈┈     .
     .          .
   ]
   memory-should-contain [
     3 <- 2  # cursor row
-    4 <- 1  # cursor column
+    4 <- 0  # cursor column
   ]
 ]
 
-scenario editor-wraps-cursor-after-inserting-characters-2 [
+scenario editor-wraps-cursor-after-inserting-characters-at-end-of-line [
+  local-scope
   assume-screen 10/width, 5/height
-  1:address:array:character <- new [abcde]
-  2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
+  # create an editor containing two lines
+  contents:address:array:character <- new [abc
+xyz]
+  1:address:editor-data/raw <- new-editor contents, screen, 0/left, 5/right
+  screen-should-contain [
+    .          .
+    .abc       .
+    .xyz       .
+    .          .
+  ]
   assume-console [
-    left-click 1, 3  # right before the wrap icon
-    type [f]
+    left-click 1, 4  # at end of first line
+    type [de]  # trigger wrap
   ]
   run [
-    editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
-    3:number <- get *2:address:editor-data, cursor-row:offset
-    4:number <- get *2:address:editor-data, cursor-column:offset
+    editor-event-loop screen:address:screen, console:address:console, 1:address:editor-data/raw
   ]
   screen-should-contain [
     .          .
-    .abcf↩     .
-    .de        .
+    .abcd↩     .
+    .e         .
+    .xyz       .
     .┈┈┈┈┈     .
-    .          .
-  ]
-  memory-should-contain [
-    3 <- 2  # cursor row
-    4 <- 0  # cursor column
   ]
 ]