diff options
Diffstat (limited to 'TUI/module.jai')
| -rw-r--r-- | TUI/module.jai | 187 |
1 files changed, 157 insertions, 30 deletions
diff --git a/TUI/module.jai b/TUI/module.jai index 034ec15..7a7dc54 100644 --- a/TUI/module.jai +++ b/TUI/module.jai @@ -8,6 +8,7 @@ #import "Basic"; #import "String"; +#import "Thread"; Drawings :: struct { CornerBR :: "\x6A"; @@ -84,18 +85,144 @@ Commands :: struct { initialized := false; +input_buffer_mutex: Mutex; +input_buffer: string; +input_counter: s64; +read_buffer: [4096] u8; + +input_process_thread: Thread; + +Key :: u8; // TODO To be improved. +Keys :: enum u8 { + None :: 0; + Resize :: 1; //410; // TODO Why?! +} + +input_semaphore: Semaphore; +key_semaphore: Semaphore; +key_mutex: Mutex; +key_input := Keys.None; +key_resize := Keys.None; +// key_queue: [2] Key; // TODO Queue with size 1!? hmmm nice! +// key_queue_idx := 0; + + + +// queue_semaphore: Semaphore; +// queue_mutex: Mutex; +// queue :: Keys; + +// Notes +// So, the semaphore usage should indicate the items on the key_queue. +// If we don't want to use a queue, maybe we can use two Key items, one for user input, and another, with higher priority, for Resize. + +dam :: (msg: string) { + print(msg, to_standard_error = true); +} + +process_input :: (thread: *Thread) -> s64 { + char: u8; + dam(">START signal_input\n"); + defer dam(">STOP signal_input\n"); + while(true) { + if initialized == false return 0; + if key_input != Keys.None { // TODO Reading without mutex... + dam("waiting.."); + sleep_milliseconds(100); + dam("!\n\r"); + continue; + } + dam("reading.."); + bytes_read := OS_read_input(*char, 1); + dam("!\n\r"); + if bytes_read > 0 { + lock(*key_mutex); + defer unlock(*key_mutex); + key_input = xx char; + dam("signaling.."); + dam("!\n\r"); + signal(*key_semaphore); + } + } + return 0; +} + +process_resize :: (signal : s32) #c_call { + new_context : Context; + push_context new_context { + if signal != SIGWINCH return; + lock(*key_mutex); + defer unlock(*key_mutex); + // TODO Only signal the key_semaphore if we don't already have a Resize on the queue. + if key_resize != Key.None continue; + key_resize = Keys.Resize; + signal(*key_semaphore); + } +} + +get_key :: (wait_milliseconds: s32) -> Key { + wait_for(*key_semaphore, wait_milliseconds); + + lock(*key_mutex); + defer unlock(*key_mutex); + + if key_resize != Keys.None { + defer key_resize = Keys.None; + return xx key_resize; + } + + defer key_input = Keys.None; + return xx key_input; +} + + start :: () { - if initialized return; - write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8); + if initialized == true return; +dam("A"); + // write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8); OS_prepare_terminal(); +dam("B"); + input_buffer = alloc_string(4096); + init(*input_buffer_mutex, "input_buffer_mutex"); + assert(thread_init(*input_process_thread, process_input), "Failed to initialize thread."); +dam("C"); + // init(*input_semaphore); + init(*key_semaphore); + init(*key_mutex, "key_mutex"); +dam("D"); initialized = true; + thread_start(*input_process_thread); +dam("E"); } stop :: () { if initialized == false return; initialized = false; + + // signal(*input_semaphore); // TODO Maybe use tcflush ??? + thread_deinit(*input_process_thread); + + // destroy(*input_semaphore); + destroy(*key_semaphore); + OS_reset_terminal(); - write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor); + // write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor); +} + +get_str :: () -> string { + lock(*input_buffer_mutex); + defer unlock(*input_buffer_mutex); + return input_buffer; + // return tprint("%", to_string(input_buffer)); + // print("%", tprint("%", input_buffer)); + // return tprint("%", input_buffer); +} + +flush_input :: () { + // TODO + lock(*input_buffer_mutex); + defer unlock(*input_buffer_mutex); + input_buffer.count = 0; } draw_box :: (x: int, y: int, width: int, height: int) { @@ -191,33 +318,33 @@ Input_Mode :: enum u8 { MACHINE; // Hides cursor, hides input, and reads right away once the first input is available. } -read_input :: (allocator: Allocator = temp, $mode: Input_Mode = .HUMAN) -> string { - #if mode == .HUMAN { - write_string(Commands.ShowCursor); - defer write_string(Commands.HideCursor); - - OS_set_input_mode(.HUMAN); - defer OS_set_input_mode(.MACHINE); - } - - assert(allocator.proc != null, "Argument 'allocator.proc' has invalid null value."); - - #assert(mode != .MACHINE); // TODO Keep an eye if I try to use read_input for machine read. Eventually, remove mode from the procedure arguments. - - builder: String_Builder(); - builder.allocator = allocator; - init_string_builder(*builder); - - while(1) { - 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 == 0 || buffer_data[buffer.count-1] == #char "\n" break; - assert(buffer.count == buffer.allocated); // TODO If newline wasn't detected, it's because the buffer got full. - expand(*builder); - } - return builder_to_string(*builder, allocator); -} +// read_input :: (allocator: Allocator = temp, $mode: Input_Mode = .HUMAN) -> string { + // #if mode == .HUMAN { + // write_string(Commands.ShowCursor); + // defer write_string(Commands.HideCursor); + // + // OS_set_input_mode(.HUMAN); + // defer OS_set_input_mode(.MACHINE); + // } +// + // assert(allocator.proc != null, "Argument 'allocator.proc' has invalid null value."); +// + // #assert(mode != .MACHINE); // TODO Keep an eye if I try to use read_input for machine read. Eventually, remove mode from the procedure arguments. + // + // builder: String_Builder(); + // builder.allocator = allocator; + // init_string_builder(*builder); + // + // while(1) { + // 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 == 0 || buffer_data[buffer.count-1] == #char "\n" break; + // assert(buffer.count == buffer.allocated); // TODO If newline wasn't detected, it's because the buffer got full. + // expand(*builder); + // } + // return builder_to_string(*builder, allocator); +// } #if OS == .WINDOWS { |
