aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TUI/module.jai280
-rw-r--r--TUI/unix.jai56
-rw-r--r--sizeof.c35
-rw-r--r--ttt.jai58
4 files changed, 198 insertions, 231 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
index 6854d59..6ca6f59 100644
--- a/TUI/module.jai
+++ b/TUI/module.jai
@@ -84,13 +84,8 @@ Commands :: struct {
initialized := false;
-
-input_buffer_mutex: Mutex;
-input_buffer: string;
-input_counter: s64;
-read_buffer: [4096] u8;
-
-input_process_thread: Thread;
+input_buffer : [64] u8;
+input_string : string;
Key :: u8; // TODO To be improved.
Keys :: enum u8 {
@@ -98,152 +93,94 @@ Keys :: enum u8 {
Resize :: 1; //410; // TODO Why?!
}
-key_semaphore: Semaphore;
-key_mutex: Mutex;
-key_input := Keys.None;
-key_resize := Keys.None;
-key_buffer: [64] 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 {
- buffer: [64] u8;
- input: string;
- // 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 {
- dam("waiting..");
- sleep_milliseconds(100); // We could increase this value as a push-back mechanism if we're just hitting it repeateadly.
- dam("!\n\r");
- continue;
- }
- if input.count > 0 {
- lock(*key_mutex);
- key_input = xx input[0];
- unlock(*key_mutex);
- signal(*key_semaphore);
-
- advance(*input);
- continue;
- }
-
- // dam("reading..");
- bytes_read := OS_read_input(buffer.data, buffer.count);
- input.data = buffer.data;
- input.count = bytes_read;
- }
- return 0;
+push_key :: (key: Key) {
+ // TODO
}
-process_resize :: (signal_code : s32) #c_call {
- new_context : Context;
- push_context new_context {
- print("SIGNAL:%", signal_code);
- if signal_code != SIGWINCH return;
- print("RESIZE\n");
- 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 != Keys.None return;
- key_resize = Keys.Resize;
- signal(*key_semaphore);
- }
-}
+get_key :: (timeout_milliseconds: s32 = -1) -> Key {
-get_key :: (wait_milliseconds: s32) -> Key {
- wait_for(*key_semaphore, wait_milliseconds);
-
- lock(*key_mutex);
- defer unlock(*key_mutex);
+ if OS_was_terminal_resized() return xx Keys.Resize;
- if key_resize != Keys.None {
- defer key_resize = Keys.None;
- return xx key_resize;
+ if input_string.count > 0 {
+ defer advance(*input_string, 1);
+ return input_string[0];
}
- defer key_input = Keys.None;
- return xx key_input;
-}
+ is_input_available := OS_wait_for_input(timeout_milliseconds);
+ if OS_was_terminal_resized() return xx Keys.Resize;
-// TODO Rename this procedure.
-set_handler :: () {
- sa : sigaction_t;
- sa.sa_handler = process_resize;
- sigemptyset(*(sa.sa_mask));
- sa.sa_flags = SA_RESTART;
- sigaction(SIGWINCH, *sa, null);
+ if is_input_available {
+ bytes_read := OS_read_input(input_buffer.data, input_buffer.count); // TODO Does not check for read errors.
+ if bytes_read > 0 {
+ input_string.data = input_buffer.data;
+ input_string.count = bytes_read;
+ defer advance(*input_string, 1);
+ return input_string[0];
+ }
+ }
+ return xx Keys.None;
}
-// TODO Rename this procedure.
-restore_handler :: () {
- sa : sigaction_t;
- sa.sa_handler = SIG_DFL;
- sigaction(SIGWINCH, null, *sa);
+get_str :: (str_limit: int = -1, allocator: Allocator = temp) -> string {
+ assert(allocator.proc != null, "Argument 'allocator.proc' has invalid null value.");
+
+ if str_limit < 0 {
+ 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 < buffer.allocated break;
+ expand(*builder);
+ }
+ return builder_to_string(*builder, allocator);
+ }
+ else {
+ buffer := alloc_string(str_limit, allocator);
+ buffer.count = OS_read_input(buffer.data, str_limit);
+ return buffer;
+ }
}
start :: () {
if initialized == true return;
-dam("A");
- // write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8);
+
+ 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(*key_semaphore);
- init(*key_mutex, "key_mutex");
-dam("D");
+
+ was_resized = false;
+ init(*resize_mutex, "resize_mutex");
+ input_string.data = input_buffer.data;
+ input_string.count = 0;
+
initialized = true;
- thread_start(*input_process_thread);
+
set_handler(); // TODO Move to beter place.
-dam("E");
-
}
stop :: () {
if initialized == false return;
initialized = false;
-
restore_handler(); // TODO Move to beter place.
- print(">A<");
- thread_deinit(*input_process_thread);
- print(">B<");
- destroy(*key_semaphore);
- print(">C<");
OS_reset_terminal();
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) {
@@ -299,7 +236,31 @@ clear_terminal :: inline () {
// TODO Maybe rename to "get_size()"
get_terminal_size :: () -> rows: int, columns: int {
assert(initialized, "TUI is not ready.");
- rows, columns := OS_get_terminal_size();
+ rows, columns: int = ---;
+ #if OS == .WINDOWS {
+ rows, columns = OS_get_terminal_size();
+ }
+ else {
+ auto_release_temp();
+
+ flush_input();
+ write_string(Commands.QueryWindowSizeInChars);
+
+ input := get_str(64);
+
+ // Expected message format: [8;<r>;<c>t
+ // where <r> is the number of rows and <c> of columns.
+ assert(
+ input[0] == #char "\e" &&
+ input[1] == #char "[" &&
+ input[2] == #char "8",
+ //input[input.count-1] == #char "t",
+ "Query window size in chars returned invalid response.");
+
+ parts := split(input, ";");
+ rows = parse_int(*parts[1]);
+ columns = parse_int(*parts[2]);
+ }
return rows, columns;
}
@@ -313,11 +274,11 @@ get_cursor_position :: () -> row: int, column: int {
assert(initialized, "TUI is not ready."); // TODO Should I use this inside each and every procedure?
auto_release_temp();
-
+
+ flush_input();
write_string(Commands.QueryCursorPosition);
- input := talloc_string(64);
- input.count = OS_read_input(input.data, input.count); // TODO Does not check for read errors.
+ input := get_str(64);
// Expected message format: \e[<r>;<c>R
// where <r> is the number of rows and <c> of columns.
@@ -334,43 +295,58 @@ get_cursor_position :: () -> row: int, column: int {
return row, column;
}
-Input_Mode :: enum u8 {
- HUMAN; // Shows cursor, echoes input, and expects an enter at the end of the line.
- 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);
-// }
-
#if OS == .WINDOWS {
// Prototyping zone... keep clear!
}
else #if OS == .LINUX || OS == .MACOS {
// Prototyping zone... keep clear!
+
+ OS_wait_for_input :: (timeout_milliseconds: s32) -> is_input_available: bool {
+ fds := pollfd.[ .{ fd = STDIN_FILENO, events = POLLIN, revents = 0 } ];
+ nfds := fds.count;
+ poll_return := poll(fds.data, xx nfds, xx timeout_milliseconds); // TODO Wait for input using poll syscall. This breaks and throws '-1 | 4 | Interrupted system call' when we resize the window while polling.
+ error_code, error_message := get_error_value_and_string();
+ return ifx poll_return > 0 then true else false;
+ }
+
+ resize_mutex : Mutex;
+ was_resized : bool;
+
+ OS_was_terminal_resized :: () -> bool {
+ lock(*resize_mutex);
+ defer unlock(*resize_mutex);
+ defer was_resized = false;
+ return was_resized;
+ }
+
+ process_resize :: (signal_code : s32) #c_call {
+ new_context : Context;
+ push_context new_context {
+ print("SIGNAL:%", signal_code);
+ if signal_code != SIGWINCH then return;
+ if was_resized == true then return;
+ print("RESIZE\n");
+ lock(*resize_mutex);
+ defer unlock(*resize_mutex);
+ was_resized = true;
+ }
+ }
+
+ // TODO Rename this procedure.
+ set_handler :: () {
+ sa : sigaction_t;
+ sa.sa_handler = process_resize;
+ sigemptyset(*(sa.sa_mask));
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGWINCH, *sa, null);
+ }
+
+ // TODO Rename this procedure.
+ restore_handler :: () {
+ sa : sigaction_t;
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGWINCH, null, *sa);
+ }
+
}
diff --git a/TUI/unix.jai b/TUI/unix.jai
index 1bfa400..a35a60a 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -6,6 +6,16 @@
// Required to do unlocking input.
libc :: #system_library "libc";
+
+ // int poll(struct pollfd *fds, nfds_t nfds, int timeout);
+ pollfd :: struct {
+ fd : s32; // File descriptor.
+ events : s16; // Requested events.
+ revents : s16; // Returned events.
+ };
+
+ poll :: (fds: *pollfd, nfds: u32, timeout: s32) -> s32 #foreign libc;
+
// TODO Remote this.
cfmakeraw :: (termios: *Terminal_IO_Mode) -> void #foreign libc;
@@ -135,8 +145,8 @@ OS_prepare_terminal :: () {
raw_tio_mode.c_lflag &= ~(.ECHO | .ECHONL | .ICANON | .ISIG | .IEXTEN);
raw_tio_mode.c_cflag &= ~(.CSIZE | .PARENB);
raw_tio_mode.c_cflag |= .CS8;
- raw_tio_mode.c_cc[Control_Chars.VMIN] = 0;
- raw_tio_mode.c_cc[Control_Chars.VTIME] = 1;
+ raw_tio_mode.c_cc[Control_Chars.VMIN] = 1;
+ raw_tio_mode.c_cc[Control_Chars.VTIME] = 0;
tcsetattr(STDIN_FILENO, 0, *raw_tio_mode); // TODO Log on error.
}
@@ -144,48 +154,6 @@ OS_reset_terminal :: () {
tcsetattr(STDIN_FILENO, 0, *initial_tio_mode); // TODO Log on error.
}
-OS_get_terminal_size :: () -> rows: int, columns: int {
-
- auto_release_temp();
-
- flush_input();
-
- // input := talloc_string(64);
- write_string(Commands.QueryWindowSizeInChars);
- // input.count = OS_read_input(input.data, input.count);
- sleep_milliseconds(1); //TODO WHYYYY??? GOD DAMIT THREADS...
- input := get_str();
- // input[0] = #char "x";
- // print(">%<", xx input);
- // print("#<#");
-
- // Expected message format: [8;<r>;<c>t
- // where <r> is the number of rows and <c> of columns.
- assert(
- input[0] == #char "\e" &&
- input[1] == #char "[" &&
- input[2] == #char "8",
- //input[input.count-1] == #char "t",
- "Query windows size in chars returned invalid response.");
-
- parts := split(input, ";");
- rows := parse_int(*parts[1]);
- columns := parse_int(*parts[2]);
- return rows, columns;
-}
-
-// OS_set_input_mode :: (mode: Input_Mode) {
- // tio_mode: *Terminal_IO_Mode = ---;
- // if mode == {
- // case .HUMAN;
- // tio_mode = *human_tio_mode;
- // case;
- // tio_mode = *cooked_tio_mode;
- // }
- // tcsetattr(STDIN_FILENO, 0, tio_mode);
- // // TODO get_error_value_and_string :: () -> (error_code: OS_Error_Code, description: string)
-// }
-
OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, error: bool = false, error_message: string = "" {
bytes_read := read(STDIN_FILENO, buffer, xx bytes_to_read);
if bytes_read < 0 {
diff --git a/sizeof.c b/sizeof.c
index 9025f78..c260c31 100644
--- a/sizeof.c
+++ b/sizeof.c
@@ -18,32 +18,33 @@
#include <time.h>
int main(int argc, char **argv) {
- initscr();
+ // initscr();
fprintf(stderr, "sizeof char: %d\n", sizeof(char));
fprintf(stderr, "sizeof short: %d\n", sizeof(short));
fprintf(stderr, "sizeof int: %d\n", sizeof(int));
+ fprintf(stderr, "sizeof long: %d\n", sizeof(long));
fprintf(stderr, "sizeof unsigned: %d\n", sizeof(unsigned));
fprintf(stderr, "sizeof chtype: %d\n", sizeof(chtype));
- int w_size_x, w_size_y;
- getmaxyx(stdscr, w_size_y, w_size_x);
- char str[64];
- memset(str, 0, 64);
- sprintf(str, "x,y : %dx%d\n", w_size_x, w_size_y);
- mvaddstr(2, 2, str);
- sprintf(str, "resize:%d\n", KEY_RESIZE);
- mvaddstr(3, 2, str);
+ // int w_size_x, w_size_y;
+ // getmaxyx(stdscr, w_size_y, w_size_x);
+ // char str[64];
+ // memset(str, 0, 64);
+ // sprintf(str, "x,y : %dx%d\n", w_size_x, w_size_y);
+ // mvaddstr(2, 2, str);
+ // sprintf(str, "resize:%d\n", KEY_RESIZE);
+ // mvaddstr(3, 2, str);
- unsigned m = ACS_DIAMOND;
+ // unsigned m = ACS_DIAMOND;
fprintf(stderr, "sizeof ACS %d\n", sizeof(ACS_DIAMOND));
-
- if (ACS_DIAMOND != 0 || ACS_URCORNER != 0){
- fprintf(stderr, "BAZINGA\n");
- }
+ //
+ // if (ACS_DIAMOND != 0 || ACS_URCORNER != 0){
+ // fprintf(stderr, "BAZINGA\n");
+ // }
// fprintf(stderr, ">%d<\n", strlen(ACS_DIAMOND));
- mvaddch(0, 0, m);
- getch();
- endwin();
+ // mvaddch(0, 0, m);
+ // getch();
+ // endwin();
}
diff --git a/ttt.jai b/ttt.jai
index 8edc8b4..9ab3db6 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -1221,7 +1221,17 @@ main :: () {
return;
}
- #if 1 {
+ #if 0 {
+ print("testing select\n");
+ TUI.start();
+ TUI.test();
+ TUI.test();
+ TUI.test();
+ TUI.stop();
+ return;
+ }
+
+ #if 0 {
print("test 3\n");
TUI.start();
key: TUI.Key = #char "d";
@@ -1242,23 +1252,35 @@ main :: () {
print("!\n\r");
return;
}
-
- // TUI.start_new_mode();
- // sleep_milliseconds(3000);
- xrows, xcolumns := TUI.get_terminal_size();
- TUI.draw_box(1, 1, xcolumns, xrows);
- // print("<beep>");
- bbb: [64] u8;
-
- br, err, err_msg := TUI.OS_read_input(bbb.data, 5);
- print(">%/%/%/%\n", cast(string)bbb, br, err, err_msg);
- sleep_milliseconds(3000);
- // coisa := TUI.get_str();
- // print("\n>%<\n", coisa);
- print("stopping\n");
- // TUI.stop_new_mode();
- TUI.stop();
- return;
+
+ #if 1 {
+ print("test 4\n", to_standard_error = true);
+ TUI.start();
+ xcolumns, xrows: int;
+ key: TUI.Key = #char "d";
+ while(key != #char "q") {
+ __mark := get_temporary_storage_mark();
+ TUI.set_cursor_position(3, 3);
+ write_string("dam ");
+ print("%:%", xcolumns, xrows);
+ key = TUI.get_key(3000);
+ if key == xx TUI.Keys.None {
+ write_string(">bazinga<");
+ sleep_milliseconds(1000);
+ }
+ else if key == xx TUI.Keys.Resize {
+ TUI.clear_terminal();
+ xrows, xcolumns = TUI.get_terminal_size();
+ TUI.draw_box(1, 1, xcolumns, xrows);
+ }
+ else {
+ print_character(key);
+ }
+ }
+ TUI.stop();
+ print("size(CxR): %x%\n", xcolumns, xrows);
+ return;
+ }
// -- -- -- TODO WIP Testing TUI -- START