1 module tagion.utils.Term; 2 3 import std.format; 4 5 import std.meta : AliasSeq, staticSort; 6 7 //import std.algorithm : sort; 8 9 enum { 10 BLACK = Color.Black.code, 11 RED = Color.Red.code, 12 GREEN = Color.Green.code, 13 YELLOW = Color.Yellow.code, 14 BLUE = Color.Blue.code, 15 MAGENTA = Color.Magenta.code, 16 CYAN = Color.Cyan.code, 17 WHITE = Color.White.code, 18 19 BOLD = Mode.Bold.code, 20 21 BACKGOUND_BLACK = Color.Black.code(true), 22 BACKGOUND_RED = Color.Red.code(true), 23 BACKGOUND_GREEN = Color.Green.code(true), 24 BACKGOUND_YELLOW = Color.Yellow.code(true), 25 BACKGOUND_BLUE = Color.Blue.code(true), 26 BACKGOUND_MAGENTA = Color.Magenta.code(true), 27 BACKGOUND_CYAN = Color.Cyan.code(true), 28 BACKGOUND_WHITE = Color.White.code(true), 29 BACKGOUND_RESET = Color.Reset.code(true), 30 31 RESET = Color.Reset.code, 32 CLEARSCREEN = Cursor.ClearScreen.code(2), 33 CLEARDOWN = Cursor.ClearScreen.code(0), 34 CLEARUP = Cursor.ClearScreen.code(1), 35 CLEARLINE = Cursor.ClearLine.code(2), 36 CLEAREOL = Cursor.ClearLine.code(0), 37 38 CR = "\x13", 39 NEXTLINE = Cursor.NextLine.code(0), 40 HOME = "\u001b[f", 41 } 42 43 enum Color { 44 Black, 45 Red, 46 Green, 47 Yellow, 48 Blue, 49 Magenta, 50 Cyan, 51 White, 52 Reset, 53 } 54 55 string code( 56 immutable Color c, 57 immutable bool background = false, 58 immutable bool bright = false) { 59 if (c is Color.Reset) { 60 return "\u001b[0m"; 61 } 62 else { 63 immutable background_color = (background) ? "4" : "3"; 64 immutable bright_color = (bright) ? "m" : ";1m"; 65 return format("\u001b[%s%d%s", background_color, c, bright_color); 66 } 67 assert(0); 68 } 69 70 enum Cursor : char { 71 Up = 'A', /// Moves cursor up by n 72 Down = 'B', /// Moves cursor down by n 73 Right = 'C', /// Moves cursor right by n 74 Left = 'D', /// Moves cursor left by n 75 NextLine = 'E', /// Moves cursor to beginning of line n lines down 76 PrevLine = 'F', /// Moves cursor to beginning of line n lines down 77 SetColumn = 'G', /// Moves cursor to column n 78 ClearScreen = 'J', /// clears the screen 79 ClearLine = 'K' /// clears the current line 80 } 81 82 string code(immutable Cursor c, immutable uint n = 1) { 83 return format("\u001b[%d%s", n, char(c)); 84 } 85 86 string linePos(const size_t pos) { 87 return format("\r\x1B[%dC", pos); 88 } 89 90 enum Mode { 91 None = 0, /// All attributes off 92 Bold = 1, /// Bold on 93 Underscore = 4, /// Underscore (on monochrome display adapter only) 94 Blink = 5, /// Blink on 95 Reverse = 7, /// Reverse video on 96 Concealed = 8, /// Concealed on 97 } 98 99 string code(immutable Mode m) { 100 return format("\u001b[%dm", m); 101 } 102 103 string setCursor(immutable uint row, immutable uint column) { 104 return format("\u001b[%d;%dH", row, column); 105 } 106 107 enum saveCursorPos = "\u001b[s"; /// Saves the current cursor position 108 enum restoreCursorPos = "\u001b[u"; /// Restores the cursor to the last saved position 109 110 version (MOBILE) { 111 } 112 else { 113 private import core.stdc.stdio; 114 private import core.sys.posix.termios; 115 116 extern (C) void cfmakeraw(termios* termios_p); 117 118 struct KeyStroke { 119 120 termios ostate; /* saved tty state */ 121 termios nstate; /* values for editor mode */ 122 123 int get() 124 out (ret) { 125 import std.stdio; 126 127 writef("%d ", ret); 128 129 } 130 do { 131 // Open stdin in raw mode 132 // Adjust output channel 133 tcgetattr(1, &ostate); // save old state 134 tcgetattr(1, &nstate); // get base of new state 135 cfmakeraw(&nstate); 136 tcsetattr(1, TCSADRAIN, &nstate); // set mode 137 scope (exit) { 138 tcsetattr(1, TCSADRAIN, &ostate); // return to original mode 139 } 140 return fgetc(stdin); 141 } 142 143 enum KeyCode { 144 NONE, 145 UP, 146 DOWN, 147 LEFT, 148 RIGHT, 149 HOME, 150 END, 151 PAGEUP, 152 PAGEDOWN, 153 ENTER, 154 DELETE, 155 BACKSPACE, 156 F1, 157 F2, 158 F3, 159 F4, 160 F5, 161 F6, 162 F7, 163 F8, 164 F9, 165 F10, 166 F11, 167 F12, 168 CTRL_A, 169 CTRL_B, 170 CTRL_C, 171 CTRL_D, 172 } 173 174 struct KeyStrain { 175 KeyCode code; 176 int[] branch; 177 int opComp(const KeyStrain b) const { 178 return branch < b.branch; 179 } 180 } 181 182 enum strain = [ 183 KeyStrain(KeyCode.UP, [27, 91, 65]), 184 KeyStrain(KeyCode.DOWN, [27, 91, 66]), 185 KeyStrain(KeyCode.RIGHT, [27, 91, 67]), 186 KeyStrain(KeyCode.LEFT, [27, 91, 68]), 187 KeyStrain(KeyCode.HOME, [27, 91, 49, 59, 50, 72]), 188 KeyStrain(KeyCode.END, [27, 91, 49, 59, 50, 70]), 189 KeyStrain(KeyCode.PAGEDOWN, [27, 91, 54, 126]), 190 KeyStrain(KeyCode.PAGEUP, [27, 91, 53, 126]), 191 KeyStrain(KeyCode.DELETE, [27, 91, 51, 126]), 192 KeyStrain(KeyCode.F1, [27, 79, 80]), 193 KeyStrain(KeyCode.F2, [27, 79, 81]), 194 KeyStrain(KeyCode.F3, [27, 79, 82]), 195 KeyStrain(KeyCode.F4, [27, 79, 83]), 196 KeyStrain(KeyCode.F5, [27, 91, 49, 53, 126]), 197 KeyStrain(KeyCode.F6, [27, 91, 49, 55, 126]), 198 KeyStrain(KeyCode.F7, [27, 91, 49, 56, 126]), 199 KeyStrain(KeyCode.F8, [27, 91, 49, 57, 126]), 200 KeyStrain(KeyCode.F9, [27, 91, 50, 48, 126]), 201 KeyStrain(KeyCode.F10, [27, 91, 50, 49, 126]), 202 KeyStrain(KeyCode.F11, [27, 91, 50, 51, 126]), 203 KeyStrain(KeyCode.F12, [27, 91, 50, 52, 126]), 204 KeyStrain(KeyCode.CTRL_A, [1]), 205 KeyStrain(KeyCode.CTRL_B, [2]), 206 KeyStrain(KeyCode.CTRL_C, [3]), 207 KeyStrain(KeyCode.CTRL_D, [4]), 208 KeyStrain(KeyCode.ENTER, [13]), 209 KeyStrain(KeyCode.BACKSPACE, [127]), 210 ]; 211 212 KeyCode getKey(ref int ch) { 213 import std.algorithm; 214 import std.array; 215 216 enum StaticComp(KeyStrain a, KeyStrain b) = a.branch < b.branch; 217 218 enum sorted_strain = strain.array.sort!((a, b) => a.branch < b.branch); //staticSort!(StaticComp, strain); 219 KeyCode select(uint index = 0, uint pos = 0)(ref int ch) { 220 static if (index < sorted_strain.length) { 221 static if (pos < sorted_strain[index].branch.length) { 222 if (ch == sorted_strain[index].branch[pos]) { 223 static if (pos + 1 is sorted_strain[index].branch.length) { 224 return sorted_strain[index].code; 225 } 226 else { 227 ch = get; 228 return select!(index, pos + 1)(ch); 229 } 230 } 231 else if (ch > sorted_strain[index].branch[pos]) { 232 return select!(index + 1, pos)(ch); 233 } 234 else { 235 return KeyCode.NONE; 236 } 237 } 238 else { 239 return select!(index + 1, pos)(ch); 240 } 241 } 242 else { 243 return KeyCode.NONE; 244 } 245 } 246 247 ch = get; 248 return select(ch); 249 } 250 } 251 }