aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authordam <devnull@localhost>2024-04-15 12:38:18 +0100
committerdam <devnull@localhost>2024-04-15 12:38:18 +0100
commit3112131c24ede1ea343383ffd4f8ca7bc4783f47 (patch)
treeb1541d366eb42a1ea2ef5c4a889e045e8dc45119 /modules
parent5844ab303d3d7fc396beb7c6d8a0104496608f08 (diff)
downloadtask-time-tracker-3112131c24ede1ea343383ffd4f8ca7bc4783f47.tar.zst
task-time-tracker-3112131c24ede1ea343383ffd4f8ca7bc4783f47.zip
Add module logger that switches between main/alternate screen buffers to write logs.
Diffstat (limited to 'modules')
-rw-r--r--modules/TUI/module.jai27
-rw-r--r--modules/TUI/windows.jai44
2 files changed, 35 insertions, 36 deletions
diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai
index 3843cd7..070161c 100644
--- a/modules/TUI/module.jai
+++ b/modules/TUI/module.jai
@@ -17,6 +17,11 @@
#import "UTF8";
#load "key_map.jai";
+#run {
+ assert(COLOR_MODE == 4 || COLOR_MODE == 8 || COLOR_MODE == 24, "Invalid COLOR_MODE. 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).");
+}
+
// Special Graphics Characters
Drawings :: struct {
Blank :: "\x5F";
@@ -271,9 +276,15 @@ input_buffer : [1024] u8;
input_string : string;
input_override : Key;
-#run {
- assert(COLOR_MODE == 4 || COLOR_MODE == 8 || COLOR_MODE == 24, "Invalid COLOR_MODE. 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).");
+previous_logger : (message: string, data: *void, info: Log_Info);
+
+module_logger :: (message: string, data: *void, info: Log_Info) {
+ // print("%0%0\n%0", Commands.MainScreenBuffer, message, Commands.AlternateScreenBuffer);
+ x, y := get_cursor_position();
+ write_string(Commands.MainScreenBuffer);
+ previous_logger(message, data, info);
+ write_string(Commands.AlternateScreenBuffer);
+ set_cursor_position(x, y);
}
assert_is_active :: inline () {
@@ -444,7 +455,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
}
else {
set_cursor_position(x, y);
- for 0..chars_count print_character(#char "*");
+ for 1..chars_count print_character(#char "*");
for chars_count..count_limit-1 print_character(#char " ");
}
set_cursor_position(x+idx, y);
@@ -510,7 +521,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
start :: () {
if active == true return;
-
+
// TODO Should start() call flush_input internally?
setup_key_map(); // TODO This is being called multiple times... please fix me!
@@ -526,6 +537,9 @@ start :: () {
Commands.SetUTF8,
Commands.CursorNormalMode,
Commands.KeypadNumMode);
+
+ previous_logger = context.logger;
+ context.logger = module_logger;
OS_prepare_terminal();
@@ -538,6 +552,9 @@ stop :: () {
clear_style();
OS_reset_terminal();
+
+ context.logger = previous_logger;
+
write_strings(Commands.MainScreenBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor);
}
diff --git a/modules/TUI/windows.jai b/modules/TUI/windows.jai
index 5155a3f..5755ef4 100644
--- a/modules/TUI/windows.jai
+++ b/modules/TUI/windows.jai
@@ -72,21 +72,6 @@
Y : SHORT;
}
- SMALL_RECT :: struct {
- Left : SHORT;
- Top : SHORT;
- Right : SHORT;
- Bottom : SHORT;
- }
-
- CONSOLE_SCREEN_BUFFER_INFO :: struct {
- dwSize : COORD;
- dwCursorPosition : COORD;
- wAttributes : WORD;
- srWindow : SMALL_RECT;
- dwMaximumWindowSize : COORD;
- }
-
INPUT_RECORD_EVENT_TYPE :: enum u16 {
KEY_EVENT :: 0x0001;
MOUSE_EVENT :: 0x0002;
@@ -148,7 +133,7 @@
was_resized: bool;
- windows_buffer: [512] u16;
+ widechar_buffer: [512] u16;
peek_input :: inline () -> INPUT_RECORD, success := true {
@@ -187,8 +172,6 @@ count_input :: inline () -> u32, success := true {
#scope_export
-// TODO All the log_error calls will be hidden by the terminal setup... we should store the logs internally, or write it to a file.
-
OS_prepare_terminal :: () {
// stdin
@@ -256,7 +239,7 @@ OS_reset_terminal :: () {
}
OS_flush_input :: inline () {
- /* NOTE
+ /*
This API is not recommended and does not have a virtual terminal equivalent.
Attempting to empty the input queue all at once can destroy state in the queue in an unexpected manner.
*/
@@ -295,19 +278,19 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success :
}
else {
- chars_view: [] u16;
- chars_view.data = windows_buffer.data;
+ widechar_view: [] u16;
+ widechar_view.data = widechar_buffer.data;
- chars_to_read := ifx available_inputs <= windows_buffer.count then available_inputs else windows_buffer.count;
+ chars_to_read := ifx available_inputs <= widechar_buffer.count then available_inputs else widechar_buffer.count;
- success = ReadConsoleW(stdin, chars_view.data, chars_to_read, *chars_view.count, null);
+ 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);
return 0, false;
}
- result:, success = wide_to_utf8_new(chars_view.data, xx chars_view.count);
+ 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);
@@ -335,13 +318,12 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success :
// 0: do not wait
// -1: wait indefinitely
OS_wait_for_input :: (timeout_milliseconds: s32 = -1) -> is_input_available: bool, success := true {
-
- /* TODO
- Add a good comment explaining how the windows part of the module was implemented... what's the idea behind it.
- Something like, Since windows provides a single input buffer with all events, we need to peek through them and
- discard the ones that are of no use for us.
- Because it's a single buffer, all functions need to do repeated work (see if it's resize, see if it's a key press)
- ... and so on.
+ /*
+ The Windows API provides all input events (keyboard, mouse, window resize) on a single input buffer.
+ To make it match this module's API, we need to do some pre-processing while waiting for input.
+ This means that OS_wait_for_input will peek at the input events, signal if a window resize is found,
+ and discard unwanted events (like button release events).
+ A similar logic is applied in OS_read_input.
*/
expiration := current_time_monotonic() + to_apollo(timeout_milliseconds / 1000.0);