diff options
Diffstat (limited to 'TUI/module.jai')
| -rw-r--r-- | TUI/module.jai | 228 |
1 files changed, 64 insertions, 164 deletions
diff --git a/TUI/module.jai b/TUI/module.jai index de56ee8..64567fa 100644 --- a/TUI/module.jai +++ b/TUI/module.jai @@ -1,9 +1,13 @@ -#if OS == .WINDOWS { - #load "windows.jai"; -} else #if (OS == .LINUX) || (OS == .MACOS) { - #load "unix.jai"; -} else { - #assert(false, "Unsupported OS."); +// TODO Move TUI into ./modules/TUI so we can stop calling --import_dir on compile. +#if OS == { + case .LINUX; + #load "unix.jai"; + case .MACOS; + #load "unix.jai"; + case .WINDOWS; + #load "windows.jai"; + case; + #assert(false, "Unsupported OS."); } #import "Basic"; @@ -61,7 +65,8 @@ Commands :: struct { RefreshWindow :: "\e[7t"; // TODO Not yet tested. - SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE + SetIEC2022 :: "\e%@"; + SetUTF8 :: "\e%G"; SetGraphicsRendition :: "\e[%m"; @@ -139,6 +144,7 @@ set_style :: (bold: bool, underline: bool = false, strike_through: bool = false, } // TODO Maybe make the OS_* procedures as inline?! +// TODO Terminal action codes are encoded with values incompatible with UTF-8 to avoid collisions. /* We wanted the Key type to represent either UTF-8 encoded characters and also keyboard keys. @@ -369,57 +375,13 @@ is_escape_code :: inline (key: Key) -> bool { return result; } -// TODO FIXME DEBUG HACK -test_union :: () -{ - // ti := type_info(K); - print("\n---\n%\n---\n", type_info(Key).*); - print("\n---\n%\n---\n", type_info(Key).runtime_size); - a: Key; - b: u8; - print(">%\n", a == b); - print(">%\n", a != Keys.None); - - c: string = ""; - print(">%\n", a == to_key(c)); - - d: []u8 = xx ""; - print(">%\n", a == to_key(d)); - - top := "┌───┐"; - btm := "└───┘"; - print(">%<\n", top); - print(">%<\n", btm); - - str := "abcd"; - tok := to_key(str); - tos := to_string(tok); - - print("1:%:\n", str); - print("2:"); - for 0..7 { - val := tok & 0xFF; - tok >>=8 ; - print("% ", FormatInt.{value=val, base=16, minimum_digits=2}); - } - print(":\n"); - print("3:%:\n", tos); - -} -#run test_union(); - -// Terminal action codes are encoded with values incompatible with UTF-8 to avoid collisions. - - initialized := false; -// input_buffer : [64] u8; // TODO FIXME Input buffer is too small!!! +//input_buffer : [64] u8; // TODO FIXME Input buffer is too small!!! input_buffer : [8] u8; // TODO FIXME Input buffer is too small!!! input_string : string; input_override : Key; -was_resized : bool; - #run { // TODO FIXME DEBUG HACK or maybe... let it be?! // Some tests. @@ -437,6 +399,16 @@ set_next_key :: (key: Key) { get_key :: (timeout_milliseconds: s32 = -1) -> Key { assert_is_initialized(); + + /* + TODO + get_key already deals with utf8 codes, but we don't know when we're receiving ANSI escape codes. If initial key is escape and other keys are awaiting in the input buffer, we need to parse them as escaped sequences. See wikiedia* for help on that. Lets use the escape sequences used on windows amd forget all others. Those should be the most used ones; at least they are the cross-platform compatible ones :P + * https://en.m.wikipedia.org/wiki/ANSI_escape_code + + Check this + https://devmemo.io/cheatsheets/terminal_escape_code/ + */ + // BBBB BBBB & 1100 0000 == 10XX XXXX -> is continuation byte is_utf8_continuation_byte :: inline (byte: u8) -> bool { @@ -457,105 +429,57 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { defer input_override = xx Keys.None; return input_override; } - + 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 #no_abc { // TODO Some trickery requires no_abc... which is not that nice in this case... - utf8_bytes := count_utf8_bytes(input_string[0]); - - // TODO We're assuming the terminal buffer contains the entirety of what we need to read for the UTF8 symbols. - if utf8_bytes > input_string.count { + should_read_input := false; + is_input_available := false; + + if input_string.count == 0 { + should_read_input = true; + is_input_available = OS_wait_for_input(timeout_milliseconds); + } + else if input_string.count < KEY_SIZE { + should_read_input = true; + is_input_available = OS_wait_for_input(0); + } - diff := utf8_bytes - input_string.count; + if OS_was_terminal_resized() return xx Keys.Resize; - // TODO Test this and make sure it's working...drop the following lines using Ctrl+V to fill the terminal buffer at once: - // d€€€a - // 1234567890123456789012345678901234567890 - print("<WoW>"); - - // Copy buffered bytes to the start, and read the remaining ones from input. - for 0..input_string.count-1 { - input_buffer[it] = input_string[it]; - } - aaa := OS_read_input(input_buffer.data + input_string.count, utf8_bytes-input_string.count); // TODO Does not check for read errors. - assert(aaa == diff, "READ MORE THAN EXPECTED"); - input_string.data = input_buffer.data; - input_string.count = utf8_bytes; + if should_read_input && is_input_available { + // Copy buffered bytes to the start, and read the remaining ones from input. + for 0..input_string.count-1 { + input_buffer[it] = input_string[it]; } + // Read input into remaining part of buffer. + bytes_read := OS_read_input(input_buffer.data + input_string.count, input_buffer.count - input_string.count); + input_string.data = input_buffer.data; + input_string.count += bytes_read; + } + + if input_string.count > 0 + { + utf8_bytes := count_utf8_bytes(input_string[0]); to_parse := input_string; to_parse.count = utf8_bytes; + + // Must be a terminal escape sequence. + if utf8_bytes == 1 && input_string[0] == #char "\e" { + assert(input_string.count <= KEY_SIZE, "Received oversized terminal sequence."); // TODO + to_parse.count = ifx input_string.count > KEY_SIZE then KEY_SIZE else input_string.count; // TODO We should look into the input_string and search for the following escape sequence or somehting!? + } + key := to_key(to_parse); - - advance(*input_string, utf8_bytes); + advance(*input_string, to_parse.count); 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]; - // } + // TODO try_parse_escape_code + // { + // assert(false, "TODO try_parse_escape_code"); // } - // 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; - utf8_bytes := count_utf8_bytes(input_string[0]); - - assert(utf8_bytes <= input_string.count, "The input buffer is too small."); // TODO Improve error message. - - // TODO This is only being done after the OS_wait_for_input... for now! - to_parse := input_string; - to_parse.count = utf8_bytes; - - // Must be a terminal escape sequence. - if utf8_bytes == 1 && input_string[0] == #char "\e" { - assert(input_string.count <= KEY_SIZE, "Received oversized terminal sequence."); // TODO - to_parse.count = ifx input_string.count > KEY_SIZE then KEY_SIZE else input_string.count; // TODO We should look into the input_string and search for the following escape sequence or somehting!? - } - - key := to_key(to_parse); - advance(*input_string, to_parse.count); - return key; - - /// /// /// /// /// /// /// /// /// - // 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); - /// /// /// /// /// /// /// /// /// - } - } return xx Keys.None; } @@ -696,6 +620,7 @@ start :: () { Commands.SetUTF8, Commands.CursorNormalMode, Commands.KeypadNumMode); + OS_prepare_terminal(); initialized = true; @@ -809,12 +734,11 @@ get_terminal_size :: () -> rows: int, columns: int { // Some systems don't allow to query the terminal size directly. // In such cases, measure it indirectly by the maximum possible cursor position. else { - #import "Math"; // TODO Maybe use S16_MAX values directly. flush_input(); cursor_row, cursor_column := get_cursor_position(); defer set_cursor_position(cursor_row, cursor_column); - set_cursor_position(S16_MAX, S16_MAX); + set_cursor_position(0xFFFF, 0xFFFF); rows, columns = get_cursor_position(); } @@ -824,8 +748,7 @@ get_terminal_size :: () -> rows: int, columns: int { set_cursor_position :: (row: int, column: int) { assert_is_initialized(); auto_release_temp(); - tmp_string := tprint(Commands.SetCursorPosition, row, column); - write_string(tmp_string); + print(Commands.SetCursorPosition, row, column); } get_cursor_position :: () -> row: int, column: int { @@ -868,29 +791,6 @@ set_terminal_title :: (title: string) { } -test :: () { - - // A) Testing stuff -#if true { - start(); - flush_input(); - set_cursor_position(S16_MAX, S16_MAX); - r_a, c_a := get_cursor_position(); - stop(); - print("\n\rA) size: %, %\n", r_a, c_a); -} - - // B) Built way -#if true { - start(); - r_b, c_b := get_terminal_size(); - stop(); - print("\n\rB) size: %, %\n", r_b, c_b); -} - -} - - #if OS == .WINDOWS { // Prototyping zone... keep clear! } |
