about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-08-27 00:26:57 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-08-27 00:26:57 -0700
commita4f5644776543e1e1211028d18f67b9164255155 (patch)
treee3d8d7892ed757675c083a8fa50e345340b9683f
parent7b4ed5cabed39f6d5afd8fabdadafcef5572654a (diff)
downloadmu-a4f5644776543e1e1211028d18f67b9164255155.tar.gz
2084
-rw-r--r--065duplex_list.mu59
-rw-r--r--edit.mu178
2 files changed, 213 insertions, 24 deletions
diff --git a/065duplex_list.mu b/065duplex_list.mu
index 17428862..3310400d 100644
--- a/065duplex_list.mu
+++ b/065duplex_list.mu
@@ -371,15 +371,72 @@ scenario removing-from-singleton-list [
 # l:address:duplex-list <- remove-duplex-between start:address:duplex-list, end:address:duplex-list
 # Remove values between 'start' and 'end' (both exclusive). Returns some valid
 # pointer into the rest of the list.
+# Also clear pointers back out from start/end for hygiene.
 recipe remove-duplex-between [
   local-scope
   start:address:duplex-list <- next-ingredient
   end:address:duplex-list <- next-ingredient
   reply-unless start, start
+  # start->next->prev = 0
+  # start->next = end
   next:address:address:duplex-list <- get-address *start, next:offset
+  prev:address:address:duplex-list <- get-address **next, prev:offset
+  *prev <- copy 0
   *next <- copy end
   reply-unless end, start
-  prev:address:address:duplex-list <- get-address *end, prev:offset
+  # end->prev->next = 0
+  # end->prev = start
+  prev <- get-address *end, prev:offset
+  next <- get-address **prev, next:offset
+  *next <- copy 0
   *prev <- copy start
   reply start
 ]
+
+# l:address:duplex-list <- insert-duplex-range in:address:duplex-list, new:address:duplex-list
+# Inserts list beginning at 'new' after 'in'. Returns some pointer into the list.
+recipe insert-duplex-range [
+  local-scope
+  in:address:duplex-list <- next-ingredient
+  start:address:duplex-list <- next-ingredient
+  reply-unless in, in
+  reply-unless start, in
+  end:address:duplex-list <- copy start
+  {
+    next:address:duplex-list <- next-duplex end
+    break-unless next
+    end <- copy next
+    loop
+  }
+  next:address:duplex-list <- next-duplex in
+  dest:address:address:duplex-list <- get-address *end, next:offset
+  *dest <- copy next
+  dest <- get-address *next, prev:offset
+  *dest <- copy end
+  dest <- get-address *in, next:offset
+  *dest <- copy start
+  dest <- get-address *start, prev:offset
+  *dest <- copy in
+  reply in
+]
+
+# helper for debugging
+recipe dump-duplex-from [
+  local-scope
+  x:address:duplex-list <- next-ingredient
+  $print x, [: ]
+  {
+    break-unless x
+    c:character <- get *x, value:offset
+    $print c, [ ]
+    x <- next-duplex x
+    {
+      is-newline?:boolean <- equal c, 10/newline
+      break-unless is-newline?
+      $print 10/newline
+      $print x, [: ]
+    }
+    loop
+  }
+  $print 10/newline, [---], 10/newline
+]
diff --git a/edit.mu b/edit.mu
index c4b153f7..3e643fa9 100644
--- a/edit.mu
+++ b/edit.mu
@@ -2415,27 +2415,6 @@ ghi]
   ]
 ]
 
-# helper for debugging
-recipe dump-editor-from-cursor [
-  local-scope
-  x:address:duplex-list <- next-ingredient
-  $print x, [: ]
-  {
-    break-unless x
-    c:character <- get *x, value:offset
-    $print c, [ ]
-    x <- next-duplex x
-    {
-      is-newline?:boolean <- equal c, 10/newline
-      break-unless is-newline?
-      $print 10/newline
-      $print x, [: ]
-    }
-    loop
-  }
-  $print 10/newline, [---], 10/newline
-]
-
 # down arrow
 
 scenario editor-moves-to-next-line-with-down-arrow [
@@ -6563,14 +6542,32 @@ after +handle-special-character [
     break-unless *undo
     op:address:operation <- first *undo
     *undo <- rest *undo
+    redo:address:address:list <- get-address *editor, redo:offset
+    *redo <- push op, *redo
     +handle-undo
     reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
   }
 ]
 
+# ctrl-y - redo operation
+after +handle-special-character [
+  {
+    ctrl-y?:boolean <- equal *c, 25/ctrl-y
+    break-unless ctrl-y?
+    redo:address:address:list <- get-address *editor, redo:offset
+    break-unless *redo
+    op:address:operation <- first *redo
+    *redo <- rest *redo
+    undo:address:address:list <- get-address *editor, undo:offset
+    *undo <- push op, *undo
+    +handle-redo
+    reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
+  }
+]
+
 # undo typing
 
-scenario editor-undo-type [
+scenario editor-undo-typing [
   # create an editor and type a character
   assume-screen 10/width, 5/height
   1:address:array:character <- new []
@@ -6596,6 +6593,19 @@ scenario editor-undo-type [
     .┈┈┈┈┈┈┈┈┈┈.
     .          .
   ]
+  # cursor should be in the right place
+  assume-console [
+    type [1]
+  ]
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+  ]
+  screen-should-contain [
+    .          .
+    .1         .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
 ]
 
 # save operation to undo
@@ -6613,6 +6623,12 @@ before +insert-character-end [
     break-unless typing
     insert-until:address:address:duplex-list <- get-address *typing, insert-until:offset
     *insert-until <- next-duplex *before-cursor
+    after-row:address:number <- get-address *typing, after-row:offset
+    *after-row <- copy *cursor-row
+    after-column:address:number <- get-address *typing, after-column:offset
+    *after-column <- copy *cursor-column
+    after-top:address:number <- get-address *typing, after-top-of-screen:offset
+    *after-top <- get *editor, top-of-screen:offset
     jump +done-inserting-character:label
   }
   # it so happens that before-cursor is at the character we just inserted
@@ -6633,10 +6649,14 @@ after +handle-undo [
     # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
     *before-cursor <- prev-duplex start
     remove-duplex-between *before-cursor, end
+    *cursor-row <- get *typing, before-row:offset
+    *cursor-column <- get *typing, before-column:offset
+    top:address:address:duplex-list <- get *editor, top-of-screen:offset
+    *top <- get *typing, before-top-of-screen:offset
   }
 ]
 
-scenario editor-undo-type-multiple [
+scenario editor-undo-typing-multiple [
   # create an editor and type multiple characters
   assume-screen 10/width, 5/height
   1:address:array:character <- new []
@@ -6664,6 +6684,118 @@ scenario editor-undo-type-multiple [
   ]
 ]
 
+scenario editor-undo-typing-multiple-2 [
+  # create an editor with some text
+  assume-screen 10/width, 5/height
+  1:address:array:character <- new [a]
+  2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right
+  editor-render screen, 2:address:editor-data
+  # type some characters
+  assume-console [
+    type [012]
+  ]
+  editor-event-loop screen:address, console:address, 2:address:editor-data
+  screen-should-contain [
+    .          .
+    .012a      .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+  # now undo
+  assume-console [
+    type [z]  # ctrl-z
+  ]
+  3:event/ctrl-z <- merge 0/text, 26/ctrl-z, 0/dummy, 0/dummy
+  replace-in-console 122/z, 3:event/ctrl-z
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+  ]
+  # back to original text
+  screen-should-contain [
+    .          .
+    .a         .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+  # cursor should be in the right place
+  assume-console [
+    type [3]
+  ]
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+  ]
+  screen-should-contain [
+    .          .
+    .3a        .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+]
+
+scenario editor-redo-typing [
+  # create an editor, type something, undo
+  assume-screen 10/width, 5/height
+  1:address:array:character <- new [a]
+  2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right
+  editor-render screen, 2:address:editor-data
+  assume-console [
+    type [012]
+    type [z]  # ctrl-z
+  ]
+  3:event/ctrl-z <- merge 0/text, 26/ctrl-z, 0/dummy, 0/dummy
+  replace-in-console 122/z, 3:event/ctrl-z
+  editor-event-loop screen:address, console:address, 2:address:editor-data
+  screen-should-contain [
+    .          .
+    .a         .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+  # redo
+  assume-console [
+    type [y]  # ctrl-y
+  ]
+  4:event/ctrl-y <- merge 0/text, 25/ctrl-y, 0/dummy, 0/dummy
+  replace-in-console 121/y, 4:event/ctrl-y
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+  ]
+  # all characters must be back
+  screen-should-contain [
+    .          .
+    .012a      .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+  # cursor should be in the right place
+  assume-console [
+    type [3]
+  ]
+  run [
+    editor-event-loop screen:address, console:address, 2:address:editor-data
+  ]
+  screen-should-contain [
+    .          .
+    .0123a     .
+    .┈┈┈┈┈┈┈┈┈┈.
+    .          .
+  ]
+]
+
+after +handle-redo [
+  {
+    typing:address:insert-operation <- maybe-convert *op, typing:variant
+    break-unless typing
+    insert-from:address:duplex-list <- get *typing, insert-from:offset
+    # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
+    insert-duplex-range *before-cursor, insert-from
+    *cursor-row <- get *typing, after-row:offset
+    *cursor-column <- get *typing, after-column:offset
+    top:address:address:duplex-list <- get *editor, top-of-screen:offset
+    *top <- get *typing, after-top-of-screen:offset
+  }
+]
+
 # todo:
 # operations for recipe side and each sandbox-data
 # undo delete sandbox as a separate primitive on the status bar