From 36af624cdd9cb54454587bfae21b30096986d22e Mon Sep 17 00:00:00 2001 From: dam Date: Sun, 5 May 2024 02:34:33 +0100 Subject: WIP : Cleanup TUI module and improved assert/error messages. --- modules/TUI/module.jai | 137 ++++++++++++++++++++----------------------------- 1 file changed, 57 insertions(+), 80 deletions(-) (limited to 'modules/TUI/module.jai') diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai index ab2567d..07d121f 100644 --- a/modules/TUI/module.jai +++ b/modules/TUI/module.jai @@ -15,36 +15,46 @@ #assert(false, "Unsupported OS."); } +#if COLOR_MODE_BITS == { + case 4; + #load "palette_4b.jai"; + case 8; + #load "palette_8b.jai"; + case 24; + #load "palette_24b.jai"; + _; + assert(false, "Invalid COLOR_MODE_BITS. Valid values are 4, 8, or 24 (default)."); +} + #import "Basic"; #import "String"; #import "Thread"; #import "UTF8"; #load "key_map.jai"; +active := false; +input_override : Key; +input_string : string; +input_buffer : [1024] u8; + KEY_SIZE :: #run type_info(Key).runtime_size; -#run { - assert(COLOR_MODE_BITS == 4 || COLOR_MODE_BITS == 8 || COLOR_MODE_BITS == 24, "Invalid COLOR_MODE_BITS. Valid values are 4, 8, or 24 (default)."); - assert(input_buffer.count >= KEY_SIZE, "The input buffer size must be capable to hold an entire Key, which should be able to hold an UTF8 code (4 bytes) or a terminal escape code (6 bytes)."); -} +#assert(input_buffer.count >= KEY_SIZE); // The input buffer size must be capable to hold an entire Key. -active := false; -input_buffer : [1024] u8; -input_string : string; -input_override : Key; -previous_logger : (message: string, data: *void, info: Log_Info); +#scope_module -module_logger :: (message: string, data: *void, info: Log_Info) { - write_strings(Commands.SaveCursorPosition, Commands.MainScreenBuffer); - previous_logger(message, data, info); - write_strings(Commands.AlternateScreenBuffer, Commands.RestoreCursorPosition); -} assert_is_active :: inline () { assert(active, "Please call setup_terminal() to start using this module."); } +log_tui_error :: (format_string: string, args: .. Any) { + write_strings(Commands.SaveCursorPosition, Commands.MainScreenBuffer); + log_error(format_string, args); + write_strings(Commands.AlternateScreenBuffer, Commands.RestoreCursorPosition); +} + #scope_export; @@ -141,56 +151,7 @@ Commands :: struct #type_info_none { CursorNormalMode :: "\e[?1l"; } -// TODO Check which procedures need the assert_is_active call. -// TODO Review the error messages on the asserts. - -//////////////////////////////////////////////////////////////////////////////// - - -#scope_file - - -#if COLOR_MODE_BITS == 4 { - #load "palette_4b.jai"; - - set_colors :: inline (foreground: Palette, background: Palette) { - print( - #run sprint("%0%0", Commands.SetGraphicsRendition, Commands.SetGraphicsRendition), - cast(u8)foreground + 30, cast(u8)background + 40); - } -} -else #if COLOR_MODE_BITS == 8 { - #load "palette_8b.jai"; - - set_colors :: inline (foreground: Palette, background: Palette) { - print( - #run sprint(Commands.SetGraphicsRendition, "38;5;%;48;5;%"), - cast(u8)foreground, cast(u8)background); - } -} -else { - #load "palette_24b.jai"; - - set_colors :: inline (foreground: Color_24b, background: Color_24b) { - print( - #run sprint(Commands.SetGraphicsRendition, "38;2;%;%;%;48;2;%;%;%"), - foreground.r, foreground.g, foreground.b, - background.r, background.g, background.b); - } -} - -set_font_style :: inline (bold: bool, underline: bool = false, strike_through: bool = false, negative: bool = false) { - print( - #run sprint(Commands.SetGraphicsRendition, "%;%;%;%"), - ifx bold then 1 else 22, - ifx underline then 4 else 24, - ifx strike_through then 9 else 29, - ifx negative then 7 else 27); -} - - -#scope_export - +#add_context terminal_style: Style; Style :: struct { #if COLOR_MODE_BITS == 4 || COLOR_MODE_BITS == 8 { @@ -214,11 +175,32 @@ Style :: struct { negative: bool; } -#add_context terminal_style: Style; - set_style :: inline (style: Style) { - set_font_style(style.bold, style.underline, style.strike_through, style.negative); - set_colors(style.foreground, style.background); + print( + #run sprint(Commands.SetGraphicsRendition, "%;%;%;%"), + ifx style.bold then 1 else 22, + ifx style.underline then 4 else 24, + ifx style.strike_through then 9 else 29, + ifx style.negative then 7 else 27); + + #if COLOR_MODE_BITS == { + case 4; + print( + #run sprint("%0%0", Commands.SetGraphicsRendition, Commands.SetGraphicsRendition), + cast(u8)style.foreground + 30, cast(u8)style.background + 40); + + case 8; + print( + #run sprint(Commands.SetGraphicsRendition, "38;5;%;48;5;%"), + cast(u8)style.foreground, cast(u8)style.background); + + case 24; + print( + #run sprint(Commands.SetGraphicsRendition, "38;2;%;%;%;48;2;%;%;%"), + style.foreground.r, style.foreground.g, style.foreground.b, + style.background.r, style.background.g, style.background.b); + } + context.terminal_style = style; } @@ -286,7 +268,7 @@ Keys :: struct #type_info_none { } to_key :: (str: $T) -> Key #modify { return T == ([]u8) || T == string; } { - assert(str.count <= KEY_SIZE, "Invalid argument passed to to_key(): 'str.count' must be less-than or equal to %, but it was %.", KEY_SIZE, str.count); + assert(str.count <= KEY_SIZE, "Invalid arguments passed to to_key(): 'str' has more than % bytes and cannot be stored as a Key.", KEY_SIZE); k: Key; for 0..str.count-1 { @@ -325,9 +307,6 @@ setup_terminal :: () -> success := true #must { input_string.count = 0; input_override = xx Keys.None; - previous_logger = context.logger; - context.logger = module_logger; - setup_key_map(); write_strings( @@ -355,8 +334,6 @@ reset_terminal :: () -> success := true #must { if !OS_reset_terminal() then return false; - context.logger = previous_logger; - write_strings( Commands.MainScreenBuffer, Commands.RestoreCursorPosition, @@ -446,8 +423,8 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { // At least one of the arguments must be properly setup to avoid an infinite-loop reading the input. read_input :: (count_limit: int = -1, terminators: .. u8) -> string { assert_is_active(); - assert(count_limit >= 0 || terminators.count > 0, "Invalid arguments passed to read_input() will result in infinite-loop."); - + assert(count_limit >= 0 || terminators.count > 0, "Invalid arguments passed to read_input(): when 'count_limit' is less-than 0 (ignored), you need to provide 'terminators' to avoid an infinite-loop."); + // Read until one of the terminator characters is found. // Since we don't know the resulting size of the returned string, we must keep the string builder growing. if count_limit < 0 { @@ -504,7 +481,7 @@ read_input :: (count_limit: int = -1, terminators: .. u8) -> string { // Resize discards the input returning an empty string and a Resize key. read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key { assert_is_active(); - assert(count_limit >= 0, "Invalid value passed to count_limit(): %.", count_limit); + assert(count_limit >= 0, "Invalid arguments passed to read_input_line(): 'count_limit' must be greater-than or equal to 0."); builder := String_Builder.{ allocator = temporary_allocator }; @@ -604,7 +581,7 @@ flush_input :: () { draw_box :: (x: int, y: int, width: int, height: int) { assert_is_active(); - assert(x > 0 && y > 0 && width > 1 && height > 1, "Invalid arguments passed to draw_box(): (%, %, %, %).\n", x, y, width, height); + assert(x > 0 && y > 0 && width > 1 && height > 1, "Invalid arguments passed to draw_box(): 'x' and 'y' must be greater-than 0; 'width' and 'height' must be greater-than 1."); auto_release_temp(); @@ -674,7 +651,7 @@ get_terminal_size :: () -> width: int, height: int { 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."); + "Failed to query window size: invalid response."); parts := split(input, ";",, temporary_allocator); rows = parse_int(*parts[1]); @@ -723,7 +700,7 @@ get_cursor_position :: () -> x: int, y: int { assert(input.count >= 2 && input[0] == FORMAT[0] && input[1] == FORMAT[1] && input[input.count-1] == FORMAT[FORMAT.count-1], - "Query cursor position returned invalid response."); + "Failed to query cursor position: invalid response."); advance(*input, 2); parts := split(input, ";",, temporary_allocator); -- cgit v1.2.3