about summary refs log tree commit diff stats
path: root/apps/tile/gap-buffer.mu
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-09-19 09:02:40 -0700
committerKartik Agaram <vc@akkartik.com>2020-09-19 09:02:40 -0700
commita0deaa1cb1920339b0e10cb53c8806c35ed94445 (patch)
treec304675358923b461995f47474179168a0417fa0 /apps/tile/gap-buffer.mu
parentc9093dbb083f4d96b985d87a526ac16cf9ab54a2 (diff)
downloadmu-a0deaa1cb1920339b0e10cb53c8806c35ed94445.tar.gz
6801 - snapshot: RPN structured editor
There's some worrisome memory corruption here between the call to max-stack-depth
and the callee picking up its args.

All this code is incredibly ugly as I start to wrestle with the challenges
of structured editors. I keep wanting to keep business logic separate from
rendering, but there are feedback loops from wanting to know where to render
the cursor. And I haven't even started trying to avoid full-screen renders
yet. That'll complect things even more. For now the data path for every
iteration of the render loop is:
  process key
  compute max depth needed (or any other global information needed for rendering)
  render
Diffstat (limited to 'apps/tile/gap-buffer.mu')
-rw-r--r--apps/tile/gap-buffer.mu256
1 files changed, 219 insertions, 37 deletions
diff --git a/apps/tile/gap-buffer.mu b/apps/tile/gap-buffer.mu
index 9d6b7161..1503690b 100644
--- a/apps/tile/gap-buffer.mu
+++ b/apps/tile/gap-buffer.mu
@@ -11,6 +11,22 @@ fn initialize-gap-buffer _self: (addr gap-buffer) {
   initialize-grapheme-stack right, 0x10
 }
 
+# just for tests
+fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
+  initialize-gap-buffer self
+  var stream-storage: (stream byte 0x10)
+  var stream/ecx: (addr stream byte) <- address stream-storage
+  write stream, s
+  {
+    var done?/eax: boolean <- stream-empty? stream
+    compare done?, 0  # false
+    break-if-!=
+    var g/eax: grapheme <- read-grapheme stream
+    add-grapheme-at-gap self, g
+    loop
+  }
+}
+
 fn render-gap-buffer screen: (addr screen), _gap: (addr gap-buffer) {
   var gap/esi: (addr gap-buffer) <- copy _gap
   var left/eax: (addr grapheme-stack) <- get gap, left
@@ -30,49 +46,26 @@ fn gap-buffer-length _gap: (addr gap-buffer) -> result/eax: int {
   result <- add left-length
 }
 
-# dump stack to screen from bottom to top
-# don't move the cursor or anything
-fn render-stack-from-bottom _self: (addr grapheme-stack), screen: (addr screen) {
-  var self/esi: (addr grapheme-stack) <- copy _self
-  var data-ah/edi: (addr handle array grapheme) <- get self, data
-  var _data/eax: (addr array grapheme) <- lookup *data-ah
-  var data/edi: (addr array grapheme) <- copy _data
-  var top-addr/ecx: (addr int) <- get self, top
-  var i/eax: int <- copy 0
-  {
-    compare i, *top-addr
-    break-if->=
-    var g/edx: (addr grapheme) <- index data, i
-    print-grapheme screen, *g
-    i <- increment
-    loop
-  }
+fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
+  var self/esi: (addr gap-buffer) <- copy _self
+  var left/eax: (addr grapheme-stack) <- get self, left
+  push-grapheme-stack left, g
 }
 
-# dump stack to screen from top to bottom
-# don't move the cursor or anything
-fn render-stack-from-top _self: (addr grapheme-stack), screen: (addr screen) {
-  var self/esi: (addr grapheme-stack) <- copy _self
-  var data-ah/edi: (addr handle array grapheme) <- get self, data
-  var _data/eax: (addr array grapheme) <- lookup *data-ah
-  var data/edi: (addr array grapheme) <- copy _data
-  var top-addr/ecx: (addr int) <- get self, top
-  var i/eax: int <- copy *top-addr
-  i <- decrement
+fn gap-to-start self: (addr gap-buffer) {
   {
-    compare i, 0
-    break-if-<
-    var g/edx: (addr grapheme) <- index data, i
-    print-grapheme screen, *g
-    i <- decrement
-    loop
+    var curr/eax: grapheme <- gap-left self
+    compare curr, -1
+    loop-if-!=
   }
 }
 
-fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
-  var self/esi: (addr gap-buffer) <- copy _self
-  var left/eax: (addr grapheme-stack) <- get self, left
-  push-grapheme-stack left, g
+fn gap-to-end self: (addr gap-buffer) {
+  {
+    var curr/eax: grapheme <- gap-right self
+    compare curr, -1
+    loop-if-!=
+  }
 }
 
 fn gap-right _self: (addr gap-buffer) -> result/eax: grapheme {
@@ -112,6 +105,79 @@ $gap-left:body: {
 }
 }
 
+fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> result/eax: boolean {
+$gap-buffer-equal?:body: {
+  var self/esi: (addr gap-buffer) <- copy _self
+  # complication: graphemes may be multiple bytes
+  # so don't rely on length
+  # instead turn the expected result into a stream and arrange to read from it in order
+  var stream-storage: (stream byte 0x10)
+  var expected-stream/ecx: (addr stream byte) <- address stream-storage
+  write expected-stream, s
+  # compare left
+  var left/edx: (addr grapheme-stack) <- get self, left
+  result <- prefix-match? left, expected-stream
+  compare result, 0  # false
+  break-if-= $gap-buffer-equal?:body
+  # compare right
+  var right/edx: (addr grapheme-stack) <- get self, right
+  result <- suffix-match? right, expected-stream
+  compare result, 0  # false
+  break-if-= $gap-buffer-equal?:body
+  # ensure there's nothing left over
+  result <- stream-empty? expected-stream
+}
+}
+
+fn test-gap-buffer-equal-from-end? {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer g
+  #
+  var c/eax: grapheme <- copy 0x61  # 'a'
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  # gap is at end (right is empty)
+  var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
+  var result/eax: int <- copy _result
+  check-ints-equal result, 1, "F - test-gap-buffer-equal-from-end?"
+}
+
+fn test-gap-buffer-equal-from-middle? {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer g
+  #
+  var c/eax: grapheme <- copy 0x61  # 'a'
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  var dummy/eax: grapheme <- gap-left g
+  # gap is in the middle
+  var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
+  var result/eax: int <- copy _result
+  check-ints-equal result, 1, "F - test-gap-buffer-equal-from-middle?"
+}
+
+fn test-gap-buffer-equal-from-start? {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer g
+  #
+  var c/eax: grapheme <- copy 0x61  # 'a'
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  add-grapheme-at-gap g, c
+  var dummy/eax: grapheme <- gap-left g
+  dummy <- gap-left g
+  dummy <- gap-left g
+  # gap is at the start
+  var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
+  var result/eax: int <- copy _result
+  check-ints-equal result, 1, "F - test-gap-buffer-equal-from-start?"
+}
+
 type grapheme-stack {
   data: (handle array grapheme)
   top: int
@@ -125,6 +191,20 @@ fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
   copy-to *top, 0
 }
 
+fn grapheme-stack-empty? _self: (addr grapheme-stack) -> result/eax: boolean {
+$grapheme-stack-empty?:body: {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var top/eax: (addr int) <- get self, top
+  compare *top, 0
+  {
+    break-if-=
+    result <- copy 1  # false
+    break $grapheme-stack-empty?:body
+  }
+  result <- copy 0  # false
+}
+}
+
 fn push-grapheme-stack _self: (addr grapheme-stack), _val: grapheme {
   var self/esi: (addr grapheme-stack) <- copy _self
   var top-addr/ecx: (addr int) <- get self, top
@@ -155,3 +235,105 @@ $pop-grapheme-stack:body: {
   val <- copy *result-addr
 }
 }
+
+# dump stack to screen from bottom to top
+# don't move the cursor or anything
+fn render-stack-from-bottom _self: (addr grapheme-stack), screen: (addr screen) {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var i/eax: int <- copy 0
+  {
+    compare i, *top-addr
+    break-if->=
+    var g/edx: (addr grapheme) <- index data, i
+    print-grapheme screen, *g
+    i <- increment
+    loop
+  }
+}
+
+# dump stack to screen from top to bottom
+# don't move the cursor or anything
+fn render-stack-from-top _self: (addr grapheme-stack), screen: (addr screen) {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var i/eax: int <- copy *top-addr
+  i <- decrement
+  {
+    compare i, 0
+    break-if-<
+    var g/edx: (addr grapheme) <- index data, i
+    print-grapheme screen, *g
+    i <- decrement
+    loop
+  }
+}
+
+# compare from bottom
+# beware: modifies 'stream', which must be disposed of after a false result
+fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> result/eax: boolean {
+$prefix-match?:body: {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/ecx: (addr int) <- get self, top
+  var i/ebx: int <- copy 0
+  {
+    compare i, *top-addr
+    break-if->=
+    # if curr != expected, return false
+    {
+      var curr-a/edx: (addr grapheme) <- index data, i
+      var expected/eax: grapheme <- read-grapheme s
+      {
+        compare expected, *curr-a
+        break-if-=
+        result <- copy 0  # false
+        break $prefix-match?:body
+      }
+    }
+    i <- increment
+    loop
+  }
+  result <- copy 1   # true
+}
+}
+
+# compare from bottom
+# beware: modifies 'stream', which must be disposed of after a false result
+fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> result/eax: boolean {
+$suffix-match?:body: {
+  var self/esi: (addr grapheme-stack) <- copy _self
+  var data-ah/edi: (addr handle array grapheme) <- get self, data
+  var _data/eax: (addr array grapheme) <- lookup *data-ah
+  var data/edi: (addr array grapheme) <- copy _data
+  var top-addr/eax: (addr int) <- get self, top
+  var i/ebx: int <- copy *top-addr
+  i <- decrement
+  {
+    compare i, 0
+    break-if-<
+    {
+      var curr-a/edx: (addr grapheme) <- index data, i
+      var expected/eax: grapheme <- read-grapheme s
+      # if curr != expected, return false
+      {
+        compare expected, *curr-a
+        break-if-=
+        result <- copy 0  # false
+        break $suffix-match?:body
+      }
+    }
+    i <- decrement
+    loop
+  }
+  result <- copy 1   # true
+}
+}