aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/TUI/module.jai137
-rw-r--r--modules/TUI/unix.jai14
-rw-r--r--modules/TUI/windows.jai34
3 files changed, 81 insertions, 104 deletions
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);
diff --git a/modules/TUI/unix.jai b/modules/TUI/unix.jai
index 940ac80..99cc61d 100644
--- a/modules/TUI/unix.jai
+++ b/modules/TUI/unix.jai
@@ -230,7 +230,7 @@ restore_resize_handler :: () {
////////////////////////////////////////////////////////////////////////////////
-#scope_export
+#scope_module
OS_prepare_terminal :: () -> success := true {
error: int = ---;
@@ -238,7 +238,7 @@ OS_prepare_terminal :: () -> success := true {
error = tcgetattr(STDIN_FILENO, *initial_tio_mode);
if error {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to get initial_tio_mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to get initial_tio_mode: code %, %", error_code, error_string);
return false;
}
@@ -254,7 +254,7 @@ OS_prepare_terminal :: () -> success := true {
error = tcsetattr(STDIN_FILENO, xx Optional_Actions.TCSANOW, *raw_tio_mode);
if error {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to set raw_tio_mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to set raw_tio_mode: code %, %", error_code, error_string);
return false;
}
@@ -268,7 +268,7 @@ OS_reset_terminal :: () -> success := true {
error := tcsetattr(STDIN_FILENO, xx Optional_Actions.TCSANOW, *initial_tio_mode);
if error {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to set initial_tio_mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to set initial_tio_mode: code %, %", error_code, error_string);
return false;
}
return;
@@ -278,7 +278,7 @@ OS_flush_input :: () -> success := true {
error := tcflush(STDIN_FILENO, xx Queue_Selector.TCIFLUSH);
if error {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to flush input: code %, %", error_code, error_string);
+ log_tui_error("Failed to flush input: code %, %", error_code, error_string);
return false;
}
return;
@@ -288,7 +288,7 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success :
bytes_read := read(STDIN_FILENO, buffer, xx bytes_to_read);
if bytes_read < 0 {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to read input: code %, %", error_code, error_string);
+ log_tui_error("Failed to read input: code %, %", error_code, error_string);
return 0, false;
}
return bytes_read;
@@ -306,7 +306,7 @@ OS_wait_for_input :: (timeout_milliseconds: s32 = -1) -> is_input_available: boo
error_code, error_string := get_error_value_and_string();
// Ignore window resize events (error_code 4).
if error_code != 4 {
- log_error("Unexpected error while waiting for input: code %, %", error_code, error_string);
+ log_tui_error("Unexpected error while waiting for input: code %, %", error_code, error_string);
return false, false;
}
}
diff --git a/modules/TUI/windows.jai b/modules/TUI/windows.jai
index fb50e49..f8d8bc8 100644
--- a/modules/TUI/windows.jai
+++ b/modules/TUI/windows.jai
@@ -142,7 +142,7 @@ peek_input :: () -> INPUT_RECORD, success := true {
records_read: u32;
if PeekConsoleInputW(stdin, *record, 1, *records_read) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to peek input: code %, %", error_code, error_string);
+ log_tui_error("Failed to peek input: code %, %", error_code, error_string);
return record, false;
}
return record;
@@ -153,7 +153,7 @@ read_input :: () -> INPUT_RECORD, success := true {
records_read: u32;
if ReadConsoleInputW(stdin, *record, 1, *records_read) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to read input: code %, %", error_code, error_string);
+ log_tui_error("Failed to read input: code %, %", error_code, error_string);
return record, false;
}
return record;
@@ -163,7 +163,7 @@ count_input :: () -> u32, success := true {
count: u32;
if GetNumberOfConsoleInputEvents(stdin, *count) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to count input: code %, %", error_code, error_string);
+ log_tui_error("Failed to count input: code %, %", error_code, error_string);
return 0, false;
}
return count;
@@ -171,7 +171,7 @@ count_input :: () -> u32, success := true {
////////////////////////////////////////////////////////////////////////////////
-#scope_export
+#scope_module
OS_prepare_terminal :: () -> success := true {
@@ -179,12 +179,12 @@ OS_prepare_terminal :: () -> success := true {
stdin = GetStdHandle(STD_INPUT_HANDLE);
if stdin == INVALID_HANDLE_VALUE {
error_code, error_string := get_error_value_and_string();
- log_error("Invalid input handler: code %, %", error_code, error_string);
+ log_tui_error("Invalid input handler: code %, %", error_code, error_string);
return false;
}
if xx GetConsoleMode(stdin, *initial_stdin_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to get input mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to get input mode: code %, %", error_code, error_string);
return false;
}
raw_stdin_mode = (cast(Console_Input_Mode) initial_stdin_mode);
@@ -193,7 +193,7 @@ OS_prepare_terminal :: () -> success := true {
if xx SetConsoleMode(stdin, xx raw_stdin_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to set input mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to set input mode: code %, %", error_code, error_string);
return false;
}
@@ -201,12 +201,12 @@ OS_prepare_terminal :: () -> success := true {
stdout = GetStdHandle(STD_OUTPUT_HANDLE);
if stdout == INVALID_HANDLE_VALUE {
error_code, error_string := get_error_value_and_string();
- log_error("Invalid output handler: code %, %", error_code, error_string);
+ log_tui_error("Invalid output handler: code %, %", error_code, error_string);
return false;
}
if xx GetConsoleMode(stdout, *initial_stdout_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to get output mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to get output mode: code %, %", error_code, error_string);
return false;
}
raw_stdout_mode = (cast(Console_Output_Mode) initial_stdout_mode);
@@ -214,7 +214,7 @@ OS_prepare_terminal :: () -> success := true {
if xx SetConsoleMode(stdout, xx raw_stdout_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to set output mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to set output mode: code %, %", error_code, error_string);
return false;
}
@@ -231,12 +231,12 @@ OS_prepare_terminal :: () -> success := true {
OS_reset_terminal :: () -> success := true {
if xx SetConsoleMode(stdin, initial_stdin_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to reset input mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to reset input mode: code %, %", error_code, error_string);
return false;
}
if xx SetConsoleMode(stdout, initial_stdout_mode) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to reset output mode: code %, %", error_code, error_string);
+ log_tui_error("Failed to reset output mode: code %, %", error_code, error_string);
return false;
}
return;
@@ -247,7 +247,7 @@ OS_flush_input :: () {
// Attempting to empty the input queue all at once can destroy state in the queue in an unexpected manner.
if FlushConsoleInputBuffer(stdin) == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to flush input: code %, %", error_code, error_string);
+ log_tui_error("Failed to flush input: code %, %", error_code, error_string);
}
}
@@ -255,7 +255,7 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success :
S32_MAX :: 0x7fff_ffff;
if (bytes_to_read > S32_MAX) {
- log_error("The Windows API only allows to read up to 2^32 bytes from the standard input. Clamping input argument.");
+ log_tui_error("The Windows API only allows to read up to 2^32 bytes from the standard input. Clamping input argument.");
bytes_to_read = S32_MAX;
}
@@ -288,14 +288,14 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success :
success = ReadConsoleW(stdin, widechar_view.data, chars_to_read, *widechar_view.count, null);
if success == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to read console: code %, %", error_code, error_string);
+ log_tui_error("Failed to read console: code %, %", error_code, error_string);
return 0, false;
}
result:, success = wide_to_utf8_new(widechar_view.data, xx widechar_view.count);
if success == false {
error_code, error_string := get_error_value_and_string();
- log_error("Failed to convert from wide to utf8: code %, %", error_code, error_string);
+ log_tui_error("Failed to convert from wide to UTF8: code %, %", error_code, error_string);
return 0, false;
}
@@ -338,7 +338,7 @@ OS_wait_for_input :: (timeout_milliseconds: s32 = -1) -> is_input_available: boo
if wait_result == WAIT_FAILED {
error_code, error_string := get_error_value_and_string();
- log_error("Error while waiting for input: code %, %", error_code, error_string);
+ log_tui_error("Error while waiting for input: code %, %", error_code, error_string);
return false, false;
}