alec.hpp (10659B)
1 #ifndef ALEC_ALEC_H 2 #define ALEC_ALEC_H 3 4 #include <algorithm> 5 #include <array> 6 #include <assert.h> 7 #include <cstdint> 8 #include <string> 9 #include <type_traits> 10 namespace ALEC { 11 12 enum CTRL { 13 BELL = 0x07, 14 BS = 0x08, 15 HT = 0x09, 16 LF = 0x0A, 17 VT = 0x0B, 18 FF = 0x0C, 19 CR = 0x0D, 20 ESC = 0x1B, 21 DEL = 0x7F, 22 }; 23 24 enum class COLOR { 25 BLACK = 0, 26 RED = 1, 27 GREEN = 2, 28 YELLOW = 3, 29 BLUE = 4, 30 MAGENTA = 5, 31 CYAN = 6, 32 WHITE = 7, 33 DEFAULT = 9, 34 }; 35 36 enum class DECOR { 37 RESET = 0, 38 BOLD = 1, 39 DIM = 2, 40 ITALIC = 3, 41 UNDERLINE = 4, 42 BLINK = 5, 43 INVERSE = 7, 44 HIDE = 8, 45 STRIKE = 9, 46 }; 47 48 enum class MOTION { 49 END = 0, 50 BEGIN = 1, 51 WHOLE = 2, 52 }; 53 54 namespace details { 55 56 template <std::size_t N> struct string_literal { 57 consteval string_literal(const char (&str)[N]) { std::copy_n(str, N, value); } 58 consteval std::size_t size() const { return N; } 59 60 char value[N]; 61 }; 62 63 struct helper { 64 template <typename T> static consteval std::size_t size(T val); 65 template <typename T> static constexpr char *append(char *ptr, T val); 66 67 template <std::size_t N> static constexpr std::size_t size(string_literal<N> val) { return val.size(); } 68 static constexpr std::size_t size(char val) { return 1; } 69 static constexpr std::size_t size(int val) { 70 std::size_t len = 1; 71 while (val /= 10) 72 len++; 73 return len; 74 } 75 76 template <std::size_t N> static constexpr char *append(char *ptr, string_literal<N> val) { 77 std::copy_n(val.value, N, ptr); 78 return ptr + N; 79 } 80 81 static constexpr char *append(char *ptr, char val) { 82 *ptr++ = val; 83 return ptr; 84 } 85 86 static constexpr char *append(char *ptr, int val) { 87 char *tmp = ptr += size(val); 88 do { 89 *--tmp = '0' + (val % 10); 90 } while (val /= 10); 91 return ptr; 92 } 93 94 static const std::string make(auto... args) { 95 std::size_t len = (helper::size(args) + ... + 2); 96 std::string res(len, 'a'); 97 res[0] = CTRL::ESC, res[1] = '['; 98 auto map = [ptr = res.data() + 2](auto const &s) mutable { ptr = helper::append(ptr, s); }; 99 (map(args), ...); 100 res[len] = 0; 101 return res; 102 } 103 }; 104 105 template <auto... Args> struct escape_t { 106 static constexpr const auto value = []() { 107 constexpr std::size_t len = (helper::size(Args) + ... + 2); 108 std::array<char, len + 1> arr{CTRL::ESC, '[', 0}; 109 auto map = [ptr = arr.data() + 2](auto const &s) mutable { ptr = helper::append(ptr, s); }; 110 (map(Args), ...); 111 arr[len] = 0; 112 return arr; 113 }(); 114 }; 115 116 template <auto... Strs> static constexpr auto escape = escape_t<Strs...>::value.data(); 117 template <details::string_literal... Strs> static constexpr auto escape_literal = escape<Strs...>; 118 119 } // namespace details 120 121 // Tamplate parameter constraints 122 123 template <int n> 124 concept limit_256_v = n >= 0 && n < 256; 125 126 template <int n> 127 concept limit_pos_v = n >= 0; 128 129 static inline bool limit_pos(int n) { return n >= 0; }; 130 static inline bool limit_256(int n) { return n >= 0 && n < 256; }; 131 132 /* Template compile-time variables */ 133 134 // Move cursor up/down/frwd/back 135 template <int n> 136 requires limit_pos_v<n> 137 static constexpr auto cursor_up_v = details::escape<n, 'A'>; 138 139 template <int n> 140 requires limit_pos_v<n> 141 static constexpr auto cursor_down_v = details::escape<n, 'B'>; 142 143 template <int n> 144 requires limit_pos_v<n> 145 static constexpr auto cursor_frwd_v = details::escape<n, 'C'>; 146 147 template <int n> 148 requires limit_pos_v<n> 149 static constexpr auto cursor_back_v = details::escape<n, 'D'>; 150 151 // Move cursor to the next/prev line 152 template <int n> 153 requires limit_pos_v<n> 154 static constexpr auto cursor_line_next_v = details::escape<n, 'E'>; 155 156 template <int n> 157 requires limit_pos_v<n> 158 static constexpr auto cursor_line_prev_v = details::escape<n, 'F'>; 159 160 // Set cursor to specific column 161 template <int n> 162 requires limit_pos_v<n> 163 static constexpr auto cursor_column_v = details::escape<n, 'G'>; 164 165 // Erase functions 166 template <MOTION m> static constexpr auto erase_display_v = details::escape<(int)m, 'J'>; 167 template <MOTION m> static constexpr auto erase_line_v = details::escape<(int)m, 'K'>; 168 169 // Scroll up/down 170 template <int n> 171 requires limit_pos_v<n> 172 static constexpr auto scroll_up_v = details::escape<n, 'S'>; 173 174 template <int n> 175 requires limit_pos_v<n> 176 static constexpr auto scroll_down_v = details::escape<n, 'T'>; 177 178 // Set cursor to a specific position 179 template <int n, int m> 180 requires limit_pos_v<n> && limit_pos_v<m> 181 static constexpr auto cursor_position_v = details::escape<n, ';', m, 'H'>; 182 183 // color 184 template <auto... val> static const char *foreground_v; 185 template <auto... val> static const char *background_v; 186 187 // palet colors 188 template <COLOR color> static constexpr auto foreground_v<color> = details::escape<(int)color + 30, 'm'>; 189 template <COLOR color> static constexpr auto background_v<color> = details::escape<(int)color + 40, 'm'>; 190 191 // 256-color palette 192 template <int idx> 193 requires limit_256_v<idx> 194 static constexpr auto foreground_v<idx> = details::escape<38, ';', 5, ';', idx, 'm'>; 195 196 template <int idx> 197 requires limit_256_v<idx> 198 static constexpr auto background_v<idx> = details::escape<48, ';', 5, ';', idx, 'm'>; 199 200 // RGB colors 201 template <int R, int G, int B> 202 requires limit_256_v<R> && limit_256_v<G> && limit_256_v<B> 203 static constexpr auto foreground_v<R, G, B> = 204 details::escape<38, ';', 5, ';', R, ';', G, ';', B, 'm'>; 205 206 template <int R, int G, int B> 207 requires limit_256_v<R> && limit_256_v<G> && limit_256_v<B> 208 static constexpr auto background_v<R, G, B> = 209 details::escape<48, ';', 5, ';', R, ';', G, ';', B, 'm'>; 210 211 // Set/reset text decorators 212 template <DECOR decor> static constexpr auto decor_set_v = details::escape<(int)decor, 'm'>; 213 template <DECOR decor> static constexpr auto decor_reset_v = details::escape<(int)decor + 20, 'm'>; 214 215 // Save/load cursor position; 216 static constexpr auto cursor_save_v = details::escape<'s'>; 217 static constexpr auto cursor_load_v = details::escape<'u'>; 218 219 // Set screen modes 220 221 template <int n> 222 requires limit_pos_v<n> 223 static constexpr auto screen_mode_set_v = details::escape<'=', n, 'h'>; 224 225 template <int n> 226 requires limit_pos_v<n> 227 static constexpr auto screen_mode_reset_v = details::escape<'=', n, 'l'>; 228 229 // Private screen modes supported by most terminals 230 231 // Save/load screen 232 static constexpr auto screen_show_v = details::escape_literal<"?47h">; 233 static constexpr auto screen_hide_v = details::escape_literal<"?47l">; 234 235 // Show/hide cursor 236 static constexpr auto cursor_show_v = details::escape_literal<"?25h">; 237 static constexpr auto cursor_hide_v = details::escape_literal<"?25l">; 238 239 // Show/hide alternate buffer 240 static constexpr auto abuf_show_v = details::escape_literal<"?1049h">; 241 static constexpr auto abuf_hide_v = details::escape_literal<"?1049l">; 242 243 /* Run-time functions */ 244 245 // Move cursor up/down/frwd/back 246 static constexpr auto cursor_up(int n) { 247 assert(limit_pos(n)); 248 return details::helper::make(n, 'A'); 249 } 250 251 static constexpr auto cursor_down(int n) { 252 assert(limit_pos(n)); 253 return details::helper::make(n, 'B'); 254 } 255 256 static constexpr auto cursor_frwd(int n) { 257 assert(limit_pos(n)); 258 return details::helper::make(n, 'C'); 259 } 260 261 static constexpr auto cursor_back(int n) { 262 assert(limit_pos(n)); 263 return details::helper::make(n, 'D'); 264 } 265 266 // Move cursor to the next/prev line 267 static constexpr auto cursor_line_next(int n) { 268 assert(limit_pos(n)); 269 return details::helper::make(n, 'E'); 270 } 271 272 static constexpr auto cursor_line_prev(int n) { 273 assert(limit_pos(n)); 274 return details::helper::make(n, 'F'); 275 } 276 277 // Set cursor to specific column 278 static constexpr auto cursor_column(int n) { 279 assert(limit_pos(n)); 280 return details::helper::make(n, 'G'); 281 } 282 283 // Erase functions 284 static constexpr auto erase_display(MOTION m) { return details::helper::make((int)m, 'J'); } 285 static constexpr auto erase_line(MOTION m) { return details::helper::make((int)m, 'K'); } 286 287 // Scroll up/down 288 static constexpr auto scroll_up(int n) { 289 assert(limit_pos(n)); 290 return details::helper::make(n, 'S'); 291 } 292 293 static constexpr auto scroll_down(int n) { 294 assert(limit_pos(n)); 295 return details::helper::make(n, 'T'); 296 } 297 298 // Set cursor to a specific position 299 static constexpr auto cursor_position(int n, int m) { 300 assert(limit_pos(n)); 301 assert(limit_pos(m)); 302 return details::helper::make(n, ';', m, 'H'); 303 } 304 305 // color 306 307 // palet colors 308 static constexpr auto foreground(COLOR color) { return details::helper::make((int)color + 30, 'm'); } 309 static constexpr auto background(COLOR color) { return details::helper::make((int)color + 40, 'm'); } 310 311 // 256-color palette 312 static constexpr auto foreground(int idx) { 313 assert(limit_256(idx)); 314 return details::helper::make(38, ';', 5, ';', idx, 'm'); 315 } 316 317 static constexpr auto background(int idx) { 318 assert(limit_256(idx)); 319 return details::helper::make(48, ';', 5, ';', idx, 'm'); 320 } 321 322 // RGB colors 323 static constexpr auto foreground(int R, int G, int B) { 324 assert(limit_256(R)); 325 assert(limit_256(G)); 326 assert(limit_256(B)); 327 return details::helper::make(38, ';', 5, ';', R, ';', G, ';', B, 'm'); 328 } 329 330 static constexpr auto background(int R, int G, int B) { 331 assert(limit_256(R)); 332 assert(limit_256(G)); 333 assert(limit_256(B)); 334 return details::helper::make(48, ';', 5, ';', R, ';', G, ';', B, 'm'); 335 } 336 337 // Set/reset text decorators 338 static constexpr auto decor_set(DECOR decor) { return details::helper::make((int)decor, 'm'); } 339 static constexpr auto decor_reset(DECOR decor) { return details::helper::make((int)decor + 20, 'm'); } 340 341 // Save/load cursor position; 342 static constexpr auto cursor_save() { return cursor_save_v; } 343 static constexpr auto cursor_load() { return cursor_load_v; } 344 345 // Set screen modes 346 static constexpr auto screen_mode_set(int n) { 347 assert(limit_pos(n)); 348 return details::helper::make('=', n, 'h'); 349 } 350 351 static constexpr auto screen_mode_reset(int n) { 352 assert(limit_pos(n)); 353 return details::helper::make('=', n, 'l'); 354 } 355 356 // Private screen modes supported by most terminals 357 358 // Save/load screen 359 static constexpr auto screen_show() { return screen_show_v; } 360 static constexpr auto screen_hide() { return screen_hide_v; } 361 362 // Show/hide cursor 363 static constexpr auto cursor_show() { return cursor_show_v; } 364 static constexpr auto cursor_hide() { return cursor_hide_v; } 365 366 // Show/hide alternate buffer 367 static constexpr auto abuf_show() { return abuf_show_v; } 368 static constexpr auto abuf_hide() { return abuf_hide_v; } 369 370 // Keyboard string TODO 371 372 } // namespace ALEC 373 374 #endif