aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TUI/module.jai46
-rw-r--r--TUI/unix.jai88
-rw-r--r--ttt.jai114
3 files changed, 170 insertions, 78 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
index 044fd65..bfed510 100644
--- a/TUI/module.jai
+++ b/TUI/module.jai
@@ -108,11 +108,13 @@ assert_is_initialized :: inline () {
}
set_next_key :: (key: Key) {
+ assert_is_initialized();
input_override = key;
}
get_key :: (timeout_milliseconds: s32 = -1) -> Key {
-
+ assert_is_initialized();
+
// BBBB BBBB & 1100 0000 == 10XX XXXX -> is continuation byte
is_utf8_continuation_byte :: inline (byte: u8) -> bool {
return (byte & 0xC0) == 0x80;
@@ -196,21 +198,21 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key {
/// /// /// /// /// /// /// /// ///
// DEBUG
- br, bc := get_cursor_position();
- column := 3;
- row += 1;
- nr, rc := get_terminal_size();
-
- if row >= (rc - 5) then row = 5;
-
- set_cursor_position(row, column);
- for 0..input_string.count-1 {
- print("%:% | ",
- FormatInt.{base= 2, minimum_digits = 8, value = input_string[it]},
- FormatInt.{base= 16, minimum_digits = 2, value = input_string[it]},
- ); // TODO DEBUG
- }
- set_cursor_position(br, bc);
+ // br, bc := get_cursor_position();
+ // column := 3;
+ // row += 1;
+ // nr, rc := get_terminal_size();
+ //
+ // if row >= (rc - 5) then row = 5;
+//
+ // set_cursor_position(row, column);
+ // for 0..input_string.count-1 {
+ // print("%:% | ",
+ // FormatInt.{base= 2, minimum_digits = 8, value = input_string[it]},
+ // FormatInt.{base= 16, minimum_digits = 2, value = input_string[it]},
+ // ); // TODO DEBUG
+ // }
+ // set_cursor_position(br, bc);
/// /// /// /// /// /// /// /// ///
advance(*input_string, utf8_bytes);
@@ -221,6 +223,7 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key {
}
get_str :: (count_limit: int = -1, allocator: Allocator = temp) -> string {
+ assert_is_initialized();
assert(allocator.proc != null, "Argument 'allocator.proc' has invalid null value.");
if count_limit < 0 {
@@ -270,6 +273,7 @@ flush_input :: () {
}
draw_box :: (x: int, y: int, width: int, height: int) {
+ assert_is_initialized();
// TODO Check if using a String_Builder improves performance (measure it)!
// TODO Validate input parameters against the terminal size.
@@ -315,13 +319,13 @@ draw_box :: (x: int, y: int, width: int, height: int) {
// TODO Maybe rename to "clear()"
clear_terminal :: inline () {
- assert(initialized, "TUI is not ready.");
+ assert_is_initialized();
write_string(Commands.ClearScreen);
}
// TODO Maybe rename to "get_size()"
get_terminal_size :: () -> rows: int, columns: int {
- assert(initialized, "TUI is not ready.");
+ assert_is_initialized();
rows, columns: int = ---;
#if OS == .WINDOWS {
rows, columns = OS_get_terminal_size();
@@ -359,15 +363,15 @@ get_terminal_size :: () -> rows: int, columns: int {
}
set_cursor_position :: (row: int, column: int) {
- assert(initialized, "TUI is not ready.");
+ assert_is_initialized();
auto_release_temp();
tmp_string := tprint(Commands.SetCursorPosition, row, column);
write_string(tmp_string);
}
get_cursor_position :: () -> row: int, column: int {
- assert(initialized, "TUI is not ready."); // TODO Should I use this inside each and every procedure?
-
+ assert_is_initialized();
+
auto_release_temp();
flush_input();
diff --git a/TUI/unix.jai b/TUI/unix.jai
index 2c34122..03a371b 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -6,19 +6,9 @@
// 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;
+ // cfmakeraw :: (termios: *Terminal_IO_Mode) -> void #foreign libc;
/* https://elixir.bootlin.com/glibc/glibc-2.28/source/termios/cfmakeraw.c#L22
void
cfmakeraw (struct termios *t)
@@ -32,19 +22,81 @@
t->c_cc[VTIME] = 0;
}
*/
-
+
// 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;
+ tcsetattr :: (fd: s32, optional_actions: s32, termios_p : *Terminal_IO_Mode) -> s32 {
+ // TODO IMPLEMENT ME
+
+ #if OS == .LINUX {
+ TCSETS :: 0x5402;
+ TCSETSW :: 0x5403;
+ TCSETSF :: 0x5404;
+ tcflag_t :: u32;
+ cc_t :: u8;
+ __KERNEL_NCCS :: 19;
+ __kernel_termios :: struct {
+ c_iflag : tcflag_t; // input mode flags
+ c_oflag : tcflag_t; // output mode flags
+ c_cflag : tcflag_t; // control mode flags
+ c_lflag : tcflag_t; // local mode flags
+ c_line : cc_t; // line discipline
+ c_cc : [__KERNEL_NCCS]cc_t; // control characters
+ };
+
+ k_termios: __kernel_termios;
+ cmd: u64;
+ if optional_actions == {
+ case xx SetAttributesActions.TCSANOW;
+ cmd = TCSETS;
+ case xx SetAttributesActions.TCSADRAIN;
+ cmd = TCSETSW;
+
+ case xx SetAttributesActions.TCSAFLUSH;
+ cmd = TCSETSF;
+
+ case;
+ return EINVAL;
+ }
+ // k_termios.c_iflag = termios_p.c_iflag & ~IBAUD0;
+ k_termios.c_iflag = xx termios_p.c_iflag;
+ k_termios.c_oflag = xx termios_p.c_oflag;
+ k_termios.c_cflag = xx termios_p.c_cflag;
+ k_termios.c_lflag = xx termios_p.c_lflag;
+ k_termios.c_line = xx termios_p.c_line;
+ // #if _HAVE_C_ISPEED && _HAVE_STRUCT_TERMIOS_C_ISPEED
+ // k_termios.c_ispeed = termios_p->c_ispeed;
+ // #endif
+ // #if _HAVE_C_OSPEED && _HAVE_STRUCT_TERMIOS_C_OSPEED
+ // k_termios.c_ospeed = termios_p->c_ospeed;
+ // #endif
+ memcpy(*k_termios.c_cc[0], *termios_p.c_cc[0], __KERNEL_NCCS * 1);//size_of(cc_t));
+ return ioctl(fd, cmd, *k_termios);
+ }
+ #if OS == .MACOS {
+ // return __ioctl (fd, TIOCSETAF, termios_p);
+ #assert(false, "NOT IMPLEMENTED");
+ }
+ return 0;
+ }
+
// 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 {
+ // TODO IMPLEMENT ME
+ // }
+
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcflush.c.html
- tcflush :: (fd: s32, queue_selector: s32) -> s32 #foreign libc;
-
+ // tcflush :: (fd: s32, queue_selector: s32) -> s32 #foreign libc;
+ tcflush :: inline (fd: s32, queue_selector: s32) -> s32 {
+ TCFLSH :: 0x540B;
+ return ioctl(fd, TCFLSH, queue_selector);
+ }
+
// 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.
@@ -187,7 +239,7 @@ OS_flush_input :: inline () {
}
OS_prepare_terminal :: () {
- tcgetattr(STDIN_FILENO, *initial_tio_mode); // TODO Log on error.
+ tcgetattr(STDIN_FILENO, *initial_tio_mode); // TODO Log error using `log()` from jai/modules/Basic/Print.jai ?
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);
diff --git a/ttt.jai b/ttt.jai
index 49e88eb..b8681ff 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -1182,36 +1182,40 @@ read_enter_confirmation :: inline (row: int, style: int, message: string) -> boo
main :: () {
// -- -- -- Testing TUI -- START
- #if 0 {
- print("test 0\n");
- TUI.test();
- return;
- }
+
+ // TODO Test input
#if 0 {
print("test 1\n");
TUI.start();
buffer: [8] u8;
- brss, error, msg := TUI.OS_read_input(buffer.data, buffer.count);
+ bytes_read, error, 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);
+ if error == true print("error:%\n", error_msg);
+ print("read % bytes:", bytes_read);
+ for 0..bytes_read-1 {
+ char := "-NA-";
+ if buffer[it] >= 33 && buffer[it] <= 126 {
+ char.data = *buffer[it];
+ char.count = 1;
+ }
+ print(" 0x% (%)", FormatInt.{minimum_digits=2, base=10, value=buffer[it]}, char);
+ }
+ print("\n");
TUI.stop();
- return;
}
#if 0 {
print("test 2\n");
- key: TUI.Key = #char "d";
- while(key != #char "q") {
+ _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);
+ bytes_read := TUI.OS_read_input(buffer.data, 1);
+ if bytes_read > 0 {
+ _key = buffer[0];
+ print(">%<", xx _key);
}
else {
print(":");
@@ -1219,43 +1223,72 @@ main :: () {
sleep_milliseconds(10);
}
TUI.stop();
- return;
}
- #if 0 {
- print("testing select\n");
+ if 1 {
+ print("TEST : set and get cursor position --\n", to_standard_error = true);
TUI.start();
- TUI.test();
- TUI.test();
- TUI.test();
+ ROW :: 3;
+ COLUMN :: 3;
+ TUI.set_cursor_position(ROW, COLUMN);
+ row, column := TUI.get_cursor_position();
TUI.stop();
- return;
+ assert(row == ROW && column == COLUMN, "Failed set/get cursor position.\n");
+ print("> success\n", to_standard_error = true);
}
-
- #if 0 {
- print("test 3\n");
+
+ if 1 {
+ print("TEST : test key input --\n", to_standard_error = true);
+ auto_release_temp();
TUI.start();
- key: TUI.Key = #char "d";
+ TUI.clear_terminal();
+ TUI.set_cursor_position(1, 1);
+ write_string("Press q to exit, other key to print it to screen, wait 1s to see animation.");
+ TUI.set_cursor_position(2, 1);
+ key: TUI.Key;
while(key != #char "q") {
__mark := get_temporary_storage_mark();
- // sleep_milliseconds(1000);
- key = TUI.get_key(3000);
-
- if key != xx TUI.Keys.None print_character(key);
+ key = TUI.get_key(1000);
+ if key != xx TUI.Keys.None print_character(cast,force(u8)key);
else write_string("-");
set_temporary_storage_mark(__mark);
}
- print("Waiting 1s..");
- sleep_milliseconds(1000);
- print("!\n\r");
- print("Stoping..");
TUI.stop();
- print("!\n\r");
- return;
+ print("> success\n", to_standard_error = true);
+ }
+
+ if 1 {
+ print("TEST : draw box --\n", to_standard_error = true);
+ auto_release_temp();
+ TUI.start();
+ TUI.clear_terminal();
+ TUI.draw_box(1, 2, 5, 3);
+ TUI.set_cursor_position(1, 1);
+ print("Can you see the box below? (y/n)");
+ key := TUI.get_key();
+ TUI.stop();
+ assert(key == #char "y", "Failed to draw box.\n");
+ print("> success\n", to_standard_error = true);
+ }
+
+ if 1 {
+ print("TEST : get terminal size --\n", to_standard_error = true);
+ auto_release_temp();
+ TUI.start();
+ TUI.clear_terminal();
+ rows, columns := TUI.get_terminal_size();
+ TUI.set_cursor_position(1, 1);
+ print("Is terminal size % columns and % rows? (y/n)", columns, rows);
+ key := TUI.get_key();
+ TUI.stop();
+ assert(key == #char "y", "Failed to get terminal size.\n");
+ print("> success\n", to_standard_error = true);
}
- #if 1 {
- print("test 4\n", to_standard_error = true);
+ // TODO Resizing terminal breaks the tests... try to fix it.
+
+ #if 0 {
+ print("test 5\n", to_standard_error = true);
TUI.start();
TUI.set_terminal_title("bazinga");
xcolumns, xrows: int;
@@ -1286,6 +1319,9 @@ main :: () {
}
TUI.stop();
print("size(CxR): %x%\n", xcolumns, xrows);
+ }
+
+ #if true {
return;
}