aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-10-16 00:48:04 +0100
committerdam <dam@gudinoff>2023-10-16 00:48:04 +0100
commit3b9f4f990ab0e865ec8e6277381e5aff0b178665 (patch)
treee46c7a14b4c2accd97001708768884c101883933
parent27269b059e7a5ae72a85b243919ad849ed672643 (diff)
downloadtask-time-tracker-3b9f4f990ab0e865ec8e6277381e5aff0b178665.tar.zst
task-time-tracker-3b9f4f990ab0e865ec8e6277381e5aff0b178665.zip
First prototype of TUI reading the input using another thread.
-rw-r--r--TUI/module.jai187
-rw-r--r--TUI/unix.jai274
-rw-r--r--ttt.jai151
3 files changed, 399 insertions, 213 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 {
diff --git a/TUI/unix.jai b/TUI/unix.jai
index 434935b..1bfa400 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -6,175 +6,158 @@
// Required to do unlocking input.
libc :: #system_library "libc";
+ // TODO Remote this.
+ cfmakeraw :: (termios: *Terminal_IO_Mode) -> void #foreign libc;
+
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html
- tcsetattr :: (fd : s32, optional_actions : s32, termios_p : *Terminal_IO_Mode) -> s32 #foreign libc;
+ tcsetattr :: (fd: s32, optional_actions: s32, termios_p : *Terminal_IO_Mode) -> s32 #foreign libc;
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
- tcgetattr :: (fd : s32, termios_p : *Terminal_IO_Mode) -> s32 #foreign libc;
+ tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 #foreign libc;
+
+ // Information for the termios.h enums is platform dependent and was retrieved from:
+ // https://elixir.bootlin.com/glibc/latest/source/sysdeps/unix/sysv/linux/bits/termios.h
+ // Set Attributes Actions.
+ SetAttributesActions :: enum u32 {
+ TCSANOW :: 0; // Change immediately.
+ TCSADRAIN :: 1; // Change when pending output is written.
+ TCSAFLUSH :: 2; // Flush pending input before changing.
+ }
// Input modes.
- // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
Input_Modes :: enum_flags u32 {
- IGNBRK; // Ignore break condition.
- BRKINT; // Signal interrupt on break.
- IGNPAR; // Ignore characters with parity errors.
- PARMRK; // Mark parity and framing errors.
-
- INPCK; // Enable input parity check.
- ISTRIP; // Strip 8th bit off characters.
- INLCR; // Map NL to CR on input.
- IGNCR; // Ignore CR.
-
- ICRNL; // Map CR to NL on input.
- IXON; // Enable start/stop output control.
- IXOFF; // Enable start/stop input control.
- IXANY; // Any character will restart after stop.
-
- _1000_;
- IMAXBEL; // Ring bell when input queue is full.
- IUCLC; // Translate upper case input to lower case. not in POSIX
- _8000_;
+ IGNBRK :: 0000001; // Ignore break condition.
+ BRKINT :: 0000002; // Signal interrupt on break.
+ IGNPAR :: 0000004; // Ignore characters with parity errors.
+ PARMRK :: 0000010; // Mark parity and framing errors.
+ INPCK :: 0000020; // Enable input parity check.
+ ISTRIP :: 0000040; // Strip 8th bit off characters.
+ INLCR :: 0000100; // Map NL to CR on input.
+ IGNCR :: 0000200; // Ignore CR.
+ ICRNL :: 0000400; // Map CR to NL on input.
+ IUCLC :: 0001000; // Translate upper case input to lower case (not in POSIX).
+ IXON :: 0002000; // Enable start/stop output control.
+ IXANY :: 0004000; // Any character will restart after stop.
+ IXOFF :: 0010000; // Enable start/stop input control.
+ IMAXBEL :: 0020000; // Ring bell when input queue is full (not in POSIX).
+ IUTF8 :: 0040000; // Input is UTF8 (not in POSIX).
}
-
+
// Output modes.
- // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
Output_Modes :: enum_flags u32 {
- OPOST; // Perform output processing.
- ONLCR; // Map NL to CR-NL on output.
- _UNUSED_0004_;
- ONOEOT; // Discard EOT (^D) on output.
- OCRNL; // Map CR to NL.
- ONOCR; // Discard CR's when on column 0.
- ONLRET; // Move to column 0 on NL.
- _UNUSED_0080_;
+ OPOST :: 0000001; // Perform output processing.
+ OLCUC :: 0000002; // Map lowercase characters to uppercase on output (not in POSIX).
+ ONLCR :: 0000004; // Map NL to CR-NL on output.
+ OCRNL :: 0000010; // Map CR to NL.
+ ONOCR :: 0000020; // Discard CR's when on column 0.
+ ONLRET :: 0000040; // Move to column 0 on NL.
+ OFILL :: 0000100; // Send fill characters for delays.
+ OFDEL :: 0000200; // Fill is DEL.
+ VTDLY :: 0040000; // Select vertical-tab delays:
+ VT0 :: 0000000; // Vertical-tab delay type 0.
+ VT1 :: 0040000; // Vertical-tab delay type 1.
}
-
+
// Control modes.
- // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
- Control_Modes :: enum_flags u32 {
- CIGNORE; // Ignore these control flags.
- _0002_;
- _0004_;
- _0008_;
-
- _0010_;
- _0020_;
- _0040_;
- _0080_;
-
- _0100_;
- _0200_;
- CSTOPB; // Two stop bits instead of one.
- CREAD; // Enable receiver.
-
- PARENB; // Parity enable.
- PARODD; // Odd parity instead of even.
- HUPCL; // Hang up on last close.
- CLOCAL; // Ignore modem status lines.
-
- CRTSCTS; // RTS/CTS flow control.
- CDTRCTS; // DTR/CTS flow control.
- _0004_0000_;
- _0008_0000_;
-
- MDMBUF; // DTR/DCD flow control.
+ Control_Modes :: enum u32 {
+ CS5 :: 0000000; // 5 bits per byte.
+ CS6 :: 0000020; // 6 bits per byte.
+ CS7 :: 0000040; // 7 bits per byte.
+ CS8 :: 0000060; // 8 bits per byte.
+ CSIZE :: 0000060; // Number of bits per byte (mask).
+ CSTOPB :: 0000100; // Two stop bits instead of one.
+ CREAD :: 0000200; // Enable receiver.
+ PARENB :: 0000400; // Parity enable.
+ PARODD :: 0001000; // Odd parity instead of even.
+ HUPCL :: 0002000; // Hang up on last close.
+ CLOCAL :: 0004000;
}
-
- CHWFLOW :Control_Modes : (.MDMBUF | .CRTSCTS | .CDTRCTS); // All types of flow control.
- CS5 :Control_Modes : 0x0000; // 5 bits per byte.
- CS6 :Control_Modes : 0x0100; // 6 bits per byte.
- CS7 :Control_Modes : 0x0200; // 7 bits per byte.
- CS8 :Control_Modes : CS6|CS7; // 8 bits per byte.
- CSIZE :Control_Modes : CS5|CS6|CS7|CS8; // Number of bits per byte (mask).
-
+
// Local modes.
- // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
Local_Modes :: enum_flags u32 {
- ECHOKE; // Visual erase for KILL.
- ECHOE; // Visual erase for ERASE.
- ECHOK; // Echo NL after KILL.
- ECHO; // Enable echo.
-
- ECHONL; // Echo NL even if ECHO is off.
- ECHOPRT; // Hardcopy visual erase.
- ECHOCTL; // Echo control characters as ^X.
- ISIG; // Enable signals.
-
- ICANON; // Do erase and kill processing.
- ALTWERASE; // Alternate WERASE algorithm.
- IEXTEN; // Enable DISCARD and LNEXT.
- EXTPROC; // External processing.
-
- _1000_;
- _2000_;
- _4000_;
- _8000_;
-
- _0001_0000_;
- _0002_0000_;
- // TODO Maybe reduce the amount of unused flags by setting the value when there are holes on the table.
- // TOSTOP :: 0x0004_0000; // Send SIGTTOU for background output.
- TOSTOP; // Send SIGTTOU for background output.
- FLUSHO; // Output being flushed (state).
-
- XCASE; // Canonical upper/lower case.
- NOKERNINFO; // Disable VSTATUS.
- _0040_0000_;
- _0080_0000_;
-
- _0100_0000_;
- PENDIN; // Retype pending input (state).
- _0400_0000_;
- NOFLSH; // Disable flush after interrupt.
+ ISIG :: 0000001; // Enable signals.
+ ICANON :: 0000002; // Do erase and kill processing.
+ ECHO :: 0000010; // Enable echo.
+ ECHOE :: 0000020; // Visual erase for ERASE.
+ ECHOK :: 0000040; // Echo NL after KILL.
+ ECHONL :: 0000100; // Echo NL even if ECHO is off.
+ NOFLSH :: 0000200; // Disable flush after interrupt.
+ TOSTOP :: 0000400; // Send SIGTTOU for background output.
+ IEXTEN :: 0100000; // Enable DISCARD and LNEXT.
}
- Terminal_IO_Mode :: struct {
- c_iflag : Input_Modes; // Input mode flags.
- c_oflag : Output_Modes; // Output mode flags.
- c_cflag : Control_Modes; // Control modes flags.
- c_lflag : Local_Modes; // Local modes flags.
- c_line : u8; // Line discipline.
- c_cc : [32]u8; // Control characters.
- c_ispeed : u32; // Input speed (baud rates).
- c_ospeed : u32; // Output speed (baud rates).
+ // Control Characters
+ Control_Chars :: enum u8 {
+ VINTR :: 0;
+ VQUIT :: 1;
+ VERASE :: 2;
+ VKILL :: 3;
+ VEOF :: 4;
+ VTIME :: 5; // Time-out value (tenths of a second) [!ICANON].
+ VMIN :: 6; // Minimum number of bytes read at once [!ICANON].
+ VSWTC :: 7;
+ VSTART :: 8;
+ VSTOP :: 9;
+ VSUSP :: 10;
+ VEOL :: 11;
+ VREPRINT :: 12;
+ VDISCARD :: 13;
+ VWERASE :: 14;
+ VLNEXT :: 15;
+ VEOL2 :: 16;
}
-
+ // The struct termios.
+ Terminal_IO_Mode :: struct {
+ c_iflag : Input_Modes; // Input mode flags.
+ c_oflag : Output_Modes; // Output mode flags.
+ c_cflag : Control_Modes; // Control modes flags.
+ c_lflag : Local_Modes; // Local modes flags.
+ c_line : u8; // Line discipline.
+ c_cc : [32]Control_Chars;// Control characters.
+ c_ispeed : u32; // Input speed (baud rates).
+ c_ospeed : u32; // Output speed (baud rates).
+ }
+
initial_tio_mode: Terminal_IO_Mode;
- default_tio_mode: Terminal_IO_Mode; // TODO Rename to 'raw_tio_mode'
- human_tio_mode: Terminal_IO_Mode; // TODO Rename to 'cooked_tio_mode'
+ raw_tio_mode: Terminal_IO_Mode;
#scope_export
OS_prepare_terminal :: () {
- tcgetattr(STDIN_FILENO, *initial_tio_mode);
-
- default_tio_mode = initial_tio_mode;
- default_tio_mode.c_iflag &= ~(.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXOFF);
- default_tio_mode.c_oflag &= ~(.OPOST);
- default_tio_mode.c_cflag &= ~(CSIZE | .PARENB);
- default_tio_mode.c_lflag &= ~(.ECHOCTL |.ECHO | .ECHOE | .ECHOKE);
-
- human_tio_mode = default_tio_mode;
- human_tio_mode.c_iflag |= (.IXOFF | .ICRNL);
- human_tio_mode.c_lflag |= (.NOKERNINFO | .ECHO | .ECHOE | .ECHOKE);
-
- tcsetattr(STDIN_FILENO, 0, *default_tio_mode);
+ error: s32;
+ tcgetattr(STDIN_FILENO, *initial_tio_mode); // TODO Log on error.
+ raw_tio_mode = initial_tio_mode;
+ raw_tio_mode.c_iflag &= ~(.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXON);
+ raw_tio_mode.c_oflag &= ~(.OPOST);
+ 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;
+ tcsetattr(STDIN_FILENO, 0, *raw_tio_mode); // TODO Log on error.
}
OS_reset_terminal :: () {
- tcsetattr(STDIN_FILENO, 0, *initial_tio_mode);
+ tcsetattr(STDIN_FILENO, 0, *initial_tio_mode); // TODO Log on error.
}
OS_get_terminal_size :: () -> rows: int, columns: int {
auto_release_temp();
- input := talloc_string(64);
+ flush_input();
+
+ // input := talloc_string(64);
write_string(Commands.QueryWindowSizeInChars);
- input.count = OS_read_input(input.data, input.count);
+ // 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.
@@ -182,6 +165,7 @@ OS_get_terminal_size :: () -> rows: int, columns: int {
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, ";");
@@ -190,17 +174,17 @@ OS_get_terminal_size :: () -> rows: int, columns: int {
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 = *default_tio_mode;
- }
- tcsetattr(STDIN_FILENO, 0, tio_mode);
- // TODO get_error_value_and_string :: () -> (error_code: OS_Error_Code, description: string)
-}
+// 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);
diff --git a/ttt.jai b/ttt.jai
index a78cf30..0515262 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -1181,50 +1181,125 @@ read_enter_confirmation :: inline (row: int, style: int, message: string) -> boo
main :: () {
- // -- -- -- TODO WIP Testing TUI -- START
- TUI.start();
- TUI.clear_terminal();
- rows, columns := TUI.get_terminal_size();
- TUI.draw_box(1, 1, columns, rows);
- TUI.set_cursor_position(4, 4);
- c_row, c_column := TUI.get_cursor_position();
- TUI.set_cursor_position(3, 3);
- input := TUI.read_input();
+ #if 0 {
+ print("test 0\n");
+ TUI.test();
+ return;
+ }
- // sleep_milliseconds(5000);
- TUI.stop();
- print("- - -\n");
- print("window r:c = %:%\n", rows, columns);
- print("cursor r:c = %:%\n", c_row, c_column);
- print("input = %\n", input);
- return;
+ #if 0 {
+ print("test 1\n");
+ TUI.start();
+ buffer: [8] u8;
+ brss, error, msg := TUI.OS_read_input(buffer.data, buffer.count);
+ TUI.stop();
+ if error == true print("error:%", msg);
+ print("br:%", brss);
+ print("input:%", cast(string)buffer);
+ TUI.stop();
+ return;
+ }
+ #if 0 {
+ print("test 2\n");
+ key: TUI.Key = #char "d";
+ while(key != #char "q") {
+ // key = TUI.get_key(10);
+ buffer: [8] u8;
+ buffer[0] = 0;
+ brss := TUI.OS_read_input(buffer.data, 1);
+ if brss > 0 {
+ key = buffer[0];
+ print(">%<", xx key);
+ }
+ else {
+ print(":");
+ }
+ sleep_milliseconds(10);
+ }
+ TUI.stop();
+ return;
+ }
- str: string;
+ #if 1 {
+ print("test 3\n");
+ TUI.start();
+ key: TUI.Key = #char "d";
+ while(key != #char "q") {
+ __mark := get_temporary_storage_mark();
+ key = TUI.get_key(3000);
+ // sleep_milliseconds(10);
+
+ if key != xx TUI.Keys.None print_character(key);
+ else write_string("-");
+ set_temporary_storage_mark(__mark);
+ }
+ TUI.stop();
+ 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;
- write_string("\e(0"); // Enter Line drawing mode
- write_string("\e[104;93m"); // bright yellow on bright blue
- write_string("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar"
- write_string("\e[10m"); // restore color
- write_string("\e(B"); // exit line drawing mode
- sleep_milliseconds(1000);
+ // -- -- -- TODO WIP Testing TUI -- START
+ // TUI.start();
+ // TUI.clear_terminal();
+ // rows, columns := TUI.get_terminal_size();
+ // TUI.draw_box(1, 1, columns, rows);
+ // TUI.set_cursor_position(4, 4);
+ // c_row, c_column := TUI.get_cursor_position();
+ // TUI.set_cursor_position(3, 3);
+ // input := TUI.read_input();
- // str = "\e[sWOW\e[u\e[1P";
- str = "\e[sWOW";
- // write(STDIN_FILENO, str.data, xx str.count);
- write_string(str);
- sleep_milliseconds(1000);
-
- str = "\e[?25l";
- // write(STDIN_FILENO, str.data, xx str.count);
- write_string(str);
- sleep_milliseconds(1000);
-
- str = "\e[?25h";
- // write(STDIN_FILENO, str.data, xx str.count);
- write_string(str);
- return;
+ // sleep_milliseconds(5000);
+ // TUI.stop();
+ // print("- - -\n");
+ // print("window r:c = %:%\n", rows, columns);
+ // print("cursor r:c = %:%\n", c_row, c_column);
+ // print("input = %\n", input);
+ // return;
+//
+//
+ // str: string;
+//
+ // write_string("\e(0"); // Enter Line drawing mode
+ // write_string("\e[104;93m"); // bright yellow on bright blue
+ // write_string("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar"
+ // write_string("\e[10m"); // restore color
+ // write_string("\e(B"); // exit line drawing mode
+ // sleep_milliseconds(1000);
+
+
+ // // str = "\e[sWOW\e[u\e[1P";
+ // str = "\e[sWOW";
+ // // write(STDIN_FILENO, str.data, xx str.count);
+ // write_string(str);
+ // sleep_milliseconds(1000);
+ //
+ // str = "\e[?25l";
+ // // write(STDIN_FILENO, str.data, xx str.count);
+ // write_string(str);
+ // sleep_milliseconds(1000);
+ //
+ // str = "\e[?25h";
+ // // write(STDIN_FILENO, str.data, xx str.count);
+ // write_string(str);
+ // return;
// -- -- -- TODO WIP Testing TUI -- STOP