diff options
| -rw-r--r-- | TUI/module.jai | 269 | ||||
| -rw-r--r-- | ttt.jai | 47 |
2 files changed, 266 insertions, 50 deletions
diff --git a/TUI/module.jai b/TUI/module.jai index 37c0f31..95ab8dc 100644 --- a/TUI/module.jai +++ b/TUI/module.jai @@ -50,18 +50,17 @@ Commands :: struct { TextMode :: "\e(B"; ClearScreen :: "\e[2J"; ClearLine :: "\e[2K"; + ClearScrollBack :: "\e[3J"; Bell :: "\x07"; - SetWindowTitle :: "\e]0;%\x07"; + SetWindowTitle :: "\e]0;%\e\\"; RefreshWindow :: "\e[7t"; // TODO Not yet tested. SetUTF8 :: "\e%G"; // TODO TEST ME PLEASE - // WIP WIP WIP - // Add commands to change StyleNormal/Italic/Bold/Color/WhatNot! - + SetGraphicsRendition :: "\e[%m"; // Cursor Position SetCursorPosition :: "\e[%;%H"; @@ -93,18 +92,44 @@ Commands :: struct { 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. TODO Does not work on windows. - } -GraphicsStyle :: struct { - BackgroundColor : u8; - ForegroundColor : u8; - Bold : bool; - Italic : bool; - Underline : bool; - Blinking : bool; - Inverse : bool; - StrikeThrough : bool; +clear_style :: () { + write_string(#run sprint(Commands.SetGraphicsRendition, "0")); +} + +Colors8b :: struct { + Black :: 0; + Maroon :: 1; + Green :: 2; + Olive :: 3; + Navy :: 4; + Purple :: 5; + Teal :: 6; + Silver :: 7; + Gray :: 8; + Red :: 9; + Lime :: 10; + Yellow :: 11; + Blue :: 12; + Magenta :: 13; + Cyan :: 14; + White :: 15; +} + +// TODO Maybe rename. +set_style_colors :: (foreground: u8, background: u8) { + print( + #run sprint(Commands.SetGraphicsRendition, "38;5;%;48;5;%"), + foreground, background); +} + +// set_colors_24b :: (foreground_r: u255) // TODO https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + +set_style :: (bold: bool, underline: bool = false, strike_through: bool = false, negative: bool = false) { + print( + #run sprint(Commands.SetGraphicsRendition, "%;%;%;%"), + ifx bold then 1 else 22, ifx underline then 4 else 24, ifx strike_through then 9 else 29, ifx negative then 7 else 27); } // TODO Maybe make the OS_* procedures as inline?! @@ -124,18 +149,187 @@ Key :: u64; KEY_SIZE :: #run type_info(Key).runtime_size; -Keys :: struct { +Keys :: struct #type_info_none { // Terminal key-codes have 1 to 6 bytes, so we can signal special cases setting the edge-bytes. - None : Key : 0xF0000000_0000000F; - Resize : Key : 0xF0000000_0000001F; + None : Key : 0xF0000000_0000000F; + Resize : Key : 0xF0000000_0000001F; - Up : Key : #run to_key("\e[A"); - Down : Key : #run to_key("\e[B"); - Right : Key : #run to_key("\e[C"); - Left : Key : #run to_key("\e[D"); - - PgUp : Key : #run to_key("\e[5~"); - PgDown : Key : #run to_key("\e[6~"); + Space : Key : #char " "; + Enter : Key : #char "\r"; + Tab : Key : #char "\t"; + + Up : Key : #run to_key("\e[A"); + Down : Key : #run to_key("\e[B"); + Right : Key : #run to_key("\e[C"); + Left : Key : #run to_key("\e[D"); + + MetaUp : Key : #run to_key("\e[1;1A"); + MetaDown : Key : #run to_key("\e[1;1B"); + MetaRight : Key : #run to_key("\e[1;1C"); + MetaLeft : Key : #run to_key("\e[1;1D"); + + ShiftUp : Key : #run to_key("\e[1;2A"); + ShiftDown : Key : #run to_key("\e[1;2B"); + ShiftRight : Key : #run to_key("\e[1;2C"); + ShiftLeft : Key : #run to_key("\e[1;2D"); + + AltUp : Key : #run to_key("\e[1;3A"); + AltDown : Key : #run to_key("\e[1;3B"); + AltRight : Key : #run to_key("\e[1;3C"); + AltLeft : Key : #run to_key("\e[1;3D"); + + AltShiftUp : Key : #run to_key("\e[1;4A"); + AltShiftDown : Key : #run to_key("\e[1;4B"); + AltShiftRight : Key : #run to_key("\e[1;4C"); + AltShiftLeft : Key : #run to_key("\e[1;4D"); + + CtrlUp : Key : #run to_key("\e[1;5A"); + CtrlDown : Key : #run to_key("\e[1;5B"); + CtrlRight : Key : #run to_key("\e[1;5C"); + CtrlLeft : Key : #run to_key("\e[1;5D"); + + CtrlShiftUp : Key : #run to_key("\e[1;6A"); + CtrlShiftDown : Key : #run to_key("\e[1;6B"); + CtrlShiftRight : Key : #run to_key("\e[1;6C"); + CtrlShiftLeft : Key : #run to_key("\e[1;6D"); + + CtrlAltUp : Key : #run to_key("\e[1;7A"); + CtrlAltDown : Key : #run to_key("\e[1;7B"); + CtrlAltRight : Key : #run to_key("\e[1;7C"); + CtrlAltLeft : Key : #run to_key("\e[1;7D"); + + CtrlAltShiftUp : Key : #run to_key("\e[1;7A"); + CtrlAltShiftDown : Key : #run to_key("\e[1;7B"); + CtrlAltShiftRight : Key : #run to_key("\e[1;7C"); + CtrlAltShiftLeft : Key : #run to_key("\e[1;7D"); + + Home : Key : #run to_key("\e[H"); + End : Key : #run to_key("\e[F"); + + Escape : Key : 0x00000000_0000001B; + Backspace : Key : 0x00000000_0000007F; + Pause : Key : 0x00000000_0000001A; + Insert : Key : #run to_key("\e[2~"); + Delete : Key : #run to_key("\e[3~"); + PgUp : Key : #run to_key("\e[5~"); + PgDown : Key : #run to_key("\e[6~"); + + F1 : Key : #run to_key("\eOP"); + F2 : Key : #run to_key("\eOQ"); + F3 : Key : #run to_key("\eOR"); + F4 : Key : #run to_key("\eOS"); + F5 : Key : #run to_key("\e[15~"); + F6 : Key : #run to_key("\e[17~"); + F7 : Key : #run to_key("\e[18~"); + F8 : Key : #run to_key("\e[19~"); + F9 : Key : #run to_key("\e[20~"); + F10 : Key : #run to_key("\e[21~"); + F11 : Key : #run to_key("\e[23~"); + F12 : Key : #run to_key("\e[24~"); + + MetaF1 : Key : #run to_key("\eO1P"); + MetaF2 : Key : #run to_key("\eO1Q"); + MetaF3 : Key : #run to_key("\eO1R"); + MetaF4 : Key : #run to_key("\eO1S"); + MetaF5 : Key : #run to_key("\e[15;1~"); + MetaF6 : Key : #run to_key("\e[17;1~"); + MetaF7 : Key : #run to_key("\e[18;1~"); + MetaF8 : Key : #run to_key("\e[19;1~"); + MetaF9 : Key : #run to_key("\e[20;1~"); + MetaF10 : Key : #run to_key("\e[21;1~"); + MetaF11 : Key : #run to_key("\e[23;1~"); + MetaF12 : Key : #run to_key("\e[24;1~"); + + ShiftF1 : Key : #run to_key("\eO2P"); + ShiftF2 : Key : #run to_key("\eO2Q"); + ShiftF3 : Key : #run to_key("\eO2R"); + ShiftF4 : Key : #run to_key("\eO2S"); + ShiftF5 : Key : #run to_key("\e[15;2~"); + ShiftF6 : Key : #run to_key("\e[17;2~"); + ShiftF7 : Key : #run to_key("\e[18;2~"); + ShiftF8 : Key : #run to_key("\e[19;2~"); + ShiftF9 : Key : #run to_key("\e[20;2~"); + ShiftF10 : Key : #run to_key("\e[21;2~"); + ShiftF11 : Key : #run to_key("\e[23;2~"); + ShiftF12 : Key : #run to_key("\e[24;2~"); + + AltF1 : Key : #run to_key("\eO3P"); + AltF2 : Key : #run to_key("\eO3Q"); + AltF3 : Key : #run to_key("\eO3R"); + AltF4 : Key : #run to_key("\eO3S"); + AltF5 : Key : #run to_key("\e[15;3~"); + AltF6 : Key : #run to_key("\e[17;3~"); + AltF7 : Key : #run to_key("\e[18;3~"); + AltF8 : Key : #run to_key("\e[19;3~"); + AltF9 : Key : #run to_key("\e[20;3~"); + AltF10 : Key : #run to_key("\e[21;3~"); + AltF11 : Key : #run to_key("\e[23;3~"); + AltF12 : Key : #run to_key("\e[24;3~"); + + AltShiftF1 : Key : #run to_key("\eO4P"); + AltShiftF2 : Key : #run to_key("\eO4Q"); + AltShiftF3 : Key : #run to_key("\eO4R"); + AltShiftF4 : Key : #run to_key("\eO4S"); + AltShiftF5 : Key : #run to_key("\e[15;4~"); + AltShiftF6 : Key : #run to_key("\e[17;4~"); + AltShiftF7 : Key : #run to_key("\e[18;4~"); + AltShiftF8 : Key : #run to_key("\e[19;4~"); + AltShiftF9 : Key : #run to_key("\e[20;4~"); + AltShiftF10 : Key : #run to_key("\e[21;4~"); + AltShiftF11 : Key : #run to_key("\e[23;4~"); + AltShiftF12 : Key : #run to_key("\e[24;4~"); + + CtrlF1 : Key : #run to_key("\eO5P"); + CtrlF2 : Key : #run to_key("\eO5Q"); + CtrlF3 : Key : #run to_key("\eO5R"); + CtrlF4 : Key : #run to_key("\eO5S"); + CtrlF5 : Key : #run to_key("\e[15;5~"); + CtrlF6 : Key : #run to_key("\e[17;5~"); + CtrlF7 : Key : #run to_key("\e[18;5~"); + CtrlF8 : Key : #run to_key("\e[19;5~"); + CtrlF9 : Key : #run to_key("\e[20;5~"); + CtrlF10 : Key : #run to_key("\e[21;5~"); + CtrlF11 : Key : #run to_key("\e[23;5~"); + CtrlF12 : Key : #run to_key("\e[24;5~"); + + CtrlShiftF1 : Key : #run to_key("\eO6P"); + CtrlShiftF2 : Key : #run to_key("\eO6Q"); + CtrlShiftF3 : Key : #run to_key("\eO6R"); + CtrlShiftF4 : Key : #run to_key("\eO6S"); + CtrlShiftF5 : Key : #run to_key("\e[15;6~"); + CtrlShiftF6 : Key : #run to_key("\e[17;6~"); + CtrlShiftF7 : Key : #run to_key("\e[18;6~"); + CtrlShiftF8 : Key : #run to_key("\e[19;6~"); + CtrlShiftF9 : Key : #run to_key("\e[20;6~"); + CtrlShiftF10 : Key : #run to_key("\e[21;6~"); + CtrlShiftF11 : Key : #run to_key("\e[23;6~"); + CtrlShiftF12 : Key : #run to_key("\e[24;6~"); + + CtrlAltF1 : Key : #run to_key("\eO7P"); + CtrlAltF2 : Key : #run to_key("\eO7Q"); + CtrlAltF3 : Key : #run to_key("\eO7R"); + CtrlAltF4 : Key : #run to_key("\eO7S"); + CtrlAltF5 : Key : #run to_key("\e[15;7~"); + CtrlAltF6 : Key : #run to_key("\e[17;7~"); + CtrlAltF7 : Key : #run to_key("\e[18;7~"); + CtrlAltF8 : Key : #run to_key("\e[19;7~"); + CtrlAltF9 : Key : #run to_key("\e[20;7~"); + CtrlAltF10 : Key : #run to_key("\e[21;7~"); + CtrlAltF11 : Key : #run to_key("\e[23;7~"); + CtrlAltF12 : Key : #run to_key("\e[24;7~"); + + CtrlAltShiftF1 : Key : #run to_key("\eO8P"); + CtrlAltShiftF2 : Key : #run to_key("\eO8Q"); + CtrlAltShiftF3 : Key : #run to_key("\eO8R"); + CtrlAltShiftF4 : Key : #run to_key("\eO8S"); + CtrlAltShiftF5 : Key : #run to_key("\e[15;8~"); + CtrlAltShiftF6 : Key : #run to_key("\e[17;8~"); + CtrlAltShiftF7 : Key : #run to_key("\e[18;8~"); + CtrlAltShiftF8 : Key : #run to_key("\e[19;8~"); + CtrlAltShiftF9 : Key : #run to_key("\e[20;8~"); + CtrlAltShiftF10 : Key : #run to_key("\e[21;8~"); + CtrlAltShiftF11 : Key : #run to_key("\e[23;8~"); + CtrlAltShiftF12 : Key : #run to_key("\e[24;8~"); } to_key :: inline (str: $T) -> Key #modify { return T == ([]u8) || T == string; } { @@ -160,6 +354,7 @@ to_string :: inline (key: Key) -> string { return str; } +// TODO FIXME DEBUG HACK test_union :: () { // ti := type_info(K); @@ -209,8 +404,9 @@ input_string : string; input_override : Key; #run { + // TODO FIXME DEBUG HACK or maybe... let it be?! // Some tests. - assert(input_buffer.count >= 6, "The input buffer size must be capable to hold an entire terminal (6 bytes) or UTF8 (4 bytes) code."); + assert(input_buffer.count >= KEY_SIZE, "The input buffer size must be capable to hold an entire terminal (6 bytes) or UTF8 (4 bytes) code."); } assert_is_initialized :: inline () { @@ -314,7 +510,8 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { // Must be a terminal escape sequence. if utf8_bytes == 1 && input_string[0] == #char "\e" { - to_parse.count = ifx input_string.count > 6 then 6 else input_string.count; // TODO We should look into the input_string and search for the following escape sequence or somehting!? + assert(input_string.count <= KEY_SIZE, "Received oversized terminal sequence."); // TODO + to_parse.count = ifx input_string.count > KEY_SIZE then KEY_SIZE else input_string.count; // TODO We should look into the input_string and search for the following escape sequence or somehting!? } key := to_key(to_parse); @@ -345,13 +542,11 @@ get_key :: (timeout_milliseconds: s32 = -1) -> Key { return xx Keys.None; } -get_str :: (count_limit: int = -1, allocator: Allocator = temp) -> string { +get_str :: (count_limit: int = -1) -> string { assert_is_initialized(); - assert(allocator.proc != null, "Argument 'allocator.proc' has invalid null value."); if count_limit < 0 { - builder: String_Builder(); - builder.allocator = allocator; + builder: String_Builder; init_string_builder(*builder); while(1) { @@ -361,10 +556,10 @@ get_str :: (count_limit: int = -1, allocator: Allocator = temp) -> string { if buffer.count < buffer.allocated break; expand(*builder); } - return builder_to_string(*builder, allocator); + return builder_to_string(*builder); } else { - buffer := alloc_string(count_limit, allocator); + buffer := alloc_string(count_limit); buffer.count = OS_read_input(buffer.data, count_limit); return buffer; } @@ -395,7 +590,7 @@ flush_input :: () { OS_flush_input(); } -// WIP WIP WIP +// TODO move style related procedures here! // set_style :: () { // print("", Commands.) -- // } @@ -463,7 +658,7 @@ get_terminal_size :: () -> rows: int, columns: int { flush_input(); write_string(Commands.QueryWindowSizeInChars); - input := get_str(64); + input := get_str(64,, temporary_allocator); // Expected response format: \e[8;<r>;<c>t // where <r> is the number of rows and <c> of columns. @@ -483,7 +678,7 @@ get_terminal_size :: () -> rows: int, columns: int { input[0] == FORMAT[0] && input[1] == FORMAT[1] && input[2] == FORMAT[2] && input[input.count-1] == FORMAT[FORMAT.count-1], "Query window size in chars returned invalid response."); - parts := split(input, ";"); + parts := split(input, ";",, temporary_allocator); rows = parse_int(*parts[1]); columns = parse_int(*parts[2]); } @@ -504,7 +699,7 @@ get_cursor_position :: () -> row: int, column: int { flush_input(); write_string(Commands.QueryCursorPosition); - input := get_str(64); + input := get_str(64,, temporary_allocator); // Expected response format: \e[<r>;<c>R // where <r> is the number of rows and <c> of columns. @@ -526,7 +721,7 @@ get_cursor_position :: () -> row: int, column: int { advance(*input, 2); - parts := split(input, ";"); + parts := split(input, ";",, temporary_allocator); row := parse_int(*parts[0]); column := parse_int(*parts[1]); return row, column; @@ -392,7 +392,7 @@ delete_task :: (using db: *Database, index: s64) -> bool { // TODO Maybe use `us size_of_task := size_of(Task); if (tasks.allocated >> 2) > tasks.count && tasks.allocated * size_of_task > 2_000_000 { new_capacity := tasks.allocated >> 1; - new_tasks_data := realloc(tasks.data, new_capacity * size_of_task, tasks.allocated * size_of_task, tasks.allocator); + new_tasks_data := realloc(tasks.data, new_capacity * size_of_task, tasks.allocated * size_of_task,, tasks.allocator); if new_tasks_data != null { tasks.data = new_tasks_data; tasks.allocated = new_capacity; @@ -713,7 +713,7 @@ import_from_csv :: (db: *Database, path: string) -> bool { // Thus this works on both 'dos' and 'unix'-style files. s := << sp; - found, result, right := split_from_left(s, 10); + found, result, right := split_from_left(s, 10,, temporary_allocator); if !found { // This is the last line; there may not have been a linefeed after that, @@ -761,7 +761,7 @@ import_from_csv :: (db: *Database, path: string) -> bool { if success == false break; task: Task; - csv_values := split(line, ","); // TODO Temporary memory... if file is too big this may break. + csv_values := split(line, ",",, temporary_allocator); // TODO Temporary memory... if file is too big this may break. // Import task name. name_length := min(task.name.count, csv_values[0].count); @@ -1069,11 +1069,16 @@ draw_tui :: (db: *Database, layout: *Layout) { // Apply theme. if (task == active_task && task == selected_task) { // attron(COLOR_PAIR(xx Styles.ACTIVE_SELECTED) | A_BOLD); TODO DAM + TUI.set_style_colors(TUI.Colors8b.Red, 6); // TODO TESTING COLORS + TUI.set_style(true, true, true, false); } else if (task == selected_task) { // attron(COLOR_PAIR(xx Styles.SELECTED)); TODO DAM + TUI.set_style_colors(4, 6); // TODO TESTING COLORS } else if (task == active_task) { + TUI.set_style_colors(TUI.Colors8b.Red, 6); // TODO TESTING COLORS + TUI.set_style(false, false, false, true); // TODO TESTING STYLE // attron(COLOR_PAIR(xx Styles.ACTIVE) | A_BOLD); TODO DAM } @@ -1081,16 +1086,18 @@ draw_tui :: (db: *Database, layout: *Layout) { x += 1; column_width = layout.columns[L_TITLE_IDX].width; // mvprintw(xx y, xx x, "%-*.*s", column_width, column_width, temp_c_string(xx task.name)); //task.name); TODO Fix required for LLVM/Cncurses. TODO DAM - TUI.set_cursor_position(y, x); // TODO FIXME OH MY GOD SUCH BAD CODEZ + TUI.set_cursor_position(y, x); + white_spaces := column_width; + // FIXME Improve by using buffer instead of printing one char at the time. + while white_spaces > 0 { + print_character(#char " "); + white_spaces -= 1; + } + TUI.set_cursor_position(y, x); task_name: string = cast(string)task.name; task_name.count = ifx task_name.count > column_width then column_width else task_name.count; print("%", task_name); - diff := column_width - task_name.count; - while diff > 0 { - diff -= 1; - print_character(#char " "); - } x += column_width; // Task times. @@ -1111,6 +1118,7 @@ draw_tui :: (db: *Database, layout: *Layout) { // Reset theme. //attrset(A_NORMAL); TODO DAM + TUI.clear_style(); } @@ -1302,7 +1310,7 @@ main :: () { last_none_char := "X"; drop_down := 0; while(key != #char "q") { - // __mark := get_temporary_storage_mark(); + __mark := get_temporary_storage_mark(); if key == { case TUI.Keys.None; { @@ -1316,16 +1324,27 @@ main :: () { TUI.clear_terminal(); drop_down = 0; } + + case TUI.Keys.MetaF7; { + TUI.set_cursor_position(3+drop_down, 2); + drop_down += 1; + write_string("META F7"); + } case; { TUI.set_cursor_position(3+drop_down, 2); str := TUI.to_string(key); for 0..str.count-1 { + print("'%'", FormatInt.{value = cast(u8)str[it], base=16}); + } + write_string(":> "); + for 0..str.count-1 { if str[it] == #char "\e" { str[it] = #char "?"; } } write_string(str); + write_string(" <EOL"); drop_down += 1; } } @@ -1337,6 +1356,8 @@ main :: () { print("size(CxR): %x%\n", size_c, size_r); key = TUI.get_key(3000); + + set_temporary_storage_mark(__mark); } TUI.stop(); print("size(CxR): %x%\n", xcolumns, xrows); @@ -1757,14 +1778,14 @@ main :: () { if (active_task == null) continue; select_task(db, db.active_idx); - case #char "\n"; #through; - case #char " "; + case TUI.Keys.Enter; #through; + case TUI.Keys.Space; if (db != *database || selected_task == null) continue; set_active_task(db, ifx db.active_idx == db.selected_idx then -1 else db.selected_idx); active_task = get_active_task(db); trigger_autosave(); - case #char "\t"; + case TUI.Keys.Tab; if (db == *database) { if (import_from_csv(*archive, ar_file_path) == false) { reset_database(*archive); |
