alec

Abstraction Layer for Escape Codes
git clone git://git.dimitrijedobrota.com/alec.git
Log | Files | Refs

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