aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-12-08 03:13:32 +0000
committerdam <dam@gudinoff>2023-12-08 03:13:32 +0000
commitf0aab177c96c6bda25927f4b748c39f2847df47a (patch)
tree82e60181ab2fc1aeee054611c2bf3a6325b63c99
parent7945094deb5cb6bac24a2ec96a4cc3bc0d64b6c8 (diff)
parentc61e13ae21cbac7b6642d2d813245c7fc0575834 (diff)
downloadtask-time-tracker-f0aab177c96c6bda25927f4b748c39f2847df47a.tar.zst
task-time-tracker-f0aab177c96c6bda25927f4b748c39f2847df47a.zip
Merge changes from black and red.
-rw-r--r--TUI/module.jai125
-rw-r--r--TUI/unix.jai8
-rw-r--r--ttt.jai91
3 files changed, 133 insertions, 91 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
index 8f5c69a..5157ba2 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 4aa0508..2c34122 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -39,6 +39,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
@@ -178,6 +181,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;
diff --git a/ttt.jai b/ttt.jai
index 110d089..1a25143 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -1181,6 +1181,7 @@ read_enter_confirmation :: inline (row: int, style: int, message: string) -> boo
main :: () {
+ // -- -- -- Testing TUI -- START
#if 0 {
print("test 0\n");
TUI.test();
@@ -1258,86 +1259,36 @@ main :: () {
TUI.start();
xcolumns, xrows: int;
key: TUI.Key = #char "d";
+ last_none_char := "X";
while(key != #char "q") {
// __mark := get_temporary_storage_mark();
+
+ if key == {
+ case xx TUI.Keys.None; {
+ TUI.set_cursor_position(2, 2);
+ last_none_char = ifx last_none_char == "X" then "+" else "X";
+ write_string(last_none_char);
+ }
+
+ case xx TUI.Keys.Resize; {
+ TUI.clear_terminal();
+ }
+ }
+ size_r, size_c := TUI.get_terminal_size();
+ TUI.draw_box(1, 1, size_c, size_r);
+ x := ifx size_r > 1 then size_r-1 else 1;
+ y := ifx size_c > 24 then size_c-24 else 1;
+ TUI.set_cursor_position(x, y);
+ print("size(CxR): %x%\n", size_c, size_r);
- TUI.set_cursor_position(3, 3);
- write_string("dam ");
- print("%:%", xcolumns, xrows);
key = TUI.get_key(3000);
- if key == xx TUI.Keys.None {
- write_string(">bazinga<");
- sleep_milliseconds(1000);
- }
- else if key == xx TUI.Keys.Resize {
- TUI.clear_terminal();
- xrows, xcolumns = TUI.get_terminal_size();
- TUI.draw_box(1, 1, xcolumns, xrows);
- }
- else if key == #char "i" {
- auto_release_temp();
- TUI.set_cursor_position(7, 3);
- write_string("input: ");
- TUI.flush_input();
- str := TUI.get_str(3);
- print(">%<\n\r", str);
- TUI.set_cursor_position(8, 3);
- }
- else {
- print_character(cast(u8)key);
- }
}
TUI.stop();
print("size(CxR): %x%\n", xcolumns, xrows);
return;
}
-
- // -- -- -- TODO WIP Testing TUI -- START
- // TUI.start();
- // TUI.clear_terminal();
- // rows, columns := TUI.get_terminal_size();
- // TUI.draw_box(1, 1, columns, rows);
- // TUI.set_cursor_position(4, 4);
- // c_row, c_column := TUI.get_cursor_position();
- // TUI.set_cursor_position(3, 3);
- // input := TUI.read_input();
-
- // sleep_milliseconds(5000);
- // TUI.stop();
- // print("- - -\n");
- // print("window r:c = %:%\n", rows, columns);
- // print("cursor r:c = %:%\n", c_row, c_column);
- // print("input = %\n", input);
- // return;
-//
-//
- // str: string;
-//
- // write_string("\e(0"); // Enter Line drawing mode
- // write_string("\e[104;93m"); // bright yellow on bright blue
- // write_string("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar"
- // write_string("\e[10m"); // restore color
- // write_string("\e(B"); // exit line drawing mode
- // sleep_milliseconds(1000);
-
-
- // // str = "\e[sWOW\e[u\e[1P";
- // str = "\e[sWOW";
- // // write(STDIN_FILENO, str.data, xx str.count);
- // write_string(str);
- // sleep_milliseconds(1000);
- //
- // str = "\e[?25l";
- // // write(STDIN_FILENO, str.data, xx str.count);
- // write_string(str);
- // sleep_milliseconds(1000);
- //
- // str = "\e[?25h";
- // // write(STDIN_FILENO, str.data, xx str.count);
- // write_string(str);
- // return;
- // -- -- -- TODO WIP Testing TUI -- STOP
+ // -- -- -- Testing TUI -- STOP
// TODO Implement signal handling and see modules/Debug.jai for examples.