aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/TUI/module.jai8
-rw-r--r--modules/TUI/unix.jai140
2 files changed, 112 insertions, 36 deletions
diff --git a/modules/TUI/module.jai b/modules/TUI/module.jai
index b5866d5..5fd29f6 100644
--- a/modules/TUI/module.jai
+++ b/modules/TUI/module.jai
@@ -1,5 +1,7 @@
#module_parameters(COLOR_MODE := 24);
+#scope_file
+
#if OS == {
case .LINUX;
#load "unix.jai";
@@ -22,6 +24,8 @@
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).");
}
+#scope_export;
+
// Special Graphics Characters
Drawings :: struct {
Blank :: "\x5F";
@@ -441,7 +445,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
// > https://unix.stackexchange.com/questions/255707/what-are-the-keyboard-shortcuts-for-the-command-line
x, y := get_cursor_position();
- write_strings(Commands.StartBlinking, Commands.BlinkingBarShape);
+ write_strings(Commands.ShowCursor, Commands.StartBlinking, Commands.BlinkingBarShape);
key := Keys.None;
while true {
@@ -515,7 +519,7 @@ read_input_line :: (count_limit: int, is_visible: bool = true) -> string, Key {
}
}
- write_strings(Commands.StopBlinking, Commands.DefaultShape);
+ write_strings(Commands.StopBlinking, Commands.DefaultShape, Commands.HideCursor);
result := ifx key == Keys.Enter then str else "";
return result, key;
diff --git a/modules/TUI/unix.jai b/modules/TUI/unix.jai
index 7103d47..8eeb6c0 100644
--- a/modules/TUI/unix.jai
+++ b/modules/TUI/unix.jai
@@ -1,5 +1,10 @@
#scope_file
+/*
+TODO : then log all error on unix...
+TODO : then do a good implementation of the libc functions about attributes...
+*/
+
#import "Atomics";
#import "System";
#import "POSIX";
@@ -7,22 +12,6 @@
// Required to do unlocking input.
libc :: #system_library "libc";
- // TODO Remove this.
- // 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)
- {
- t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- t->c_oflag &= ~OPOST;
- t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- t->c_cflag &= ~(CSIZE|PARENB);
- t->c_cflag |= CS8;
- t->c_cc[VMIN] = 1; // read returns when one char is available.
- 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 {
@@ -82,10 +71,68 @@
}
// 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
- // }
+ // tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 #foreign libc;
+ tcgetattr :: (fd: s32, termios_p: *Terminal_IO_Mode) -> s32 {
+ 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
+ };
+
+
+ // int
+ // __tcgetattr (int fd, struct termios *termios_p)
+ // {
+ // struct __kernel_termios k_termios;
+ k_termios: __kernel_termios;
+ retval: int;
+ retval = ioctl(fd, TCGETS, *k_termios);
+ if retval == 0 {
+ termios_p.c_iflag = xx k_termios.c_iflag;
+ termios_p.c_oflag = xx k_termios.c_oflag;
+ termios_p.c_cflag = xx k_termios.c_cflag;
+ termios_p.c_lflag = xx k_termios.c_lflag;
+ termios_p.c_line = xx k_termios.c_line;
+ // #if _HAVE_STRUCT_TERMIOS_C_ISPEED
+ // # if _HAVE_C_ISPEED
+ // termios_p->c_ispeed = k_termios.c_ispeed;
+ // # else
+ // termios_p->c_ispeed = k_termios.c_cflag & (CBAUD | CBAUDEX);
+ // # endif
+ // #endif
+ // #if _HAVE_STRUCT_TERMIOS_C_OSPEED
+ // # if _HAVE_C_OSPEED
+ // termios_p->c_ospeed = k_termios.c_ospeed;
+ // # else
+ // termios_p->c_ospeed = k_termios.c_cflag & (CBAUD | CBAUDEX);
+ // # endif
+ // #endif
+ size_of_cc_t := __KERNEL_NCCS * 1;
+ memcpy(*termios_p.c_cc[0], *k_termios.c_cc[0], size_of_cc_t);
+ // memset(*termios_p.c_cc[0] + size_of_cc_t + 1, _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * 1);
+ //
+ // if (sizeof (cc_t) == 1 || _POSIX_VDISABLE == 0 || (unsigned char) _POSIX_VDISABLE == (unsigned char) -1) {
+ // memset (__mempcpy (&termios_p->c_cc[0], &k_termios.c_cc[0], __KERNEL_NCCS * sizeof (cc_t)), _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * sizeof (cc_t));
+ // }
+ // else
+ // {
+ // memcpy (&termios_p->c_cc[0], &k_termios.c_cc[0], __KERNEL_NCCS * sizeof (cc_t));
+ // for (size_t cnt = __KERNEL_NCCS; cnt < NCCS; ++cnt) {
+ // termios_p->c_cc[cnt] = _POSIX_VDISABLE;
+ // }
+ // }
+ }
+ return xx retval;
+ }
// https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcflush.c.html
// tcflush :: (fd: s32, queue_selector: s32) -> s32 #foreign libc;
@@ -232,8 +279,15 @@ restore_resize_handler :: () {
#scope_export
-OS_prepare_terminal :: () {
- tcgetattr(STDIN_FILENO, *initial_tio_mode); // TODO Log error using `log()` from jai/modules/Basic/Print.jai ?
+OS_prepare_terminal :: () -> success := true { // On critical paths, we may use the #must for the success return value.
+ error: int = ---;
+
+ error = tcgetattr(STDIN_FILENO, *initial_tio_mode);
+ if error {
+ error_code, error_string := get_error_value_and_string();
+ log_error("Failed to get initial_tio_mode: code %, %", error_code, error_string);
+ }
+
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);
@@ -242,28 +296,48 @@ OS_prepare_terminal :: () {
raw_tio_mode.c_cflag |= .CS8;
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.
-
+
+ error = tcsetattr(STDIN_FILENO, 0, *raw_tio_mode);
+ if error {
+ error_code, error_string := get_error_value_and_string();
+ log_error("Failed to set raw_tio_mode: code %, %", error_code, error_string);
+ return false;
+ }
+
was_resized = false;
prepare_resize_handler();
+ return;
}
-OS_reset_terminal :: () {
+OS_reset_terminal :: inline () -> success := true {
restore_resize_handler();
- tcsetattr(STDIN_FILENO, 0, *initial_tio_mode); // TODO Log on error.
+ error := tcsetattr(STDIN_FILENO, 0, *initial_tio_mode);
+ if error {
+ error_code, error_string := get_error_value_and_string();
+ log_error("Failed to set initial_tio_mode: code %, %", error_code, error_string);
+ return false;
+ }
+ return;
}
-OS_flush_input :: inline () {
+OS_flush_input :: inline () -> success := true {
TCIFLUSH :: 0; // TODO Is this always zero in all systems?
- tcflush(STDIN_FILENO, TCIFLUSH);
+ error := tcflush(STDIN_FILENO, TCIFLUSH);
+ if error {
+ error_code, error_string := get_error_value_and_string();
+ log_error("Failed to flush input: code %, %", error_code, error_string);
+ return false;
+ }
+ return;
}
// TODO Nothing is checking for the errors returned by this... shame!
-OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, error: bool = false, error_message: string = "" {
+OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, success := true {
bytes_read := read(STDIN_FILENO, buffer, xx bytes_to_read);
if bytes_read < 0 {
- error_code, error_message := get_error_value_and_string();
- return -1, true, error_message;
+ error_code, error_string := get_error_value_and_string();
+ log_error("Failed to read input: code %, %", error_code, error_string);
+ return 0, false;
}
return bytes_read;
}
@@ -279,8 +353,6 @@ OS_wait_for_input :: (timeout_milliseconds: s32 = -1) -> is_input_available: boo
return ifx poll_return > 0 then true else false;
}
-// TODO This procedure hides the behaviour of reseting on read.
-// We should have the `was_resized` on module.jai so that we know it may be used in another thread.
OS_was_terminal_resized :: () -> bool {
- return atomic_swap(*was_resized, false); // TODO If the windows implementation is similar, we may push this into the main module file.
+ return atomic_swap(*was_resized, false);
}