diff options
| author | dam <dam@gudinoff> | 2023-09-20 18:00:20 +0100 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-09-20 18:00:20 +0100 |
| commit | 65adffcf572c98c0198affcdf729d989fec253ae (patch) | |
| tree | 31f2c0fe7ca0cec7e7b932bb6c2f8126a7577bac | |
| parent | 9e2fc467ad0e779734d836656875cf92bcb5732a (diff) | |
| download | task-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.jai | 194 | ||||
| -rw-r--r-- | TUI/unix.jai | 63 | ||||
| -rw-r--r-- | TUI/windows.jai | 111 | ||||
| -rw-r--r-- | ttt.jai | 4 | ||||
| -rw-r--r-- | tui.jai | 363 |
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; +} @@ -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; - } -} |
