diff options
Diffstat (limited to 'TUI/module.jai')
| -rw-r--r-- | TUI/module.jai | 129 |
1 files changed, 94 insertions, 35 deletions
diff --git a/TUI/module.jai b/TUI/module.jai index 21f1dd7..de56ee8 100644 --- a/TUI/module.jai +++ b/TUI/module.jai @@ -559,33 +559,55 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { return xx Keys.None; } -// TODO Maybe rename!? Or replace with read_string... or read_input... or something else?! -get_string :: (count_limit: int = -1) -> string { +// TODO Review me! +read_input :: (count_limit: int = -1, terminators: .. u8) -> string { assert_is_initialized(); - + + assert(count_limit >= 0 || terminators.count > 0, "Infinite loop detected, aborting."); // TODO Maybe just return!? + // if count_limit < 0 && terminators.count == 0 { + // TODO Write error to log. + // return ""; + // } + if count_limit < 0 { builder: String_Builder; init_string_builder(*builder); - while(1) { + while read_loop := true { buffer := get_current_buffer(*builder); buffer_data := get_buffer_data(buffer); - buffer.count = OS_read_input(buffer_data, buffer.allocated); // TODO Does not check for read errors. - if buffer.count < buffer.allocated break; - expand(*builder); + buffer.count += OS_read_input(buffer_data + buffer.count, buffer.allocated - buffer.count); + for 0..buffer.count-1 { + for t: terminators { + if buffer_data[it] == t then break read_loop; + } + } + if buffer.count == buffer.allocated then expand(*builder); + OS_wait_for_input(); } return builder_to_string(*builder); } else { buffer := alloc_string(count_limit); - buffer.count = OS_read_input(buffer.data, count_limit); + buffer.count = 0; + + while read_loop := true { + buffer.count += OS_read_input(buffer.data + buffer.count, count_limit - buffer.count); + if buffer.count == count_limit then break; + for 0..buffer.count-1 { + for t: terminators { + if buffer[it] == t then break read_loop; + } + } + OS_wait_for_input(); + } + return buffer; } } // TODO UNTESTED -// TODO Is count_limit the number of bytes of UTF8 symbols? -user_line_input :: (count_limit: int, is_visible: bool = true) -> string, Key { +read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { assert(count_limit >= 0, "Invalid value on count_limit parameter."); str := alloc_string(count_limit); @@ -689,6 +711,8 @@ stop :: () { flush_input :: () { OS_flush_input(); + input_string.data = input_buffer.data; + input_string.count = 0; } // TODO move style related procedures here! @@ -753,33 +777,46 @@ get_terminal_size :: () -> rows: int, columns: int { auto_release_temp(); - rows, columns: int = ---; - flush_input(); write_string(Commands.QueryWindowSizeInChars); - input := get_string(64,, temporary_allocator); - - // Expected response format: \e[8;<r>;<c>t - // where <r> is the number of rows and <c> of columns. - 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); - } + rows, columns: int = ---; + if OS_wait_for_input(0) { - // Discard tail noise. - while input.count >= 3 && input[input.count-1] != FORMAT[FORMAT.count-1] { - input.count -= 1; - } - - assert(input.count >= 3 && - 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."); + // Expected response format: \e[8;<r>;<c>t + // where <r> is the number of rows and <c> of columns. + FORMAT :: "\e[8;<r>;<c>t"; + input := read_input(64, #char "t",, temporary_allocator); - parts := split(input, ";",, temporary_allocator); - rows = parse_int(*parts[1]); - columns = parse_int(*parts[2]); + // 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 >= 3 && input[input.count-1] != FORMAT[FORMAT.count-1] { + input.count -= 1; + } + + assert(input.count >= 3 && + 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, ";",, temporary_allocator); + rows = parse_int(*parts[1]); + columns = parse_int(*parts[2]); + } + // 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); + rows, columns = get_cursor_position(); + } return rows, columns; } @@ -798,12 +835,12 @@ get_cursor_position :: () -> row: int, column: int { flush_input(); write_string(Commands.QueryCursorPosition); - input := get_string(64,, temporary_allocator); // Expected response format: \e[<r>;<c>R // where <r> is the number of rows and <c> of columns. FORMAT :: "\e[<r>;<c>R"; - + input := read_input(64, #char "R"); + // Discard head noise. while input.count >= 2 && (input[0] != FORMAT[0] || input[1] != FORMAT[1]) { advance(*input); @@ -818,7 +855,6 @@ get_cursor_position :: () -> row: int, column: int { 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, ";",, temporary_allocator); row := parse_int(*parts[0]); @@ -832,6 +868,29 @@ 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! } |
