Browse Source

fix bad terminology: grapheme -> code point

Unix text-mode terminals transparently support utf-8 these days, and so
I treat utf-8 sequences (which I call graphemes in Mu) as fundamental.

I then blindly carried over this state of affairs to bare-metal Mu,
where it makes no sense. If you don't have a terminal handling
font-rendering for you, fonts are most often indexed by code points and
not utf-8 sequences.
main
Kartik K. Agaram 10 months ago
parent
commit
6e05a8fa27
  1. 81
      103glyph.subx
  2. 2
      317abort.subx
  3. 8
      400.mu
  4. 15
      403unicode.mu
  5. 80
      500fake-screen.mu
  6. 41
      501draw-text.mu
  7. 75
      504test-screen.mu
  8. 27
      513grapheme-stack.mu
  9. 4
      514gap-buffer.mu
  10. 4
      apps/colors.mu
  11. 8
      apps/rpn.mu
  12. 41
      browse-slack/environment.mu
  13. 7
      linux/403unicode.mu
  14. 2
      shell/primitives.mu
  15. 8
      shell/sandbox.mu

81
103grapheme.subx → 103glyph.subx

@ -1,4 +1,9 @@
# Use the built-in font to draw a grapheme to real screen.
# Use the built-in font to draw glyphs to screen.
# https://en.wikipedia.org/wiki/Glyph#Typography
# The Mu computer can currently only render glyphs corresponding to single
# code points. No combining characters.
# https://en.wikipedia.org/wiki/Code_point
# https://en.wikipedia.org/wiki/Combining_character
#
# We need to do this in machine code because Mu doesn't have global variables
# yet (for the start of the font).
@ -9,20 +14,20 @@
# The Mu computer's font is 8px wide and 16px tall.
# Therefore 'x' here is in [0, 128), and 'y' is in [0, 48)
# Doesn't update the cursor; where the cursor should go after printing the
# current grapheme is a higher-level concern.
draw-grapheme-on-real-screen: # g: grapheme, x: int, y: int, color: int, background-color: int -> _/eax
# current code-point is a higher-level concern.
draw-code-point-on-real-screen: # c: code-point, x: int, y: int, color: int, background-color: int -> _/eax
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(draw-grapheme-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 0x80 0x30) # => eax
$draw-grapheme-on-real-screen:end:
(draw-code-point-on-screen-buffer *Video-memory-addr *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) 0x80 0x30) # => eax
$draw-code-point-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
draw-grapheme-on-screen-array: # screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
draw-code-point-on-screen-array: # screen-data: (addr array byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
@ -39,17 +44,17 @@ draw-grapheme-on-screen-array: # screen-data: (addr array byte), g: grapheme, x
8b/-> *(ebp+0x20) 0/r32/eax
f7 4/subop/multiply-into-eax *(ebp+0x24)
81 7/subop/compare %edx 0/imm32
0f 85/jump-if-!= $draw-grapheme-on-screen-array:overflow/disp32
0f 85/jump-if-!= $draw-code-point-on-screen-array:overflow/disp32
# if (eax > ecx) abort
39/compare %eax 1/r32/ecx
0f 8f/jump-if-> $draw-grapheme-on-screen-array:abort/disp32
0f 8f/jump-if-> $draw-code-point-on-screen-array:abort/disp32
}
# eax = screen-data+4 (skip length)
8b/-> *(ebp+8) 0/r32/eax
05/add-to-eax 4/imm32
#
(draw-grapheme-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24)) # => eax
$draw-grapheme-on-screen-array:end:
(draw-code-point-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24)) # => eax
$draw-code-point-on-screen-array:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
@ -58,30 +63,30 @@ $draw-grapheme-on-screen-array:end:
5d/pop-to-ebp
c3/return
$draw-grapheme-on-screen-array:overflow:
(abort "draw-grapheme-on-screen-array: screen dimensions too large")
$draw-code-point-on-screen-array:overflow:
(abort "draw-code-point-on-screen-array: screen dimensions too large")
$draw-grapheme-on-screen-array:abort:
(abort "draw-grapheme-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
$draw-code-point-on-screen-array:abort:
(abort "draw-code-point-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
# 'buffer' here is not a valid Mu type: a naked address without a length.
# returns number of 8x16 units printed to screen (1 or 2).
draw-grapheme-on-screen-buffer: # buffer: (addr byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
draw-code-point-on-screen-buffer: # buffer: (addr byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
56/push-esi
# switch screen-width and screen-height from grapheme to pixel units
# switch screen-width and screen-height from code-point to pixel units
c1 4/subop/shift-left *(ebp+20) 3/imm8/log2-font-width
c1 4/subop/shift-left *(ebp+24) 4/imm8/log2-font-height
# esi = g
# esi = c
8b/-> *(ebp+0xc) 6/r32/esi
# if (g >= 4352) return # unicode planes supported: latin, greek, cyrillic, armenian, hebrew, arabic, syriac, thaana, n'ko, indian (iscii), sinhala, thai, lao, tibetan, myanmar, georgian
# if (c >= 4352) return # unicode planes supported: latin, greek, cyrillic, armenian, hebrew, arabic, syriac, thaana, n'ko, indian (iscii), sinhala, thai, lao, tibetan, myanmar, georgian
# next few to support: CJK, ethiopic, cherokee, ...
81 7/subop/compare %esi 0x1100/imm32
0f 8d/jump-if->= $draw-grapheme-on-screen-buffer:end/disp32
# var letter-bitmap/esi = font[g]
0f 8d/jump-if->= $draw-code-point-on-screen-buffer:end/disp32
# var letter-bitmap/esi = font[c]
69/multiply %esi 0x21/imm32/glyph-size 6/r32/esi
81 0/subop/add %esi 0x0010000c/imm32/Font # see boot.subx
# dispatch based on letter-bitmap->size
@ -91,13 +96,13 @@ draw-grapheme-on-screen-buffer: # buffer: (addr byte), g: grapheme, x: int, y:
3d/compare-eax-and 8/imm32
{
75/jump-if-!= break/disp8
(draw-narrow-grapheme-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
(draw-narrow-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
b8/copy-to-eax 1/imm32
eb/jump $draw-grapheme-on-screen-buffer:end/disp8
eb/jump $draw-code-point-on-screen-buffer:end/disp8
}
(draw-wide-grapheme-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
(draw-wide-code-point-on-screen-buffer *(ebp+8) %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
b8/copy-to-eax 2/imm32
$draw-grapheme-on-screen-buffer:end:
$draw-code-point-on-screen-buffer:end:
# . restore registers
5e/pop-to-esi
# . epilogue
@ -105,16 +110,16 @@ $draw-grapheme-on-screen-buffer:end:
5d/pop-to-ebp
c3/return
wide-grapheme?: # g: grapheme -> _/eax: boolean
wide-code-point?: # c: code-point -> _/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# eax = g
# eax = c
8b/-> *(ebp+8) 0/r32/eax
# if (g >= 128) return # characters beyond ASCII currently not supported
# if (c >= 128) return # characters beyond ASCII currently not supported
3d/compare-eax-and 0x80/imm32
0f 8d/jump-if->= $wide-grapheme?:end/disp32
# var letter-bitmap/eax = font[g]
0f 8d/jump-if->= $wide-code-point?:end/disp32
# var letter-bitmap/eax = font[c]
69/multiply %eax 0x21/imm32/glyph-size 0/r32/eax
05/add-to-eax 0x0010000c/imm32/Font # see boot.subx
# dispatch based on letter-bitmap->size
@ -122,7 +127,7 @@ wide-grapheme?: # g: grapheme -> _/eax: boolean
25/and-eax-with 0xff/imm32
3d/compare-eax-and 8/imm32
0f 95/set-if-!= %eax
$wide-grapheme?:end:
$wide-code-point?:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
@ -130,7 +135,7 @@ $wide-grapheme?:end:
# buffer: naked address to raw screen RAM without a length
# letter-bitmap: naked address to 8-pixel wide font glyph
draw-narrow-grapheme-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
draw-narrow-code-point-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
@ -163,7 +168,7 @@ draw-narrow-grapheme-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (a
#
e9/jump loop/disp32
}
$draw-narrow-grapheme-on-screen-buffer:end:
$draw-narrow-code-point-on-screen-buffer:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
@ -176,7 +181,7 @@ $draw-narrow-grapheme-on-screen-buffer:end:
# buffer: naked address to raw screen RAM without a length
# letter-bitmap: naked address to 16-pixel wide font glyph
draw-wide-grapheme-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
draw-wide-code-point-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (addr byte), x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
@ -219,7 +224,7 @@ draw-wide-grapheme-on-screen-buffer: # buffer: (addr byte), letter-bitmap: (add
#
e9/jump loop/disp32
}
$draw-wide-grapheme-on-screen-buffer:end:
$draw-wide-code-point-on-screen-buffer:end:
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
@ -260,11 +265,11 @@ draw-run-of-pixels-from-glyph: # buffer: (addr byte), glyph-byte: byte, x: int,
{
73/jump-if-not-CF break/disp8
(pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18) *(ebp+0x20) *(ebp+0x24))
eb/jump $draw-grapheme-on-screen-buffer:continue/disp8
eb/jump $draw-code-point-on-screen-buffer:continue/disp8
}
# otherwise use the background color
(pixel-on-screen-buffer *(ebp+8) %eax *(ebp+0x14) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
$draw-grapheme-on-screen-buffer:continue:
$draw-code-point-on-screen-buffer:continue:
# --x
48/decrement-eax
#
@ -318,7 +323,7 @@ $set-cursor-position-on-real-screen:end:
# tracking what was on the screen at this position before and passing it
# in again.
# - does not stop showing the cursor at this location when the cursor moves
draw-cursor-on-real-screen: # g: grapheme
draw-cursor-on-real-screen: # c: code-point
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
@ -327,7 +332,7 @@ draw-cursor-on-real-screen: # g: grapheme
51/push-ecx
#
(cursor-position-on-real-screen) # => eax, ecx
(draw-grapheme-on-real-screen *(ebp+8) %eax %ecx 0 7) # => eax
(draw-code-point-on-real-screen *(ebp+8) %eax %ecx 0 7) # => eax
$draw-cursor-on-real-screen:end:
# . restore registers
59/pop-to-ecx

2
317abort.subx

@ -311,7 +311,7 @@ draw-slice-wrapping-right-then-down-from-cursor-over-full-screen: # screen: (ad
73/jump-if-addr>= break/disp8
# print *curr
8a/byte-> *ecx 0/r32/eax
(draw-grapheme-at-cursor-over-full-screen *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18))
(draw-code-point-at-cursor-over-full-screen *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18))
#
41/increment-ecx
#

8
400.mu

@ -1,11 +1,11 @@
# screen
sig pixel-on-real-screen x: int, y: int, color: int
sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int -> _/eax: int
sig draw-grapheme-on-screen-array screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
sig wide-grapheme? g: grapheme -> _/eax: boolean
sig draw-code-point-on-real-screen c: code-point, x: int, y: int, color: int, background-color: int -> _/eax: int
sig draw-code-point-on-screen-array screen-data: (addr array byte), c: code-point, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int -> _/eax: int
sig wide-code-point? c: code-point -> _/eax: boolean
sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int
sig set-cursor-position-on-real-screen x: int, y: int
sig draw-cursor-on-real-screen g: grapheme
sig draw-cursor-on-real-screen c: code-point
sig color-rgb color: int -> _/ecx: int, _/edx: int, _/ebx: int
# timer

15
403unicode.mu

@ -7,18 +7,21 @@
# Graphemes may consist of multiple code points.
#
# Mu graphemes are always represented in utf-8, and they are required to fit
# in 4 bytes.
# in 4 bytes. (This can be confusing if you focus just on ASCII, where Mu's
# graphemes and code-points are identical.)
#
# Mu doesn't currently support combining code points, or graphemes made of
# multiple code points. One day we will.
# We also don't currently support code points that translate into multiple
# or wide graphemes. (In particular, Tab will never be supported.)
# https://en.wikipedia.org/wiki/Combining_character
fn to-code-point in: grapheme -> _/eax: code-point {
var g/eax: grapheme <- copy in
var result/eax: code-point <- copy g # TODO: support non-ASCII
return result
}
# transliterated from tb_utf8_unicode_to_char in https://github.com/nsf/termbox
# https://wiki.tcl-lang.org/page/UTF%2D8+bit+by+bit explains the algorithm
#
# The day we want to support combining characters, this function will need to
# take multiple code points. Or something.
fn to-grapheme in: code-point -> _/eax: grapheme {
var c/eax: int <- copy in
var num-trailers/ecx: int <- copy 0

80
500fake-screen.mu

@ -23,7 +23,7 @@ type screen {
}
type screen-cell {
data: grapheme
data: code-point
color: int
background-color: int
unused?: boolean
@ -89,27 +89,27 @@ fn screen-size _screen: (addr screen) -> _/eax: int, _/ecx: int {
# testable screen primitive
# return number of 8x16 units drawn
fn draw-grapheme _screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int -> _/eax: int {
fn draw-code-point _screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int -> _/eax: int {
var screen/esi: (addr screen) <- copy _screen
{
compare screen, 0
break-if-!=
var result/eax: int <- draw-grapheme-on-real-screen g, x, y, color, background-color
var result/eax: int <- draw-code-point-on-real-screen c, x, y, color, background-color
return result
}
# fake screen
var wide?/eax: boolean <- wide-grapheme? g
var wide?/eax: boolean <- wide-code-point? c
compare wide?, 0/false
{
break-if-=
draw-wide-grapheme-on-fake-screen screen, g, x, y, color, background-color
draw-wide-code-point-on-fake-screen screen, c, x, y, color, background-color
return 2
}
draw-narrow-grapheme-on-fake-screen screen, g, x, y, color, background-color
draw-narrow-code-point-on-fake-screen screen, c, x, y, color, background-color
return 1
}
fn draw-narrow-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int {
fn draw-narrow-code-point-on-fake-screen _screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int {
var screen/esi: (addr screen) <- copy _screen
# ignore if out of bounds
{
@ -145,9 +145,9 @@ fn draw-narrow-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: i
var data/eax: (addr array screen-cell) <- lookup *data-ah
var offset/ecx: (offset screen-cell) <- compute-offset data, index
var dest-cell/ecx: (addr screen-cell) <- index data, offset
var dest-grapheme/eax: (addr grapheme) <- get dest-cell, data
var g2/edx: grapheme <- copy g
copy-to *dest-grapheme, g2
var dest-code-point/eax: (addr code-point) <- get dest-cell, data
var c2/edx: code-point <- copy c
copy-to *dest-code-point, c2
var dest-color/eax: (addr int) <- get dest-cell, color
var src-color/edx: int <- copy color
copy-to *dest-color, src-color
@ -158,7 +158,7 @@ fn draw-narrow-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: i
copy-to *dest, 0/false
}
fn draw-wide-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int {
fn draw-wide-code-point-on-fake-screen _screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int {
var screen/esi: (addr screen) <- copy _screen
# ignore if out of bounds
{
@ -169,7 +169,7 @@ fn draw-wide-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: int
{
var xmax-addr/eax: (addr int) <- get screen, width
var xmax/eax: int <- copy *xmax-addr
xmax <- decrement # wide graphemes need an extra unit
xmax <- decrement # wide code-points need an extra unit
compare x, xmax
break-if-<
return
@ -193,9 +193,9 @@ fn draw-wide-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: int
var data/eax: (addr array screen-cell) <- lookup *data-ah
var offset/ecx: (offset screen-cell) <- compute-offset data, index
var dest-cell/ecx: (addr screen-cell) <- index data, offset
var dest-grapheme/eax: (addr grapheme) <- get dest-cell, data
var g2/edx: grapheme <- copy g
copy-to *dest-grapheme, g2
var dest-code-point/eax: (addr code-point) <- get dest-cell, data
var c2/edx: code-point <- copy c
copy-to *dest-code-point, c2
var dest-color/eax: (addr int) <- get dest-cell, color
var src-color/edx: int <- copy color
copy-to *dest-color, src-color
@ -217,14 +217,6 @@ fn draw-wide-grapheme-on-fake-screen _screen: (addr screen), g: grapheme, x: int
}
}
# we can't really render non-ASCII yet, but when we do we'll be ready
# return number of 8x16 units drawn
fn draw-code-point screen: (addr screen), c: code-point, x: int, y: int, color: int, background-color: int -> _/eax: int {
var g/eax: grapheme <- copy c
var result/eax: int <- draw-grapheme screen, g, x, y, color, background-color
return result
}
# fake screens only
fn screen-cell-index _screen: (addr screen), x: int, y: int -> _/ecx: int {
var screen/esi: (addr screen) <- copy _screen
@ -298,18 +290,18 @@ fn set-cursor-position _screen: (addr screen), x: int, y: int {
copy-to *dest, src
}
fn draw-cursor screen: (addr screen), g: grapheme {
fn draw-cursor screen: (addr screen), c: code-point {
{
compare screen, 0
break-if-!=
draw-cursor-on-real-screen g
draw-cursor-on-real-screen c
return
}
# fake screen
var cursor-x/eax: int <- copy 0
var cursor-y/ecx: int <- copy 0
cursor-x, cursor-y <- cursor-position screen
var dummy/eax: int <- draw-grapheme screen, g, cursor-x, cursor-y, 0/fg, 7/bg
var dummy/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, 0/fg, 7/bg
}
fn clear-screen _screen: (addr screen) {
@ -367,11 +359,11 @@ fn fake-screen-empty? _screen: (addr screen) -> _/eax: boolean {
{
compare x, *width
break-if->=
var g/eax: grapheme <- screen-grapheme-at screen, x, y
var c/eax: code-point <- screen-code-point-at screen, x, y
{
compare g, 0
compare c, 0
break-if-=
compare g, 0x20/space
compare c, 0x20/space
break-if-=
return 0/false
}
@ -506,21 +498,21 @@ fn screen-cell-unused-at-index? _screen: (addr screen), _index: int -> _/eax: bo
return *src
}
fn screen-grapheme-at _screen: (addr screen), x: int, y: int -> _/eax: grapheme {
fn screen-code-point-at _screen: (addr screen), x: int, y: int -> _/eax: code-point {
var screen/esi: (addr screen) <- copy _screen
var index/ecx: int <- screen-cell-index screen, x, y
var result/eax: grapheme <- screen-grapheme-at-index screen, index
var result/eax: code-point <- screen-code-point-at-index screen, index
return result
}
fn screen-grapheme-at-index _screen: (addr screen), _index: int -> _/eax: grapheme {
fn screen-code-point-at-index _screen: (addr screen), _index: int -> _/eax: code-point {
var screen/esi: (addr screen) <- copy _screen
var data-ah/eax: (addr handle array screen-cell) <- get screen, data
var data/eax: (addr array screen-cell) <- lookup *data-ah
var index/ecx: int <- copy _index
var offset/ecx: (offset screen-cell) <- compute-offset data, index
var cell/eax: (addr screen-cell) <- index data, offset
var src/eax: (addr grapheme) <- get cell, data
var src/eax: (addr code-point) <- get cell, data
return *src
}
@ -661,11 +653,11 @@ fn copy-pixels _screen: (addr screen), target-screen: (addr screen) {
}
}
# It turns out double-buffering graphemes is useless because rendering fonts
# It turns out double-buffering screen-cells is useless because rendering fonts
# takes too long. (At least under Qemu.)
# So we'll instead convert graphemes to pixels when double-buffering.
# So we'll instead convert screen-cells to pixels when double-buffering.
# 'screen' must be a fake screen.
fn convert-graphemes-to-pixels _screen: (addr screen) {
fn convert-screen-cells-to-pixels _screen: (addr screen) {
var screen/esi: (addr screen) <- copy _screen
var width-a/ebx: (addr int) <- get screen, width
var height-a/edx: (addr int) <- get screen, height
@ -678,25 +670,25 @@ fn convert-graphemes-to-pixels _screen: (addr screen) {
compare y, *height-a
break-if->=
var x/edi: int <- copy 0
$convert-graphemes-to-pixels:loop-x: {
$convert-screen-cells-to-pixels:loop-x: {
compare x, *width-a
break-if->=
{
var tmp/eax: grapheme <- screen-grapheme-at screen, x, y
# skip null graphemes that only get created when clearing screen
var tmp/eax: code-point <- screen-code-point-at screen, x, y
# skip null code-points that only get created when clearing screen
# there may be other pixels drawn there, and we don't want to clobber them
# this is a situation where fake screens aren't faithful to real screens; we don't support overlap between graphemes and raw pixels
# this is a situation where fake screens aren't faithful to real screens; we don't support overlap between screen-cells and raw pixels
compare tmp, 0
break-if-=
var g: grapheme
copy-to g, tmp
var c: code-point
copy-to c, tmp
var tmp/eax: int <- screen-color-at screen, x, y
var fg: int
copy-to fg, tmp
var bg/eax: int <- screen-background-color-at screen, x, y
var offset/eax: int <- draw-grapheme-on-screen-array data, g, x, y, fg, bg, *width-a, *height-a
var offset/eax: int <- draw-code-point-on-screen-array data, c, x, y, fg, bg, *width-a, *height-a
x <- add offset
loop $convert-graphemes-to-pixels:loop-x
loop $convert-screen-cells-to-pixels:loop-x
}
x <- increment
loop

41
501draw-text.mu

@ -81,11 +81,11 @@ fn move-cursor-to-left-margin-of-next-line screen: (addr screen) {
set-cursor-position screen, cursor-x, cursor-y
}
fn draw-grapheme-at-cursor-over-full-screen screen: (addr screen), g: grapheme, color: int, background-color: int {
fn draw-code-point-at-cursor-over-full-screen screen: (addr screen), c: code-point, 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 _offset/eax: int <- draw-grapheme screen, g, cursor-x, cursor-y, color, background-color
var _offset/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, color, background-color
var offset/edx: int <- copy _offset
var width/eax: int <- copy 0
var dummy/ecx: int <- copy 0
@ -100,11 +100,6 @@ fn draw-grapheme-at-cursor-over-full-screen screen: (addr screen), g: grapheme,
}
}
fn draw-code-point-at-cursor-over-full-screen screen: (addr screen), c: code-point, color: int, background-color: int {
var g/eax: grapheme <- copy c
draw-grapheme-at-cursor-over-full-screen 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
@ -125,7 +120,8 @@ fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: i
var g/eax: grapheme <- read-grapheme stream
compare g, 0xffffffff/end-of-file
break-if-=
var offset/eax: int <- draw-grapheme screen, g, xcurr, y, color, background-color
var c/eax: code-point <- to-code-point g
var offset/eax: int <- draw-code-point screen, c, xcurr, y, color, background-color
xcurr <- add offset
loop
}
@ -156,8 +152,8 @@ fn draw-text-rightward-from-cursor-over-full-screen screen: (addr screen), text:
draw-text-rightward-from-cursor screen, text, width, color, background-color
}
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
fn render-code-point screen: (addr screen), c: code-point, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
compare c, 0xa/newline
var x/ecx: int <- copy x
{
break-if-!=
@ -167,7 +163,7 @@ fn render-grapheme screen: (addr screen), g: grapheme, xmin: int, ymin: int, xma
increment y
return x, y
}
var offset/eax: int <- draw-grapheme screen, g, x, y, color, background-color
var offset/eax: int <- draw-code-point screen, c, x, y, color, background-color
x <- add offset
compare x, xmax
{
@ -210,15 +206,16 @@ fn draw-text-wrapping-right-then-down screen: (addr screen), _text: (addr array
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 c/ebx: code-point <- copy 0
{
{
var _g/eax: grapheme <- read-grapheme stream
g <- copy _g
var g/eax: grapheme <- read-grapheme stream
var _c/eax: code-point <- to-code-point g
c <- copy _c
}
compare g, 0xffffffff/end-of-file
compare c, 0xffffffff/end-of-file
break-if-=
xcurr, ycurr <- render-grapheme screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
xcurr, ycurr <- render-code-point screen, c, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
loop
}
set-cursor-position screen, xcurr, ycurr
@ -301,7 +298,8 @@ fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin:
var g/eax: grapheme <- read-grapheme stream
compare g, 0xffffffff/end-of-file
break-if-=
var offset/eax: int <- draw-grapheme screen, g, xcurr, ycurr, color, background-color
var c/eax: code-point <- to-code-point g
var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
xcurr <- add offset
compare xcurr, xmax
{
@ -355,7 +353,8 @@ fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xm
var g/eax: grapheme <- read-grapheme stream
compare g, 0xffffffff/end-of-file
break-if-=
var offset/eax: int <- draw-grapheme screen, g, xcurr, ycurr, color, background-color
var c/eax: code-point <- to-code-point g
var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
xcurr <- add offset
compare xcurr, xmax
{
@ -422,7 +421,8 @@ fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: in
var g/eax: grapheme <- read-grapheme stream
compare g, 0xffffffff/end-of-file
break-if-=
var dummy/eax: int <- draw-grapheme screen, g, x, ycurr, color, background-color
var c/eax: code-point <- to-code-point g
var dummy/eax: int <- draw-code-point screen, c, x, ycurr, color, background-color
ycurr <- increment
loop
}
@ -463,7 +463,8 @@ fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr str
var g/eax: grapheme <- read-grapheme stream
compare g, 0xffffffff/end-of-file
break-if-=
var offset/eax: int <- draw-grapheme screen, g, xcurr, ycurr, color, background-color
var c/eax: code-point <- to-code-point g
var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
ycurr <- increment
compare ycurr, ymax
{

75
504test-screen.mu

@ -24,32 +24,33 @@ fn check-screen-row-from _screen: (addr screen), x: int, y: int, expected: (addr
var unused?/eax: boolean <- screen-cell-unused-at-index? screen, index
compare unused?, 0/false
break-if-!=
var _g/eax: grapheme <- screen-grapheme-at-index screen, index
var g/ebx: grapheme <- copy _g
var _c/eax: code-point <- screen-code-point-at-index screen, index
var c/ebx: code-point <- copy _c
var expected-grapheme/eax: grapheme <- read-grapheme e-addr
var expected-code-point/eax: code-point <- to-code-point expected-grapheme
# compare graphemes
$check-screen-row-from:compare-graphemes: {
# if expected-grapheme is space, null grapheme is also ok
# if expected-code-point is space, null grapheme is also ok
{
compare expected-grapheme, 0x20
compare expected-code-point, 0x20
break-if-!=
compare g, 0
compare c, 0
break-if-= $check-screen-row-from:compare-graphemes
}
# if (g == expected-grapheme) print "."
compare g, expected-grapheme
# if (c == expected-code-point) print "."
compare c, expected-code-point
break-if-=
# otherwise print an error
failure-count <- increment
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, expected-grapheme, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, expected-code-point, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, g, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, c, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
move-cursor-to-left-margin-of-next-line 0/screen
}
@ -90,21 +91,22 @@ fn check-screen-row-in-color-from _screen: (addr screen), fg: int, y: int, x: in
var unused?/eax: boolean <- screen-cell-unused-at-index? screen, index
compare unused?, 0/false
break-if-!=
var _g/eax: grapheme <- screen-grapheme-at-index screen, index
var g/ebx: grapheme <- copy _g
var _expected-grapheme/eax: grapheme <- read-grapheme e-addr
var expected-grapheme/edi: grapheme <- copy _expected-grapheme
var _c/eax: code-point <- screen-code-point-at-index screen, index
var c/ebx: code-point <- copy _c
var expected-grapheme/eax: grapheme <- read-grapheme e-addr
var _expected-code-point/eax: code-point <- to-code-point expected-grapheme
var expected-code-point/edi: code-point <- copy _expected-code-point
$check-screen-row-in-color-from:compare-cells: {
# if expected-grapheme is space, null grapheme is also ok
# if expected-code-point is space, null grapheme is also ok
{
compare expected-grapheme, 0x20
compare expected-code-point, 0x20
break-if-!=
compare g, 0
compare c, 0
break-if-= $check-screen-row-in-color-from:compare-cells
}
# if expected-grapheme is space, a different color is ok
# if expected-code-point is space, a different color is ok
{
compare expected-grapheme, 0x20
compare expected-code-point, 0x20
break-if-!=
var color/eax: int <- screen-color-at-index screen, index
compare color, fg
@ -112,8 +114,8 @@ fn check-screen-row-in-color-from _screen: (addr screen), fg: int, y: int, x: in
}
# compare graphemes
$check-screen-row-in-color-from:compare-graphemes: {
# if (g == expected-grapheme) print "."
compare g, expected-grapheme
# if (c == expected-code-point) print "."
compare c, expected-code-point
{
break-if-!=
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
@ -123,13 +125,13 @@ fn check-screen-row-in-color-from _screen: (addr screen), fg: int, y: int, x: in
count-test-failure
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, expected-grapheme, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, expected-code-point, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, g, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, c, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
move-cursor-to-left-margin-of-next-line 0/screen
}
@ -145,7 +147,7 @@ fn check-screen-row-in-color-from _screen: (addr screen), fg: int, y: int, x: in
count-test-failure
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, expected-grapheme, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, expected-code-point, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
@ -183,21 +185,22 @@ fn check-screen-row-in-background-color-from _screen: (addr screen), bg: int, y:
var unused?/eax: boolean <- screen-cell-unused-at-index? screen, index
compare unused?, 0/false
break-if-!=
var _g/eax: grapheme <- screen-grapheme-at-index screen, index
var g/ebx: grapheme <- copy _g
var _expected-grapheme/eax: grapheme <- read-grapheme e-addr
var expected-grapheme/edi: grapheme <- copy _expected-grapheme
var _g/eax: code-point <- screen-code-point-at-index screen, index
var g/ebx: code-point <- copy _g
var expected-grapheme/eax: grapheme <- read-grapheme e-addr
var _expected-code-point/eax: code-point <- to-code-point expected-grapheme
var expected-code-point/edi: code-point <- copy _expected-code-point
$check-screen-row-in-background-color-from:compare-cells: {
# if expected-grapheme is space, null grapheme is also ok
# if expected-code-point is space, null grapheme is also ok
{
compare expected-grapheme, 0x20
compare expected-code-point, 0x20
break-if-!=
compare g, 0
break-if-= $check-screen-row-in-background-color-from:compare-cells
}
# if expected-grapheme is space, a different background-color is ok
# if expected-code-point is space, a different background-color is ok
{
compare expected-grapheme, 0x20
compare expected-code-point, 0x20
break-if-!=
var background-color/eax: int <- screen-background-color-at-index screen, index
compare background-color, bg
@ -205,8 +208,8 @@ fn check-screen-row-in-background-color-from _screen: (addr screen), bg: int, y:
}
# compare graphemes
$check-screen-row-in-background-color-from:compare-graphemes: {
# if (g == expected-grapheme) print "."
compare g, expected-grapheme
# if (g == expected-code-point) print "."
compare g, expected-code-point
{
break-if-!=
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
@ -216,13 +219,13 @@ fn check-screen-row-in-background-color-from _screen: (addr screen), bg: int, y:
count-test-failure
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, expected-grapheme, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, expected-code-point, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, g, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, g, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
move-cursor-to-left-margin-of-next-line 0/screen
break $check-screen-row-in-background-color-from:compare-graphemes
@ -239,7 +242,7 @@ fn check-screen-row-in-background-color-from _screen: (addr screen), bg: int, y:
count-test-failure
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
draw-grapheme-at-cursor-over-full-screen 0/screen, expected-grapheme, 3/cyan, 0/bg
draw-code-point-at-cursor-over-full-screen 0/screen, expected-code-point, 3/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg

27
513grapheme-stack.mu

@ -98,7 +98,12 @@ fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _sel
compare i, *top-addr
break-if->=
{
var g/esi: (addr grapheme) <- index data, i
var c: code-point
{
var g/eax: (addr grapheme) <- index data, i
var tmp/eax: code-point <- to-code-point *g
copy-to c, tmp
}
var fg: int
{
var tmp/eax: int <- copy color
@ -109,7 +114,7 @@ fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _sel
break-if-!=
copy-to fg, 0xf/highlight
}
x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color
}
i <- increment
loop
@ -152,8 +157,13 @@ fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self:
break-if-=
compare i, 0
break-if-<
var g/esi: (addr grapheme) <- index data, i
x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, background-color, color
var c: code-point
{
var g/eax: (addr grapheme) <- index data, i
var tmp/eax: code-point <- to-code-point *g
copy-to c, tmp
}
x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, background-color, color
i <- decrement
}
# remaining iterations
@ -172,8 +182,13 @@ fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self:
copy-to fg, 0xf/highlight
}
#
var g/esi: (addr grapheme) <- index data, i
x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
var c: code-point
{
var g/eax: (addr grapheme) <- index data, i
var tmp/eax: code-point <- to-code-point *g
copy-to c, tmp
}
x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color
i <- decrement
loop
}

4
514gap-buffer.mu

@ -409,8 +409,8 @@ fn render-gap-buffer-wrapping-right-then-down screen: (addr screen), _gap: (addr
bg <- copy color
}
# print a grapheme either way so that cursor position doesn't affect printed width
var space/edx: grapheme <- copy 0x20
x2, y2 <- render-grapheme screen, space, xmin, ymin, xmax, ymax, x2, y2, fg, bg
var space/edx: code-point <- copy 0x20
x2, y2 <- render-code-point screen, space, xmin, ymin, xmax, ymax, x2, y2, fg, bg
return x2, y2
}

4
apps/colors.mu

@ -27,8 +27,8 @@ fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk)
loop-if-=
var key2/eax: int <- copy key
append-byte in, key2
var g/eax: grapheme <- copy key2
draw-grapheme-at-cursor-over-full-screen screen, g, 0xf/fg, 0/bg
var c/eax: code-point <- copy key2 # TODO: unicode input
draw-code-point-at-cursor-over-full-screen screen, c, 0xf/fg, 0/bg
loop
}
clear-screen screen

8
apps/rpn.mu

@ -19,7 +19,7 @@ fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk)
var in-storage: (stream byte 0x80)
var in/esi: (addr stream byte) <- address in-storage
var y/ecx: int <- copy 0
var space/edx: grapheme <- copy 0x20
var space/edx: code-point <- copy 0x20
# read-eval-print loop
{
# print prompt
@ -35,12 +35,12 @@ fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk)
loop-if-=
var key2/eax: int <- copy key
append-byte in, key2
var g/eax: grapheme <- copy key2
draw-grapheme-at-cursor-over-full-screen screen, g, 0xf/fg, 0/bg
var c/eax: code-point <- copy key2
draw-code-point-at-cursor-over-full-screen screen, c, 0xf/fg, 0/bg
loop
}
# clear cursor
draw-grapheme-at-cursor-over-full-screen screen, space, 3/fg/never-used, 0/bg
draw-code-point-at-cursor-over-full-screen screen, space, 3/fg/never-used, 0/bg
# parse and eval
var out/eax: int <- simplify in
# print

41
browse-slack/environment.mu

@ -378,7 +378,7 @@ fn render-search-input screen: (addr screen), _env: (addr environment) {
compare x, 0x4a/end-search
break-if->
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x5f/underscore, 0/xmin 1/ymin, 0x80/xmax, 1/ymax, x, 1/y, 0xf/fg 0/bg
x, y <- render-code-point screen, 0x5f/underscore, 0/xmin 1/ymin, 0x80/xmax, 1/ymax, x, 1/y, 0xf/fg 0/bg
loop
}
}
@ -580,17 +580,17 @@ fn draw-json-stream-wrapping-right-then-down screen: (addr screen), stream: (add
var xcurr/eax: int <- copy x
var ycurr/ecx: int <- copy y
{
var g/ebx: grapheme <- read-json-grapheme stream
compare g, 0xffffffff/end-of-file
var c/ebx: code-point <- read-json-code-point stream
compare c, 0xffffffff/end-of-file
break-if-=
$draw-json-stream-wrapping-right-then-down:render-grapheme: {
compare g, 0x5c/backslash
compare c, 0x5c/backslash
{
break-if-!=
xcurr, ycurr <- render-json-escaped-grapheme screen, stream, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
xcurr, ycurr <- render-json-escaped-code-point screen, stream, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
break $draw-json-stream-wrapping-right-then-down:render-grapheme
}
xcurr, ycurr <- render-grapheme screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
xcurr, ycurr <- render-code-point screen, c, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
}
loop
}
@ -599,15 +599,16 @@ fn draw-json-stream-wrapping-right-then-down screen: (addr screen), stream: (add
}
# just return a different register
fn read-json-grapheme stream: (addr stream byte) -> _/ebx: grapheme {
var result/eax: grapheme <- read-grapheme stream
fn read-json-code-point stream: (addr stream byte) -> _/ebx: code-point {
var g/eax: grapheme <- read-grapheme stream
var result/eax: code-point <- to-code-point g
return result
}
# '\' encountered
# https://www.json.org/json-en.html
fn render-json-escaped-grapheme screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, xcurr: int, ycurr: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
var g/ebx: grapheme <- read-json-grapheme stream
fn render-json-escaped-code-point screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, xcurr: int, ycurr: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
var g/ebx: code-point <- read-json-code-point stream
compare g, 0xffffffff/end-of-file
{
break-if-!=
@ -647,16 +648,16 @@ fn render-json-escaped-grapheme screen: (addr screen), stream: (addr stream byte
{
compare g, 0x75/u
break-if-!=
x, y <- render-json-escaped-unicode-grapheme screen, stream, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-json-escaped-unicode-code-point screen, stream, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# most characters escape to themselves
x, y <- render-grapheme screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, g, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# '\u' encountered
fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, xcurr: int, ycurr: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
fn render-json-escaped-unicode-code-point screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, xcurr: int, ycurr: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
var ustream-storage: (stream byte 4)
var ustream/esi: (addr stream byte) <- address ustream-storage
# slurp 4 bytes exactly
@ -679,7 +680,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x2d/dash, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x2d/dash, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u2014 = -
@ -689,7 +690,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x2d/dash, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x2d/dash, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u2018 = '
@ -699,7 +700,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x27/quote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x27/quote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u2019 = '
@ -709,7 +710,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x27/quote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x27/quote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u201c = "
@ -719,7 +720,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x22/dquote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x22/dquote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u201d = "
@ -729,7 +730,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x22/dquote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x22/dquote, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u2022 = *
@ -739,7 +740,7 @@ fn render-json-escaped-unicode-grapheme screen: (addr screen), stream: (addr str
break-if-=
var x/eax: int <- copy 0
var y/ecx: int <- copy 0
x, y <- render-grapheme screen, 0x2a/asterisk, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
x, y <- render-code-point screen, 0x2a/asterisk, xmin, ymin, xmax, ymax, xcurr, ycurr, color, background-color
return x, y
}
# \u2026 = ...

7
linux/403unicode.mu

@ -11,14 +11,11 @@
#
# Mu doesn't currently support combining code points, or graphemes made of
# multiple code points. One day we will.
# We also don't currently support code points that translate into multiple
# or wide graphemes. (In particular, Tab will never be supported.)
# On Linux, we also don't currently support code points that translate into
# multiple or wide graphemes. (In particular, Tab will never be supported.)
# transliterated from tb_utf8_unicode_to_char in https://github.com/nsf/termbox
# https://wiki.tcl-lang.org/page/UTF%2D8+bit+by+bit explains the algorithm
#
# The day we want to support combining characters, this function will need to
# take multiple code points. Or something.
fn to-grapheme in: code-point -> _/eax: grapheme {
var c/eax: int <- copy in
var num-trailers/ecx: int <- copy 0

2
shell/primitives.mu

@ -3493,7 +3493,7 @@ fn apply-blit _args-ah: (addr handle cell), out: (addr handle cell), trace: (add
var dest-ah/eax: (addr handle screen) <- get second, screen-data
var dest/eax: (addr screen) <- lookup *dest-ah
#
convert-graphemes-to-pixels src
convert-screen-cells-to-pixels src
copy-pixels src, dest
}

8
shell/sandbox.mu

@ -255,8 +255,8 @@ fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmi
fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int {
var target-screen/esi: (addr screen) <- copy _target-screen
convert-graphemes-to-pixels target-screen # might overwrite existing pixel data with graphemes
# overlapping the two is not supported
convert-screen-cells-to-pixels target-screen # might overwrite existing pixel data with screen cells
# overlapping the two is not supported
# pixel data
{
# screen top left pixels x y width height
@ -383,10 +383,10 @@ fn print-screen-cell-of-fake-screen screen: (addr screen), _target: (addr screen
var index/ecx: int <- screen-cell-index target, x, y
var offset/ecx: (offset screen-cell) <- compute-offset data, index
var src-cell/esi: (addr screen-cell) <- index data, offset
var src-grapheme/eax: (addr grapheme) <- get src-cell, data
var src-code-point/eax: (addr code-point) <- get src-cell, data
var src-color/ecx: (addr int) <- get src-cell, color
var src-background-color/edx: (addr int) <- get src-cell, background-color
draw-grapheme-at-cursor-over-full-screen screen, *src-grapheme, *src-color, *src-background-color
draw-code-point-at-cursor-over-full-screen screen, *src-code-point, *src-color, *src-backgro