From 76f3be800b9306a0a63c9f888b5e61c27ea35c0e Mon Sep 17 00:00:00 2001 From: dam Date: Tue, 29 Aug 2023 09:21:24 +0100 Subject: Attempting to replace ncurses. --- tio.jai | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- ttt.jai | 40 ++++++++++-------- 2 files changed, 148 insertions(+), 34 deletions(-) diff --git a/tio.jai b/tio.jai index 37c7e4a..f6ee0cb 100644 --- a/tio.jai +++ b/tio.jai @@ -1,4 +1,10 @@ +#module_parameters(ENABLE_SIGINT := true, ENABLE_SIGQUIT := true); + +#import "Basic"; + +// TODO Eventually, I'll need to add #scope_module ... + terminal_state : struct { // size : ivec2; width: s32; @@ -15,18 +21,22 @@ terminal_state : struct { __term : My_Termios; My_Termios :: struct { - c_iflag : u32; - c_oflag : u32; - c_cflag : u32; - c_lflag : u32; - unknown_pad : u8; - c_cc : [32]u8; - c_ispeed : u32; - c_ospeed : u32; + c_iflag : u32; // Input mode flags. + c_oflag : u32; // Output mode flags. + c_cflag : u32; // Control mode flags. + c_lflag : u32; // Local mode flags. + c_line : u8; // Line discipline. + c_cc : [32]u8; // Control characters. + c_ispeed : u32; // Input speed. + c_ospeed : u32; // Output speed. } 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; } else { @@ -57,6 +67,52 @@ Graphics_Mode :: struct { bcol256 : u8; } +Key :: enum u64 { + READ_ERROR :: 0xffffffff_ffffffff; + + UP :: 0x41_5b1b; + DOWN :: 0x42_5b1b; + RIGHT :: 0x43_5b1b; + LEFT :: 0x44_5b1b; + + CTRL_UP :: 0x4135_3b315b1b; + CTRL_DOWN :: 0x4235_3b315b1b; + CTRL_RIGHT :: 0x4335_3b315b1b; + CTRL_LEFT :: 0x4435_3b315b1b; + + SHIFT_UP :: 0x4132_3b315b1b; + SHIFT_DOWN :: 0x4232_3b315b1b; + SHIFT_RIGHT :: 0x4332_3b315b1b; + SHIFT_LEFT :: 0x4432_3b315b1b; + + CTRL_SHIFT_UP :: 0x4136_3b315b1b; + CTRL_SHIFT_DOWN :: 0x4236_3b315b1b; + CTRL_SHIFT_RIGHT:: 0x4336_3b315b1b; + CTRL_SHIFT_LEFT :: 0x4436_3b315b1b; + + ALT_UP :: 0x4133_3b315b1b; + ALT_DOWN :: 0x4233_3b315b1b; + ALT_RIGHT :: 0x4333_3b315b1b; + ALT_LEFT :: 0x4433_3b315b1b; + + CTRL_C :: 0x03; + CTRL_V :: 0x16; + CTRL_X :: 0x18; + CTRL_Y :: 0x19; + CTRL_Z :: 0x1A; + CTRL_BACKSLASH :: 0x1C; + + // ALT_SHIFT_UP :: 0x4133_3b315b1b; + // ALT_SHIFT_DOWN :: 0x4233_3b315b1b; + // ALT_SHIFT_RIGHT :: 0x4333_3b315b1b; + // ALT_SHIFT_LEFT :: 0x4433_3b315b1b; + + ENTER :: 0x0D; + ESCAPE :: 0x1B; + BACKSPACE :: 0x7F; + DELETE :: 0x7E335B1B; +} + Color :: enum u8 { RESET :: 0; DEFAULT :: 39; @@ -81,11 +137,40 @@ Color :: enum u8 { BRIGHT_WHITE :: 97; } -__old_logger : type_of(context.logger); +update_terminal_size :: () { + TIOCGWINSZ :: 0x5413; + winsize : struct { + ws_row, ws_col, ws_xpixel, ws_ypixel : u16; + } + ioctl(0, TIOCGWINSZ, *winsize); + terminal_state.width = xx winsize.ws_col; + terminal_state.height = xx winsize.ws_row; +} initialize :: () { #if OS == .LINUX { - tcgetattr(STDIN_FILENO, *__term); + + tui_write("\e[?25l"); // hide cursor + tui_write("\e7"); // save cursor position + tui_write("\e[?1047h"); // switch screen + tui_write("\e[?30l"); // hide scrollbar + + tui_write("\e[H"); // move to top left corner + tui_write("\e[0m"); // set default mode + tui_write("\e[2J"); // clear screen + { + 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); + } + update_terminal_size(); } else { assert(false, "procedure call on unsupported OS\n"); } @@ -95,22 +180,47 @@ terminate :: () { #if OS == .LINUX { tcsetattr(STDIN_FILENO, 0, *__term); // return echo - tio_write("\e[?47l"); // restore screen - tio_write("\e8"); // restore cursor - tio_write("\e[?25h"); // show cursor - tio_write("\e[?30h"); // show scrollbar + tui_write("\e[?47l"); // restore screen + tui_write("\e8"); // restore cursor + tui_write("\e[?25h"); // show cursor + tui_write("\e[?30h"); // show scrollbar terminal_state = .{}; - context.logger = __old_logger; } else { assert(false, "procedure call on unsupported OS\n"); } } -tio_write :: (str : string) { +tui_write :: (str : string) { #if OS == .LINUX { write(STDIN_FILENO, str.data, xx str.count); } else { assert(false, "procedure call on unsupported OS\n"); } } + +buffer: [..] Key; + +tui_ungetch :: (key: Key) { + array_add(*buffer, key); +} + +tui_getch :: (block := true) -> Key { + #if OS == .LINUX { + buf : Key = xx 0; + if buffer.count > 0 return pop(*buffer); + l := read(STDIN_FILENO, (cast(*u8)*buf), 8); //!!! + check_signal :: inline (key : Key) { + #if ENABLE_SIGINT if key == .CTRL_C raise(SIGINT); //!!! + #if ENABLE_SIGQUIT if key == .CTRL_BACKSLASH raise(SIGQUIT); + } + check_signal(buf); + return ifx l <= 0 then Key.READ_ERROR else buf; + } else { + return .READ_ERROR; + } +} + +tui_clear_screen :: inline () { + tui_write("\e[2J"); +} diff --git a/ttt.jai b/ttt.jai index b3a1cd3..7431ac6 100644 --- a/ttt.jai +++ b/ttt.jai @@ -25,9 +25,9 @@ #import "File"; #import "File_Utilities"; #import "String"; -//#import "curses"; +// #import "curses"; // #import "kscurses"; -TIO :: #import "tio"; +TUI :: #import "tio"; // TODO Rename module to "tui.jai" #load "Integer_Saturating_Arithmetic.jai"; @@ -36,7 +36,6 @@ TIO :: #import "tio"; stdscr: *void; // TODO DAM A_BOLD: s32 = 0; // TODO DAM COLOR_PAIR :: (a: s32) -> s32 { return 0; } // TODO DAM -ERR :: -1; // TODO DAM KEY_RESIZE :: 410; // TODO DAM KEY_F2 :: 266; // TODO DAM KEY_F5 :: 269; // TODO DAM @@ -902,13 +901,12 @@ initialize_tui :: () { } // TODO DAM - TIO.initialize(); - TIO.terminate(); // TODO DAM - //stdscr = initscr(); // Start curses mode. TODO DAM - //cbreak(); // Line buffering disabled; pass on everty thing to me. TODO DAM - //keypad(stdscr, true); // I need those nifty F1..F12. TODO DAM - //curs_set(0); // Set cursor invisible. TODO DAM - //noecho(); // Disable echoing input characters. TODO DAM + TUI.initialize(); + // stdscr = initscr(); // Start curses mode. TODO DAM + // cbreak(); // Line buffering disabled; pass on everty thing to me. TODO DAM + // keypad(stdscr, true); // I need those nifty F1..F12. TODO DAM + // curs_set(0); // Set cursor invisible. TODO DAM + // noecho(); // Disable echoing input characters. TODO DAM // Initialize pairs of colors. //start_color(); TODO DAM @@ -957,10 +955,11 @@ draw_tui :: (db: *Database, layout: *Layout) { // Reset theme and clear screen. //attrset(A_NORMAL); TODO DAM - //erase(); TODO DAM + TUI.tui_clear_screen(); // Draw outer border. //box(stdscr, 0, 0); TODO DAM + // WIP // Draw table grids. // TODO Maybe this could be simplified? @@ -1362,7 +1361,7 @@ main :: () { layout := *layouts[Layouts.COMPACT]; //flushinp(); TODO DAM - //ungetch(KEY_RESIZE); TODO DAM + TUI.tui_ungetch(KEY_RESIZE); // TODO DAM while (true) { if (is_terminal_too_small) { @@ -1376,7 +1375,7 @@ main :: () { reset_temporary_storage(); //timeout(INPUT_TIMEOUT_MS); TODO DAM - key := 0; // getch(); TODO DAM + key := TUI.tui_getch(); // getch(); TODO DAM if key == #char "q" || key == #char "Q" break; update_times(*database); //timeout(INPUT_AWAIT_INF); TODO DAM @@ -1400,7 +1399,7 @@ main :: () { if key == { // When getch() times out. - case ERR; + case .READ_ERROR; if (is_autosave_enabled && countdown_to_autosave > 0) { countdown_to_autosave -= INPUT_TIMEOUT_MS; if (countdown_to_autosave <= 0) { @@ -1414,8 +1413,13 @@ main :: () { // When terminal is resized. case KEY_RESIZE; - //clear(); TODO DAM - //getmaxyx(stdscr, *size_y, *size_x); TODO DAM + TUI.tui_clear_screen(); + //getmaxyx(stdscr, *size_y, *size_x); + TUI.update_terminal_size(); // TODO DAM + size_x = TUI.terminal_state.width; + size_y = TUI.terminal_state.height; + print("resize:%x%", size_x, size_y); + asd := TUI.tui_getch(); is_terminal_too_small = size_x < 60 || size_y < 3; update_layout(); layout = *layouts[ifx size_x > 100 then Layouts.NORMAL else Layouts.COMPACT]; @@ -1495,7 +1499,7 @@ main :: () { if (selected_task == null) continue; // Prepare position to input time operation. - selected_day := key - #char "1"; + selected_day := cast(int)(key - #char "1"); // TODO DAM this cast... input_width := layout.columns[L_DAYS_IDX + selected_day].width; input_pos_x := 1 + layout.columns[L_TITLE_IDX].width; @@ -1766,7 +1770,7 @@ main :: () { //getch(); TODO DAM } - //endwin(); TODO DAM + TUI.terminate(); // TODO DAM exit(xx ifx error_saving then 1 else 0); } -- cgit v1.2.3