aboutsummaryrefslogtreecommitdiff
path: root/TUI
diff options
context:
space:
mode:
Diffstat (limited to 'TUI')
-rw-r--r--TUI/module.jai125
-rw-r--r--TUI/unix.jai8
2 files changed, 112 insertions, 21 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
index a12b762..5e19e4f 100644
--- a/TUI/module.jai
+++ b/TUI/module.jai
@@ -97,6 +97,7 @@ input_buffer : [64] u8;
input_string : string;
input_override : Key;
+row := 5;
set_next_key :: (key: Key) {
input_override = key;
@@ -104,6 +105,22 @@ set_next_key :: (key: Key) {
get_key :: (timeout_milliseconds: s32 = -1) -> Key {
+ // BBBB BBBB & 1100 0000 == 10XX XXXX -> is continuation byte
+ is_utf8_continuation_byte :: inline (byte: u8) -> bool {
+ return (byte & 0xC0) == 0x80;
+ }
+
+ // BBBB BBBB & 1110 0000 == 110X XXXX -> 1 initial + 1 continuation byte
+ // BBBB BBBB & 1111 0000 == 1110 XXXX -> 1 initial + 2 continuation byte
+ // BBBB BBBB & 1111 1000 == 1111 0XXX -> 1 initial + 3 continuation byte
+ count_utf8_bytes :: inline (byte: u8) -> int {
+ if (byte & 0xE0) == 0xC0 return 1+1;
+ if (byte & 0xF0) == 0xE0 return 1+2;
+ if (byte & 0xF8) == 0xF0 return 1+3;
+ return 1;
+ }
+
+
/*
TODO WIP Implement UTF-8 support, i.e., merge continuation bytes if needed:
@@ -123,23 +140,73 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key {
}
if OS_was_terminal_resized() return xx Keys.Resize;
-
+
+ // FIXME Old version...
+ // if input_string.count > 0 {
+ // defer advance(*input_string, 1);
+ // return input_string[0];
+ // }
+ // FIXME New version...
if input_string.count > 0 {
- defer advance(*input_string, 1);
- return input_string[0];
+ utf8_bytes := count_utf8_bytes(input_string[0]);
+ key: Key;
+ for 1..utf8_bytes {
+ key = key << 8;
+ key |= input_string[utf8_bytes-it];
+ }
+ advance(*input_string, utf8_bytes);
+ return key;
}
is_input_available := OS_wait_for_input(timeout_milliseconds);
if OS_was_terminal_resized() return xx Keys.Resize;
+ // FIXME Old version...
+ // if is_input_available {
+ // bytes_read := OS_read_input(input_buffer.data, input_buffer.count); // TODO Does not check for read errors.
+ // if bytes_read > 0 {
+ // input_string.data = input_buffer.data;
+ // input_string.count = bytes_read;
+ // defer advance(*input_string, 1);
+ // return input_string[0];
+ // }
+ // }
+ // FIXME New version...
if is_input_available {
bytes_read := OS_read_input(input_buffer.data, input_buffer.count); // TODO Does not check for read errors.
if bytes_read > 0 {
input_string.data = input_buffer.data;
input_string.count = bytes_read;
- defer advance(*input_string, 1);
- return input_string[0];
+ utf8_bytes := count_utf8_bytes(input_string[0]);
+
+ key: Key;
+ for 1..utf8_bytes {
+ key = key << 8;
+ key |= input_string[utf8_bytes-it];
+ }
+
+ /// /// /// /// /// /// /// /// ///
+ // DEBUG
+ br, bc := get_cursor_position();
+ column := 3;
+ row += 1;
+ nr, rc := get_terminal_size();
+
+ if row >= (rc - 5) then row = 5;
+
+ set_cursor_position(row, column);
+ for 0..input_string.count-1 {
+ print("%:% | ",
+ FormatInt.{base= 2, minimum_digits = 8, value = input_string[it]},
+ FormatInt.{base= 16, minimum_digits = 2, value = input_string[it]},
+ ); // TODO DEBUG
+ }
+ set_cursor_position(br, bc);
+ /// /// /// /// /// /// /// /// ///
+
+ advance(*input_string, utf8_bytes);
+ return key;
}
}
return xx Keys.None;
@@ -191,7 +258,7 @@ stop :: () {
}
flush_input :: () {
- // TODO
+ OS_flush_input();
}
draw_box :: (x: int, y: int, width: int, height: int) {
@@ -256,16 +323,23 @@ get_terminal_size :: () -> rows: int, columns: int {
flush_input();
write_string(Commands.QueryWindowSizeInChars);
-
input := get_str(64);
-
- // Expected message format: [8;<r>;<c>t
+
+ // Expected response format: \e[8;<r>;<c>t
// where <r> is the number of rows and <c> of columns.
- assert(
- input[0] == #char "\e" &&
- input[1] == #char "[" &&
- input[2] == #char "8",
- //input[input.count-1] == #char "t",
+ FORMAT :: "\e[8;<r>;<c>t";
+
+ // Discard head noise.
+ while input.count >= 3 && (input[0] != FORMAT[0] || input[1] != FORMAT[1] || input[2] != FORMAT[2]) {
+ advance(*input);
+ }
+
+ // Discard tail noise.
+ while input.count >= 2 && input[input.count-1] != FORMAT[FORMAT.count-1] {
+ input.count -= 1;
+ }
+
+ assert(input[0] == FORMAT[0] && input[1] == FORMAT[1] && input[2] == FORMAT[2] && input[input.count-1] == FORMAT[FORMAT.count-1],
"Query window size in chars returned invalid response.");
parts := split(input, ";");
@@ -289,17 +363,26 @@ get_cursor_position :: () -> row: int, column: int {
flush_input();
write_string(Commands.QueryCursorPosition);
-
input := get_str(64);
- // Expected message format: \e[<r>;<c>R
+ // Expected response format: \e[<r>;<c>R
// where <r> is the number of rows and <c> of columns.
- assert(
- input[0] == #char "\e" &&
- input[1] == #char "[" &&
- input[input.count-1] == #char "R",
- "Query cursor position returned invalid response.");
+ FORMAT :: "\e[<r>;<c>R";
+
+ // Discard head noise.
+ while input.count >= 2 && (input[0] != FORMAT[0] || input[1] != FORMAT[1]) {
+ advance(*input);
+ }
+
+ // Discard tail noise.
+ while input.count >= 2 && input[input.count-1] != FORMAT[FORMAT.count-1] {
+ input.count -= 1;
+ }
+ assert(input[0] == FORMAT[0] && input[1] == FORMAT[1] && input[input.count-1] == FORMAT[FORMAT.count-1],
+ "Query cursor position returned invalid response.");
+
+
advance(*input, 2);
parts := split(input, ";");
row := parse_int(*parts[0]);
diff --git a/TUI/unix.jai b/TUI/unix.jai
index fb79f86..73a763a 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -25,6 +25,9 @@
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 #foreign libc;
+ // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcflush.c.html
+ tcflush :: (fd: s32, queue_selector: s32) -> s32 #foreign libc;
+
// Information for the termios.h enums is platform dependent and was retrieved from:
// https://elixir.bootlin.com/glibc/latest/source/sysdeps/unix/sysv/linux/bits/termios.h
@@ -169,6 +172,11 @@ restore_resize_handler :: () {
#scope_export
+OS_flush_input :: inline () {
+ TCIFLUSH :: 0; // TODO Is this always zero in all systems?
+ tcflush(STDIN_FILENO, TCIFLUSH);
+}
+
OS_prepare_terminal :: () {
tcgetattr(STDIN_FILENO, *initial_tio_mode); // TODO Log on error.
raw_tio_mode = initial_tio_mode;