diff options
| author | dam <dam@gudinoff> | 2023-12-08 03:13:32 +0000 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-12-08 03:13:32 +0000 |
| commit | f0aab177c96c6bda25927f4b748c39f2847df47a (patch) | |
| tree | 82e60181ab2fc1aeee054611c2bf3a6325b63c99 | |
| parent | 7945094deb5cb6bac24a2ec96a4cc3bc0d64b6c8 (diff) | |
| parent | c61e13ae21cbac7b6642d2d813245c7fc0575834 (diff) | |
| download | task-time-tracker-f0aab177c96c6bda25927f4b748c39f2847df47a.tar.zst task-time-tracker-f0aab177c96c6bda25927f4b748c39f2847df47a.zip | |
Merge changes from black and red.
| -rw-r--r-- | TUI/module.jai | 125 | ||||
| -rw-r--r-- | TUI/unix.jai | 8 | ||||
| -rw-r--r-- | ttt.jai | 91 |
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; @@ -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. |
