aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-09-20 18:00:20 +0100
committerdam <dam@gudinoff>2023-09-20 18:00:20 +0100
commit65adffcf572c98c0198affcdf729d989fec253ae (patch)
tree31f2c0fe7ca0cec7e7b932bb6c2f8126a7577bac
parent9e2fc467ad0e779734d836656875cf92bcb5732a (diff)
downloadtask-time-tracker-65adffcf572c98c0198affcdf729d989fec253ae.tar.zst
task-time-tracker-65adffcf572c98c0198affcdf729d989fec253ae.zip
Moved TUI into a module with split OS-based implementations.
-rw-r--r--TUI/module.jai194
-rw-r--r--TUI/unix.jai63
-rw-r--r--TUI/windows.jai111
-rw-r--r--ttt.jai4
-rw-r--r--tui.jai363
5 files changed, 370 insertions, 365 deletions
diff --git a/TUI/module.jai b/TUI/module.jai
new file mode 100644
index 0000000..67a9edd
--- /dev/null
+++ b/TUI/module.jai
@@ -0,0 +1,194 @@
+#if OS == .WINDOWS {
+ #load "windows.jai";
+} else #if (OS == .LINUX) || (OS == .MACOS) {
+ #load "unix.jai";
+} else {
+ #assert(false, "Unsupported OS.");
+}
+
+#import "String";
+
+// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#designate-character-set
+// https://github.com/MicrosoftDocs/Console-Docs/blob/main/docs/console-virtual-terminal-sequences.md
+
+isTUIActive := false; // TODO Rename this variable.
+
+
+Drawings :: struct {
+ CornerBR :: "\x6A";
+ CornerTR :: "\x6B";
+ CornerTL :: "\x6C";
+ CornerBL :: "\x6D";
+ Cross :: "\x6E";
+ LineH :: "\x71";
+ TeeL :: "\x74";
+ TeeR :: "\x75";
+ TeeB :: "\x76";
+ TeeT :: "\x77";
+ LineV :: "\x78";
+
+ Blank :: "\x5F";
+ Diamond :: "\x60";
+ Checkerboard :: "\x61";
+ PlusMinus :: "\x67";
+ LessThanOrEqual :: "\x79";
+ GreaterThanOrEqual :: "\x7A";
+ Pi :: "\x7B";
+ NotEqual :: "\x7C";
+ CenteredDot :: "\x7E";
+}
+
+Commands :: struct {
+ EnterAlternateBuffer :: "\e[?1049h";
+ EnterMainBuffer :: "\e[?1049l";
+
+ EnterDrawingMode :: "\e(0";
+ EnterNormalMode :: "\e(B";
+ ClearScreen :: "\e[2J";
+ ClearLine :: "\e[2K";
+
+ RefreshWindow :: "\e[7t"; // TODO Not yet tested.
+
+ SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE
+
+ // Cursor Visibility
+ ShowCursor :: "\e[?25h";
+ HideCursor :: "\e[?25l";
+ StartBlinking :: "\e[?25h]";
+ StopBlinking :: "\e[?25l]";
+ SaveCursorPosition :: "\e7";
+ RestoreCursorPosition :: "\e8";
+
+ // Cursor Shape
+ DefaultShape :: "\e[0 q";
+ BlinkingBlockShape :: "\e[1 q";
+ SteadyBlockShape :: "\e[2 q";
+ BlinkingUnderlineShape :: "\e[3 q";
+ SteadyUnderlineShape :: "\e[4 q";
+ BlinkingBarShape :: "\e[5 q";
+ SteadyBarShape :: "\e[6 q";
+
+ // Input Mode
+ KeypadAppMode :: "\e=";
+ KeypadNumMode :: "\e>";
+ CursorAppMode :: "\e[?1h";
+ CursorNormalMode :: "\e[?1l";
+
+ // Query State
+ QueryCursorPosition :: "\e[6n"; // Emits the cursor position as: "ESC [ <r> ; <c> R" Where <r> = row and <c> = column.
+ QueryDeviceAttributes :: "\e[0c";
+ QueryWindowSizeInChars :: "\e[18t"; // Emits the window size as: "ESC [ 8 <r> ; <c> t" Where <r> = row and <c> = column.
+
+}
+
+start :: () {
+ OS_prepare_terminal();
+ write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8);
+ isTUIActive = true;
+}
+
+stop :: () {
+ isTUIActive = false;
+ write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor);
+ OS_reset_terminal();
+}
+
+draw_box :: (x: int, y: int, width: int, height: int, to_standard_error := false) {
+
+
+ // TODO Hardcoded box starting at 1,1... fix this!
+
+ write_strings(
+ // Commands.EnterNormalMode,
+ Commands.EnterDrawingMode,
+ "\e[1;1H", // Move to position 1,1
+ // TODO // Move pointer to top-left corner.
+ Drawings.CornerTL,
+ to_standard_error = to_standard_error);
+
+ for 1..width-2 {
+ write_string(Drawings.LineH, to_standard_error = to_standard_error);
+ }
+ write_string(Drawings.CornerTR, to_standard_error = to_standard_error);
+
+
+ // TODO Take care of the temporary allocations.
+ for idx: 2..height-1 {
+ tmpL := tprint("\e[%;%H", idx, 1);
+ tmpR := tprint("\e[%;%H", idx, width);
+ write_strings(
+ tmpL,
+ Drawings.LineV,
+ tmpR,
+ Drawings.LineV,
+ to_standard_error = to_standard_error);
+ }
+
+ tmpBL := tprint("\e[%;%H", height, 1);
+ write_strings(
+ tmpBL,
+ Drawings.CornerBL,
+ to_standard_error = to_standard_error);
+ for 1..width-2 {
+ write_string(Drawings.LineH, to_standard_error = to_standard_error);
+ }
+ write_string(Drawings.CornerBR, to_standard_error = to_standard_error);
+
+ write_strings(
+ // TODO // print
+ Commands.EnterNormalMode,
+ to_standard_error = to_standard_error);
+}
+
+clear_screen :: inline () {
+ write_string(Commands.ClearScreen);
+}
+
+get_terminal_size :: () -> rows: int, columns: int {
+ rows, columns := OS_get_terminal_size();
+ return rows, columns;
+}
+
+// read_input: () -> string {
+ // return OS_read_input();
+// }
+
+// get_cursor_position :: () -> row: int, column: int {
+// assert(isTUIActive, "TUI is not active."); // TODO
+// write_string(TUI.Commands.QueryCursorPosition); // Returned "\e[21;1R"
+// read_input()
+// }
+
+
+// read_input: () -> string;
+
+#if OS == .WINDOWS {
+
+ // #run read_input = () -> string {
+ read_input :: () -> string {
+ MAX_BYTES_TO_READ :: 1024;
+ temp : [MAX_BYTES_TO_READ] u8;
+ result: string = ---;
+ bytes_read : s32;
+
+ if !ReadConsoleA( stdin, temp.data, xx temp.count, *bytes_read )
+ return "";
+
+ result.data = alloc(bytes_read);
+ result.count = bytes_read;
+ memcpy(result.data, temp.data, bytes_read);
+ return result;
+ };
+}
+else #if OS == .LINUX || OS == .MACOS {
+ #import "Basic";
+ #import "POSIX";
+
+ read_input :: () -> string {
+ buffer: [8192] u8;
+ bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
+ str := to_string(buffer.data, bytes_read);
+ return str;
+ };
+}
diff --git a/TUI/unix.jai b/TUI/unix.jai
new file mode 100644
index 0000000..439447d
--- /dev/null
+++ b/TUI/unix.jai
@@ -0,0 +1,63 @@
+#import "POSIX";
+
+
+ __term : My_Termios;
+
+ My_Termios :: struct {
+ c_iflag : u32; // Input mode flags.
+ c_oflag : u32; // Output mode flags.
+ c_cflag : u32; // Control modes flags.
+ c_lflag : u32; // 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).
+ }
+
+ // Required to do unlocking input.
+ libc :: #system_library "libc";
+
+ // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html
+ tcsetattr :: (fd : s32, optional_actions : s32, termios_p : *My_Termios) -> s32 #foreign libc;
+
+ // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
+ tcgetattr :: (fd : s32, termios_p : *My_Termios) -> s32 #foreign libc;
+
+
+OS_prepare_terminal :: () {
+ // TODO Required to do unlocking input.
+ tcgetattr(STDIN_FILENO, *__term);
+ term_new := __term;
+
+ term_new.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+ term_new.c_oflag &= 0xFFFFFFFE;// ~OPOST;
+ term_new.c_lflag &= 0xFFFF7FB4;// ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ term_new.c_cflag &= 0xFFFFFECF;// ~(CSIZE | PARENB);
+ term_new.c_cflag |= 0x00000030;
+
+ tcsetattr(STDIN_FILENO, 0, *term_new);
+}
+
+OS_reset_terminal :: () {
+ tcsetattr(STDIN_FILENO, 0, *__term); // return echo
+}
+
+OS_get_terminal_size :: () -> rows: int, columns: int {
+ buffer: [512] u8;
+ write_string(Commands.QueryWindowSizeInChars);
+ bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
+
+ str := to_string(buffer.data, bytes_read);
+
+ // Result: [8;79;156t
+ assert(
+ buffer.data[0] == #char "\e" &&
+ buffer.data[1] == #char "[" &&
+ buffer.data[2] == #char "8",
+ "Query windows size in chars returned invalid response.");
+
+ parts := split(str, ";");
+ rows := parse_int(*parts[1]);
+ columns := parse_int(*parts[2]);
+ return rows, columns;
+}
diff --git a/TUI/windows.jai b/TUI/windows.jai
new file mode 100644
index 0000000..ef0cfa8
--- /dev/null
+++ b/TUI/windows.jai
@@ -0,0 +1,111 @@
+#import "Windows";
+
+
+ kernel32 :: #system_library "kernel32";
+
+ GetConsoleScreenBufferInfo :: (hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) -> bool #foreign kernel32;
+ ReadConsoleA :: (hConsoleHandle: HANDLE, buff : *u8, chars_to_read : s32, chars_read : *s32, lpInputControl := *void ) -> bool #foreign kernel32;
+ // ReadConsole :: (hConsoleInput: HANDLE, lpBuffer: *u8, nNumberOfCharsToRead: s32, lpNumberOfCharsRead: *s32, pInputControl := *void) -> bool #foreign kernel32;
+ GetConsoleMode :: (hConsoleHandle: HANDLE, lpMode: *u32) -> bool #foreign kernel32;
+ SetConsoleMode :: (hConsoleHandle: HANDLE, dwMode: u32) -> bool #foreign kernel32;
+ GetLastError :: () -> s32 #foreign kernel32;
+
+ ENABLE_VIRTUAL_TERMINAL_INPUT :: 0x0200;
+
+ ENABLE_PROCESSED_OUTPUT :: 0x0001;
+ ENABLE_WRAP_AT_EOL_OUTPUT :: 0x0002;
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING :: 0x0004;
+ DISABLE_NEWLINE_AUTO_RETURN :: 0x0008;
+ ENABLE_LVB_GRID_WORLDWIDE :: 0x0010;
+
+ SHORT :: s16;
+ WORD :: u16;
+ DWORD :: s32;
+
+ COORD :: struct {
+ X : SHORT;
+ Y : SHORT;
+ }
+
+ SMALL_RECT :: struct {
+ Left : SHORT;
+ Top : SHORT;
+ Right : SHORT;
+ Bottom : SHORT;
+ }
+
+ CONSOLE_SCREEN_BUFFER_INFO :: struct {
+ dwSize : COORD;
+ dwCursorPosition : COORD;
+
+ wAttributes : WORD;
+ srWindow : SMALL_RECT;
+ dwMaximumWindowSize : COORD;
+ }
+
+
+ stdin: HANDLE;
+ initial_stdin_mode: u32;
+ stdout: HANDLE;
+ initial_stdout_mode: u32;
+
+
+OS_prepare_terminal :: () {
+ print("TODO TUI\n", to_standard_error = true);
+
+
+ // stdin
+ stdin = GetStdHandle(STD_INPUT_HANDLE );
+ if stdin == INVALID_HANDLE_VALUE {
+ print("Invalid input handler.", to_standard_error = true);
+ return;
+ }
+ if GetConsoleMode(stdin, *initial_stdin_mode) == false {
+ print("Failed to get input mode.", to_standard_error = true);
+ return;
+ }
+ if SetConsoleMode(stdin, initial_stdin_mode | ENABLE_VIRTUAL_TERMINAL_INPUT) == false {
+ print("Failed to set input mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+
+ // stdout
+ stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ outMode: u32 = 0;
+ if stdout == INVALID_HANDLE_VALUE {
+ print("Invalid output handler.", to_standard_error = true);
+ return;
+ }
+ if GetConsoleMode(stdout, *initial_stdout_mode) == false {
+ print("Failed to get output mode.", to_standard_error = true);
+ return;
+ }
+ if SetConsoleMode(stdout, initial_stdout_mode | ENABLE_PROCESSED_OUTPUT| ENABLE_VIRTUAL_TERMINAL_PROCESSING) == false {
+ print("Failed to set output mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+}
+
+OS_reset_terminal :: () {
+ print("TODO TUI\n", to_standard_error = true);
+
+ if SetConsoleMode(stdin, initial_stdin_mode) == false {
+ print("Failed to reset input mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+
+ if SetConsoleMode(stdout, initial_stdout_mode) == false {
+ print("Failed to reset output mode: %.", GetLastError(), to_standard_error = true);
+ return;
+ }
+}
+
+OS_get_terminal_size :: () -> rows: int, columns: int {
+
+ ScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO;
+ GetConsoleScreenBufferInfo(stdout, *ScreenBufferInfo);
+ columns := ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1;
+ rows := ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1;
+
+ return rows, columns;
+}
diff --git a/ttt.jai b/ttt.jai
index 588be28..0cd8ead 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -28,7 +28,7 @@
// #import "curses";
// #import "kscurses";
TIO :: #import "tio"; // TODO Move things into TUI.
-TUI :: #import "tui";
+TUI :: #import "TUI";
#load "Integer_Saturating_Arithmetic.jai";
@@ -1184,7 +1184,7 @@ main :: () {
// -- -- -- TODO WIP Testing TUI -- START
TUI.start();
TUI.clear_screen();
- rows, columns := TUI.get_buffer_size();
+ rows, columns := TUI.get_terminal_size();
TUI.draw_box(1,1,columns, rows);
sleep_milliseconds(1500);
TUI.stop();
diff --git a/tui.jai b/tui.jai
deleted file mode 100644
index e2ecaaf..0000000
--- a/tui.jai
+++ /dev/null
@@ -1,363 +0,0 @@
-
-// TODO Change this into a module with subfiles windows.jai and unix.jai
-// #if OS == .WINDOWS {
-// #load "windows.jai";
-// } else #if (OS == .LINUX) || (OS == .MACOS) {
-// #load "unix.jai";
-// } else {
-// #assert(false, "Unsupported OS.");
-// }
-
-
-// TODO On OS validations, use .LINUX or .MACOS to allow MACOS users to enj... errmmm test this.
-
-#import "Basic";
-#import "String";
-
-
- // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
- // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#designate-character-set
- // https://github.com/MicrosoftDocs/Console-Docs/blob/main/docs/console-virtual-terminal-sequences.md
-
-isTUIActive := false; // TODO Rename this variable.
-
-
-Drawings :: struct {
- CornerBR :: "\x6A";
- CornerTR :: "\x6B";
- CornerTL :: "\x6C";
- CornerBL :: "\x6D";
- Cross :: "\x6E";
- LineH :: "\x71";
- TeeL :: "\x74";
- TeeR :: "\x75";
- TeeB :: "\x76";
- TeeT :: "\x77";
- LineV :: "\x78";
-
- Blank :: "\x5F";
- Diamond :: "\x60";
- Checkerboard :: "\x61";
- PlusMinus :: "\x67";
- LessThanOrEqual :: "\x79";
- GreaterThanOrEqual :: "\x7A";
- Pi :: "\x7B";
- NotEqual :: "\x7C";
- CenteredDot :: "\x7E";
-}
-
-Commands :: struct {
- EnterAlternateBuffer :: "\e[?1049h";
- EnterMainBuffer :: "\e[?1049l";
-
- EnterDrawingMode :: "\e(0";
- EnterNormalMode :: "\e(B";
- ClearScreen :: "\e[2J";
- ClearLine :: "\e[2K";
-
- RefreshWindow :: "\e[7t"; // TODO Not yet tested.
-
- SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE
-
- // Cursor Visibility
- ShowCursor :: "\e[?25h";
- HideCursor :: "\e[?25l";
- StartBlinking :: "\e[?25h]";
- StopBlinking :: "\e[?25l]";
- SaveCursorPosition :: "\e7";
- RestoreCursorPosition :: "\e8";
-
- // Cursor Shape
- DefaultShape :: "\e[0 q";
- BlinkingBlockShape :: "\e[1 q";
- SteadyBlockShape :: "\e[2 q";
- BlinkingUnderlineShape :: "\e[3 q";
- SteadyUnderlineShape :: "\e[4 q";
- BlinkingBarShape :: "\e[5 q";
- SteadyBarShape :: "\e[6 q";
-
- // Input Mode
- KeypadAppMode :: "\e=";
- KeypadNumMode :: "\e>";
- CursorAppMode :: "\e[?1h";
- CursorNormalMode :: "\e[?1l";
-
- // Query State
- QueryCursorPosition :: "\e[6n"; // Emits the cursor position as: "ESC [ <r> ; <c> R" Where <r> = row and <c> = column.
- QueryDeviceAttributes :: "\e[0c";
- QueryWindowSizeInChars :: "\e[18t"; // Emits the window size as: "ESC [ 8 <r> ; <c> t" Where <r> = row and <c> = column.
-
-}
-
-start :: () {
- #if OS == .LINUX {
- // TODO Required to do unlocking input.
- tcgetattr(STDIN_FILENO, *__term);
- term_new := __term;
-
- term_new.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
- term_new.c_oflag &= 0xFFFFFFFE;// ~OPOST;
- term_new.c_lflag &= 0xFFFF7FB4;// ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- term_new.c_cflag &= 0xFFFFFECF;// ~(CSIZE | PARENB);
- term_new.c_cflag |= 0x00000030;
-
- tcsetattr(STDIN_FILENO, 0, *term_new);
- }
- else {
- print("TODO TUI\n", to_standard_error = true);
-
-
- // stdin
- stdin = GetStdHandle(STD_INPUT_HANDLE );
- if stdin == INVALID_HANDLE_VALUE {
- print("Invalid input handler.", to_standard_error = true);
- return;
- }
- if GetConsoleMode(stdin, *initial_stdin_mode) == false {
- print("Failed to get input mode.", to_standard_error = true);
- return;
- }
- if SetConsoleMode(stdin, initial_stdin_mode | ENABLE_VIRTUAL_TERMINAL_INPUT) == false {
- print("Failed to set input mode: %.", GetLastError(), to_standard_error = true);
- return;
- }
-
- // stdout
- stdout = GetStdHandle(STD_OUTPUT_HANDLE);
- outMode: u32 = 0;
- if stdout == INVALID_HANDLE_VALUE {
- print("Invalid output handler.", to_standard_error = true);
- return;
- }
- if GetConsoleMode(stdout, *initial_stdout_mode) == false {
- print("Failed to get output mode.", to_standard_error = true);
- return;
- }
- if SetConsoleMode(stdout, initial_stdout_mode | ENABLE_PROCESSED_OUTPUT| ENABLE_VIRTUAL_TERMINAL_PROCESSING) == false {
- print("Failed to set output mode: %.", GetLastError(), to_standard_error = true);
- return;
- }
- }
- write_strings(Commands.HideCursor, Commands.SaveCursorPosition, Commands.EnterAlternateBuffer, Commands.SetUTF8);
- isTUIActive = true;
-}
-
-stop :: () {
- isTUIActive = false;
- write_strings(Commands.EnterMainBuffer, Commands.RestoreCursorPosition, Commands.ShowCursor);
-
- #if OS == .LINUX {
- tcsetattr(STDIN_FILENO, 0, *__term); // return echo
- }
- else {
- print("TODO TUI\n", to_standard_error = true);
-
- if SetConsoleMode(stdin, initial_stdin_mode) == false {
- print("Failed to reset input mode: %.", GetLastError(), to_standard_error = true);
- return;
- }
-
- if SetConsoleMode(stdout, initial_stdout_mode) == false {
- print("Failed to reset output mode: %.", GetLastError(), to_standard_error = true);
- return;
- }
- }
-}
-
-draw_box :: (x: int, y: int, width: int, height: int, to_standard_error := false) {
-
-
- // TODO Hardcoded box starting at 1,1... fix this!
-
- write_strings(
- // Commands.EnterNormalMode,
- Commands.EnterDrawingMode,
- "\e[1;1H", // Move to position 1,1
- // TODO // Move pointer to top-left corner.
- Drawings.CornerTL,
- to_standard_error = to_standard_error);
-
- for 1..width-2 {
- write_string(Drawings.LineH, to_standard_error = to_standard_error);
- }
- write_string(Drawings.CornerTR, to_standard_error = to_standard_error);
-
-
- // TODO Take care of the temporary allocations.
- for idx: 2..height-1 {
- tmpL := tprint("\e[%;%H", idx, 1);
- tmpR := tprint("\e[%;%H", idx, width);
- write_strings(
- tmpL,
- Drawings.LineV,
- tmpR,
- Drawings.LineV,
- to_standard_error = to_standard_error);
- }
-
- tmpBL := tprint("\e[%;%H", height, 1);
- write_strings(
- tmpBL,
- Drawings.CornerBL,
- to_standard_error = to_standard_error);
- for 1..width-2 {
- write_string(Drawings.LineH, to_standard_error = to_standard_error);
- }
- write_string(Drawings.CornerBR, to_standard_error = to_standard_error);
-
- write_strings(
- // TODO // print
- Commands.EnterNormalMode,
- to_standard_error = to_standard_error);
-}
-
-clear_screen :: inline () {
- write_string(Commands.ClearScreen);
-}
-
-
-// get_cursor_position :: () -> row: int, column: int {
-// assert(isTUIActive, "TUI is not active."); // TODO
-// write_string(TUI.Commands.QueryCursorPosition); // Returned "\e[21;1R"
-// read_input()
-// }
-
-
-// read_input: () -> string;
-
-#if OS == .LINUX {
- #import "Basic";
- #import "POSIX";
-
- __term : My_Termios;
-
- My_Termios :: struct {
- c_iflag : u32; // Input mode flags.
- c_oflag : u32; // Output mode flags.
- c_cflag : u32; // Control modes flags.
- c_lflag : u32; // 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).
- }
-
- // Required to do unlocking input.
- libc :: #system_library "libc";
-
- // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcsetattr.c.html
- tcsetattr :: (fd : s32, optional_actions : s32, termios_p : *My_Termios) -> s32 #foreign libc;
-
- // https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/tcgetattr.c.html
- tcgetattr :: (fd : s32, termios_p : *My_Termios) -> s32 #foreign libc;
-
-
-
- read_input :: () -> string {
- buffer: [8192] u8;
- bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
- str := to_string(buffer.data, bytes_read);
- return str;
- };
-
- get_buffer_size :: () -> rows: int, columns: int {
- buffer: [512] u8;
- write_string(Commands.QueryWindowSizeInChars);
- bytes_read := read(STDIN_FILENO, buffer.data, buffer.count-1);
-
- str := to_string(buffer.data, bytes_read);
-
- // Result: [8;79;156t
- assert(
- buffer.data[0] == #char "\e" &&
- buffer.data[1] == #char "[" &&
- buffer.data[2] == #char "8",
- "Query windows size in chars returned invalid response.");
-
- parts := split(str, ";");
- rows := parse_int(*parts[1]);
- columns := parse_int(*parts[2]);
- return rows, columns;
- }
-
-}
-else #if OS == .WINDOWS {
- #import "Windows";
-
- ENABLE_VIRTUAL_TERMINAL_INPUT :: 0x0200;
-
- ENABLE_PROCESSED_OUTPUT :: 0x0001;
- ENABLE_WRAP_AT_EOL_OUTPUT :: 0x0002;
- ENABLE_VIRTUAL_TERMINAL_PROCESSING :: 0x0004;
- DISABLE_NEWLINE_AUTO_RETURN :: 0x0008;
- ENABLE_LVB_GRID_WORLDWIDE :: 0x0010;
-
- SHORT :: s16;
- WORD :: u16;
- DWORD :: s32;
-
- COORD :: struct {
- X : SHORT;
- Y : SHORT;
- }
-
- SMALL_RECT :: struct {
- Left : SHORT;
- Top : SHORT;
- Right : SHORT;
- Bottom : SHORT;
- }
-
- CONSOLE_SCREEN_BUFFER_INFO :: struct {
- dwSize : COORD;
- dwCursorPosition : COORD;
-
- wAttributes : WORD;
- srWindow : SMALL_RECT;
- dwMaximumWindowSize : COORD;
- }
-
- kernel32 :: #system_library "kernel32";
-
- GetConsoleScreenBufferInfo :: (hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) -> bool #foreign kernel32;
- ReadConsoleA :: (hConsoleHandle: HANDLE, buff : *u8, chars_to_read : s32, chars_read : *s32, lpInputControl := *void ) -> bool #foreign kernel32;
- // ReadConsole :: (hConsoleInput: HANDLE, lpBuffer: *u8, nNumberOfCharsToRead: s32, lpNumberOfCharsRead: *s32, pInputControl := *void) -> bool #foreign kernel32;
- GetConsoleMode :: (hConsoleHandle: HANDLE, lpMode: *u32) -> bool #foreign kernel32;
- SetConsoleMode :: (hConsoleHandle: HANDLE, dwMode: u32) -> bool #foreign kernel32;
- GetLastError :: () -> s32 #foreign kernel32;
-
- stdin: HANDLE;
- initial_stdin_mode: u32;
- stdout: HANDLE;
- initial_stdout_mode: u32;
-
- // #run read_input = () -> string {
- read_input :: () -> string {
- MAX_BYTES_TO_READ :: 1024;
- temp : [MAX_BYTES_TO_READ] u8;
- result: string = ---;
- bytes_read : s32;
-
- if !ReadConsoleA( stdin, temp.data, xx temp.count, *bytes_read )
- return "";
-
- result.data = alloc(bytes_read);
- result.count = bytes_read;
- memcpy(result.data, temp.data, bytes_read);
- return result;
- };
-
- get_buffer_size :: () -> rows: int, columns: int {
-
- // GET WINDOW CHAR SIZE
-
-
- ScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO;
- GetConsoleScreenBufferInfo(stdout, *ScreenBufferInfo);
- Size: COORD;
- Size.X = ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1;
- Size.Y = ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1;
-
- return Size.Y, Size.X;
- }
-}