about summary refs log tree commit diff stats
path: root/501draw-text.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-03-03 22:09:50 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-03-03 22:21:03 -0800
commit71e4f3812982dba2efb471283d310224e8db363e (patch)
treeea111a1acb8b8845dbda39c0e1b4bac1d198143b /501draw-text.mu
parentc6b928be29ac8cdb4e4d6e1eaa20420ff03e5a4c (diff)
downloadmu-71e4f3812982dba2efb471283d310224e8db363e.tar.gz
7842 - new directory organization
Baremetal is now the default build target and therefore has its sources
at the top-level. Baremetal programs build using the phase-2 Mu toolchain
that requires a Linux kernel. This phase-2 codebase which used to be at
the top-level is now under the linux/ directory. Finally, the phase-2 toolchain,
while self-hosting, has a way to bootstrap from a C implementation, which
is now stored in linux/bootstrap. The bootstrap C implementation uses some
literate programming tools that are now in linux/bootstrap/tools.

So the whole thing has gotten inverted. Each directory should build one
artifact and include the main sources (along with standard library). Tools
used for building it are relegated to sub-directories, even though those
tools are often useful in their own right, and have had lots of interesting
programs written using them.

A couple of things have gotten dropped in this process:
  - I had old ways to run on just a Linux kernel, or with a Soso kernel.
    No more.
  - I had some old tooling for running a single test at the cursor. I haven't
    used that lately. Maybe I'll bring it back one day.

The reorg isn't done yet. Still to do:
  - redo documentation everywhere. All the README files, all other markdown,
    particularly vocabulary.md.
  - clean up how-to-run comments at the start of programs everywhere
  - rethink what to do with the html/ directory. Do we even want to keep
    supporting it?

In spite of these shortcomings, all the scripts at the top-level, linux/
and linux/bootstrap are working. The names of the scripts also feel reasonable.
This is a good milestone to take stock at.
Diffstat (limited to '501draw-text.mu')
-rw-r--r--501draw-text.mu466
1 files changed, 466 insertions, 0 deletions
diff --git a/501draw-text.mu b/501draw-text.mu
new file mode 100644
index 00000000..9b207361
--- /dev/null
+++ b/501draw-text.mu
@@ -0,0 +1,466 @@
+# some primitives for moving the cursor without making assumptions about
+# raster order
+fn move-cursor-left screen: (addr screen) {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  compare cursor-x, 0
+  {
+    break-if->
+    return
+  }
+  cursor-x <- decrement
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn move-cursor-right screen: (addr screen) {
+  var _width/eax: int <- copy 0
+  var dummy/ecx: int <- copy 0
+  _width, dummy <- screen-size screen
+  var limit/edx: int <- copy _width
+  limit <- decrement
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  compare cursor-x, limit
+  {
+    break-if-<
+    return
+  }
+  cursor-x <- increment
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn move-cursor-up screen: (addr screen) {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  compare cursor-y, 0
+  {
+    break-if->
+    return
+  }
+  cursor-y <- decrement
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn move-cursor-down screen: (addr screen) {
+  var dummy/eax: int <- copy 0
+  var _height/ecx: int <- copy 0
+  dummy, _height <- screen-size screen
+  var limit/edx: int <- copy _height
+  limit <- decrement
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  compare cursor-y, limit
+  {
+    break-if-<
+    return
+  }
+  cursor-y <- increment
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn move-cursor-to-start-of-next-line screen: (addr screen) {
+  var dummy/eax: int <- copy 0
+  var _height/ecx: int <- copy 0
+  dummy, _height <- screen-size screen
+  var limit/edx: int <- copy _height
+  limit <- decrement
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  compare cursor-y, limit
+  {
+    break-if-<
+    return
+  }
+  cursor-y <- increment
+  cursor-x <- copy 0
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn draw-grapheme-at-cursor screen: (addr screen), g: grapheme, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  draw-grapheme screen, g, cursor-x, cursor-y, color, background-color
+}
+
+# we can't really render non-ASCII yet, but when we do we'll be ready
+fn draw-code-point-at-cursor screen: (addr screen), c: code-point, color: int, background-color: int {
+  var g/eax: grapheme <- copy c
+  draw-grapheme-at-cursor screen, g, color, background-color
+}
+
+# draw a single line of text from x, y to xmax
+# return the next 'x' coordinate
+# if there isn't enough space, truncate
+fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write stream, text
+  var xcurr/eax: int <- draw-stream-rightward screen, stream, x, xmax, y, color, background-color
+  return xcurr
+}
+
+# draw a single-line stream from x, y to xmax
+# return the next 'x' coordinate
+# if there isn't enough space, truncate
+fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
+  var xcurr/ecx: int <- copy x
+  {
+    var g/eax: grapheme <- read-grapheme stream
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    draw-grapheme screen, g, xcurr, y, color, background-color
+    xcurr <- increment
+    loop
+  }
+  set-cursor-position screen, xcurr, y
+  return xcurr
+}
+
+fn draw-text-rightward-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  width, height <- screen-size screen
+  var result/eax: int <- draw-text-rightward screen, text, x, width, y, color, background-color
+  return result
+}
+
+fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  cursor-x <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color, background-color
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn render-grapheme screen: (addr screen), g: grapheme, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  compare g, 0xa/newline
+  var x/eax: int <- copy x
+  {
+    break-if-!=
+    # minimum effort to clear cursor
+    draw-code-point screen, 0x20/space, x, y, color, background-color
+    x <- copy xmin
+    increment y
+    return x, y
+  }
+  draw-grapheme screen, g, x, y, color, background-color
+  x <- increment
+  compare x, xmax
+  {
+    break-if-<
+    x <- copy xmin
+    increment y
+  }
+  return x, y
+}
+
+# draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+# return the next (x, y) coordinate in raster order where drawing stopped
+# that way the caller can draw more if given the same min and max bounding-box.
+# if there isn't enough space, truncate
+fn draw-text-wrapping-right-then-down screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write stream, text
+  var x/eax: int <- copy _x
+  var y/ecx: int <- copy _y
+  x, y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
+  return x, y
+}
+
+# draw a stream in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+# return the next (x, y) coordinate in raster order where drawing stopped
+# that way the caller can draw more if given the same min and max bounding-box.
+# if there isn't enough space, truncate
+fn draw-stream-wrapping-right-then-down screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var xcurr/eax: int <- copy x
+  var ycurr/ecx: int <- copy y
+  var g/ebx: grapheme <- copy 0
+  {
+    {
+      var _g/eax: grapheme <- read-grapheme stream
+      g <- copy _g
+    }
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    xcurr, ycurr <- render-grapheme screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
+    loop
+  }
+  set-cursor-position screen, xcurr, ycurr
+  return xcurr, ycurr
+}
+
+fn move-cursor-rightward-and-downward screen: (addr screen), xmin: int, xmax: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  cursor-x <- increment
+  compare cursor-x, xmax
+  {
+    break-if-<
+    cursor-x <- copy xmin
+    cursor-y <- increment
+  }
+  set-cursor-position screen, cursor-x, cursor-y
+}
+
+fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var x2/eax: int <- copy 0
+  var y2/ecx: int <- copy 0
+  x2, y2 <- screen-size screen  # width, height
+  x2, y2 <- draw-text-wrapping-right-then-down screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
+  return x2, y2  # cursor-x, cursor-y
+}
+
+fn draw-text-wrapping-right-then-down-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  var end-x/edx: int <- copy cursor-x
+  end-x <- increment
+  compare end-x, xmax
+  {
+    break-if-<
+    cursor-x <- copy xmin
+    cursor-y <- increment
+  }
+  cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
+}
+
+fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  width, height <- screen-size screen
+  draw-text-wrapping-right-then-down-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
+}
+
+fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write-int32-hex stream, n
+  var xcurr/edx: int <- copy x
+  var ycurr/ecx: int <- copy y
+  {
+    var g/eax: grapheme <- read-grapheme stream
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    draw-grapheme screen, g, xcurr, ycurr, color, background-color
+    xcurr <- increment
+    compare xcurr, xmax
+    {
+      break-if-<
+      xcurr <- copy xmin
+      ycurr <- increment
+    }
+    loop
+  }
+  set-cursor-position screen, xcurr, ycurr
+  return xcurr, ycurr
+}
+
+fn draw-int32-hex-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var x2/eax: int <- copy 0
+  var y2/ecx: int <- copy 0
+  x2, y2 <- screen-size screen  # width, height
+  x2, y2 <- draw-int32-hex-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
+  return x2, y2  # cursor-x, cursor-y
+}
+
+fn draw-int32-hex-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  var end-x/edx: int <- copy cursor-x
+  end-x <- increment
+  compare end-x, xmax
+  {
+    break-if-<
+    cursor-x <- copy xmin
+    cursor-y <- increment
+  }
+  cursor-x, cursor-y <- draw-int32-hex-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
+}
+
+fn draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  width, height <- screen-size screen
+  draw-int32-hex-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
+}
+
+fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write-int32-decimal stream, n
+  var xcurr/edx: int <- copy x
+  var ycurr/ecx: int <- copy y
+  {
+    var g/eax: grapheme <- read-grapheme stream
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    draw-grapheme screen, g, xcurr, ycurr, color, background-color
+    xcurr <- increment
+    compare xcurr, xmax
+    {
+      break-if-<
+      xcurr <- copy xmin
+      ycurr <- increment
+    }
+    loop
+  }
+  set-cursor-position screen, xcurr, ycurr
+  return xcurr, ycurr
+}
+
+fn draw-int32-decimal-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var x2/eax: int <- copy 0
+  var y2/ecx: int <- copy 0
+  x2, y2 <- screen-size screen  # width, height
+  x2, y2 <- draw-int32-decimal-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
+  return x2, y2  # cursor-x, cursor-y
+}
+
+fn draw-int32-decimal-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  var end-x/edx: int <- copy cursor-x
+  end-x <- increment
+  compare end-x, xmax
+  {
+    break-if-<
+    cursor-x <- copy xmin
+    cursor-y <- increment
+  }
+  cursor-x, cursor-y <- draw-int32-decimal-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
+}
+
+fn draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  width, height <- screen-size screen
+  draw-int32-decimal-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
+}
+
+## Text direction: down then right
+
+# draw a single line of text vertically from x, y to ymax
+# return the next 'y' coordinate
+# if there isn't enough space, truncate
+fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write stream, text
+  var ycurr/eax: int <- draw-stream-downward screen, stream, x, y, ymax, color, background-color
+  return ycurr
+}
+
+# draw a single-line stream vertically from x, y to ymax
+# return the next 'y' coordinate
+# if there isn't enough space, truncate
+fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
+  var ycurr/ecx: int <- copy y
+  {
+    var g/eax: grapheme <- read-grapheme stream
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    draw-grapheme screen, g, x, ycurr, color, background-color
+    ycurr <- increment
+    loop
+  }
+  set-cursor-position screen, x, ycurr
+  return ycurr
+}
+
+fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color, background-color
+}
+
+# draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+# return the next (x, y) coordinate in raster order where drawing stopped
+# that way the caller can draw more if given the same min and max bounding-box.
+# if there isn't enough space, truncate
+fn draw-text-wrapping-down-then-right screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var stream-storage: (stream byte 0x100)
+  var stream/esi: (addr stream byte) <- address stream-storage
+  write stream, text
+  var x/eax: int <- copy _x
+  var y/ecx: int <- copy _y
+  x, y <- draw-stream-wrapping-down-then-right screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
+  return x, y
+}
+
+# draw a stream down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
+# return the next (x, y) coordinate in raster order where drawing stopped
+# that way the caller can draw more if given the same min and max bounding-box.
+# if there isn't enough space, truncate
+fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var xcurr/edx: int <- copy x
+  var ycurr/ecx: int <- copy y
+  {
+    var g/eax: grapheme <- read-grapheme stream
+    compare g, 0xffffffff/end-of-file
+    break-if-=
+    draw-grapheme screen, g, xcurr, ycurr, color, background-color
+    ycurr <- increment
+    compare ycurr, ymax
+    {
+      break-if-<
+      xcurr <- increment
+      ycurr <- copy ymin
+    }
+    loop
+  }
+  set-cursor-position screen, xcurr, ycurr
+  return xcurr, ycurr
+}
+
+fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+  var x2/eax: int <- copy 0
+  var y2/ecx: int <- copy 0
+  x2, y2 <- screen-size screen  # width, height
+  x2, y2 <- draw-text-wrapping-down-then-right screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
+  return x2, y2  # cursor-x, cursor-y
+}
+
+fn draw-text-wrapping-down-then-right-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
+  var cursor-x/eax: int <- copy 0
+  var cursor-y/ecx: int <- copy 0
+  cursor-x, cursor-y <- cursor-position screen
+  var end-y/edx: int <- copy cursor-y
+  end-y <- increment
+  compare end-y, ymax
+  {
+    break-if-<
+    cursor-x <- increment
+    cursor-y <- copy ymin
+  }
+  cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
+}
+
+fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
+  var width/eax: int <- copy 0
+  var height/ecx: int <- copy 0
+  width, height <- screen-size screen
+  draw-text-wrapping-down-then-right-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
+}
+
+# hacky error-handling
+# just go into an infinite loop
+fn abort e: (addr array byte) {
+  var dummy1/eax: int <- copy 0
+  var dummy2/ecx: int <- copy 0
+  dummy1, dummy2 <- draw-text-wrapping-right-then-down-over-full-screen 0/screen, e, 0/x, 0x2f/y, 0xf/fg=white, 0xc/bg=red
+  {
+    loop
+  }
+}