about summary refs log tree commit diff stats
path: root/shell
diff options
context:
space:
mode:
Diffstat (limited to 'shell')
-rw-r--r--shell/environment.mu45
-rw-r--r--shell/gap-buffer.mu239
2 files changed, 284 insertions, 0 deletions
diff --git a/shell/environment.mu b/shell/environment.mu
index 1545f0ff..6f0718b1 100644
--- a/shell/environment.mu
+++ b/shell/environment.mu
@@ -117,6 +117,18 @@ fn edit-environment _self: (addr environment), key: grapheme, data-disk: (addr d
     compare key, 7/ctrl-g
     break-if-!=
     var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
+    compare *cursor-in-function-modal-a, 0/false
+    break-if-!=
+    # look for a word to prepopulate the modal
+    var current-word-storage: (stream byte 0x40)
+    var current-word/edi: (addr stream byte) <- address current-word-storage
+    word-at-cursor self, current-word
+    var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
+    var partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
+    clear-gap-buffer partial-function-name
+    load-gap-buffer-from-stream partial-function-name, current-word
+    # enable the modal
+    var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
     copy-to *cursor-in-function-modal-a, 1/true
     return
   }
@@ -186,6 +198,39 @@ fn edit-environment _self: (addr environment), key: grapheme, data-disk: (addr d
   edit-sandbox sandbox, key, globals, data-disk, 1/tweak-real-screen
 }
 
+fn word-at-cursor _self: (addr environment), out: (addr stream byte) {
+  var self/esi: (addr environment) <- copy _self
+  var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
+  compare *cursor-in-function-modal-a, 0/false
+  {
+    break-if-=
+    # cursor in function modal
+    return
+  }
+  var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
+  compare *cursor-in-globals-a, 0/false
+  {
+    break-if-=
+    # cursor in some function editor
+    var globals/eax: (addr global-table) <- get self, globals
+    var cursor-index-addr/ecx: (addr int) <- get globals, cursor-index
+    var cursor-index/ecx: int <- copy *cursor-index-addr
+    var globals-data-ah/eax: (addr handle array global) <- get globals, data
+    var globals-data/eax: (addr array global) <- lookup *globals-data-ah
+    var cursor-offset/ecx: (offset global) <- compute-offset globals-data, cursor-index
+    var curr-global/eax: (addr global) <- index globals-data, cursor-offset
+    var curr-global-data-ah/eax: (addr handle gap-buffer) <- get curr-global, input
+    var curr-global-data/eax: (addr gap-buffer) <- lookup *curr-global-data-ah
+    word-at-gap curr-global-data, out
+    return
+  }
+  # cursor in sandbox
+  var sandbox/ecx: (addr sandbox) <- get self, sandbox
+  var sandbox-data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
+  var sandbox-data/eax: (addr gap-buffer) <- lookup *sandbox-data-ah
+  word-at-gap sandbox-data, out
+}
+
 fn render-function-modal screen: (addr screen), _self: (addr environment) {
   var self/esi: (addr environment) <- copy _self
   var width/eax: int <- copy 0
diff --git a/shell/gap-buffer.mu b/shell/gap-buffer.mu
index c2f9b3b2..9b4c4faf 100644
--- a/shell/gap-buffer.mu
+++ b/shell/gap-buffer.mu
@@ -134,6 +134,245 @@ fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) {
   }
 }
 
+fn word-at-gap _self: (addr gap-buffer), out: (addr stream byte) {
+  var self/esi: (addr gap-buffer) <- copy _self
+  clear-stream out
+  var left/ecx: (addr grapheme-stack) <- get self, left
+  var left-index/eax: int <- top-most-word left
+  emit-stack-from-index left, left-index, out
+  draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen "|" 7/fg 0/bg
+  var right/ecx: (addr grapheme-stack) <- get self, right
+  var right-index/eax: int <- top-most-word right
+  draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, right-index, 4/fg 0/bg
+  emit-stack-to-index right, right-index, out
+}
+
+fn test-word-at-gap-single-word-with-gap-at-end {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "abc"
+  # gap is at end (right is empty)
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "abc", "F - test-word-at-gap-single-word-with-gap-at-end"
+}
+
+fn test-word-at-gap-single-word-with-gap-at-start {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "abc"
+  gap-to-start g
+  #
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "abc", "F - test-word-at-gap-single-word-with-gap-at-start"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-end {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "abc "
+  # gap is at end (right is empty)
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-end"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-start {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, " abc"
+  gap-to-start g
+  #
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  rewind-stream out
+  draw-stream-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, out, 5/fg 0/bg
+  check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-start"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-end {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "a bc d"
+  # gap is at end (right is empty)
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "d", "F - test-word-at-gap-multiple-words-with-gap-at-end"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-initial-word {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "a bc d"
+  gap-to-start g
+  #
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "a", "F - test-word-at-gap-multiple-words-with-gap-at-initial-word"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-final-word {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "a bc d"
+  var dummy/eax: grapheme <- gap-left g
+  # gap is at final word
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "d", "F - test-word-at-gap-multiple-words-with-gap-at-final-word"
+}
+
+fn test-word-at-gap-multiple-words-with-gap-at-final-non-word {
+  var _g: gap-buffer
+  var g/esi: (addr gap-buffer) <- address _g
+  initialize-gap-buffer-with g, "abc "
+  var dummy/eax: grapheme <- gap-left g
+  # gap is at final word
+  var out-storage: (stream byte 0x10)
+  var out/eax: (addr stream byte) <- address out-storage
+  word-at-gap g, out
+  check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-final-non-word"
+}
+
+fn top-most-word _self: (addr grapheme-stack) -> _/eax: int {
+  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 *top-addr
+  i <- decrement
+  {
+    compare i, 0
+    break-if-<
+    var g/edx: (addr grapheme) <- index data, i
+    {
+      var foo/eax: int <- copy *g
+      draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg 0/bg
+    }
+    var is-word?/eax: boolean <- is-ascii-word-grapheme? *g
+    {
+      var foo/eax: int <- copy is-word?
+      draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 1/fg 0/bg
+    }
+    compare is-word?, 0/false
+    break-if-=
+    i <- decrement
+    loop
+  }
+  i <- increment
+  return i
+}
+
+fn bottom-most-word _self: (addr grapheme-stack) -> _/eax: int {
+  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->=
+    var g/edx: (addr grapheme) <- index data, i
+    {
+      var foo/eax: int <- copy *g
+      draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 4/fg 0/bg
+    }
+    var is-word?/eax: boolean <- is-ascii-word-grapheme? *g
+    compare is-word?, 0/false
+    break-if-=
+    i <- decrement
+    loop
+  }
+  return i
+}
+
+fn emit-stack-from-index _self: (addr grapheme-stack), start: int, out: (addr stream byte) {
+  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 start
+  {
+    compare i, *top-addr
+    break-if->=
+    var g/edx: (addr grapheme) <- index data, i
+    write-grapheme out, *g
+    i <- increment
+    loop
+  }
+}
+
+fn emit-stack-to-index _self: (addr grapheme-stack), end: int, out: (addr stream byte) {
+  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
+  draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, i, 3/fg 0/bg
+  i <- decrement
+  {
+    compare i, 0
+    break-if-<
+    compare i, end
+    break-if-<
+    var g/edx: (addr grapheme) <- index data, i
+    write-grapheme out, *g
+    i <- decrement
+    loop
+  }
+}
+
+fn is-ascii-word-grapheme? g: grapheme -> _/eax: boolean {
+  compare g, 0x21/!
+  {
+    break-if-!=
+    return 1/true
+  }
+  compare g, 0x3f/?
+  {
+    break-if-!=
+    return 1/true
+  }
+  compare g, 0x41/A
+  {
+    break-if->=
+    return 0/false
+  }
+  compare g, 0x5a/Z
+  {
+    break-if->=
+    return 1/true
+  }
+  compare g, 0x5f/_
+  {
+    break-if-!=
+    return 1/true
+  }
+  compare g, 0x61/a
+  {
+    break-if->=
+    return 0/false
+  }
+  compare g, 0x7a/z
+  {
+    break-if->=
+    return 1/true
+  }
+  return 0/false
+}
+
 # We implicitly render everything editable in a single color, and assume the
 # cursor is a single other color.
 fn render-gap-buffer-wrapping-right-then-down screen: (addr screen), _gap: (addr gap-buffer), xmin: int, ymin: int, xmax: int, ymax: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {