alecAbstraction Layer for Escape Codes | 
          
| git clone git://git.dimitrijedobrota.com/alec.git | 
| Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | 
| commit | c63bca584930693f0470ee517f924d3eedccabb7 | 
| parent | 621cc1fdfe336bbff877ceac0318e289d2eb811f | 
| author | Dimitrije Dobrota < mail@dimitrijedobrota.com > | 
| date | Mon, 1 Jan 2024 23:18:06 +0000 | 
Rewrite, use template variables
* Not locked in with basic_ostream
* Greatly simplify the template code
* Cleaner implementation
* Enforce validity with concepts
* Further improved my understanding of templates
* Add details namespace to hide implementation
| M | CMakeLists.txt | | | + - | 
| M | demo/demo.cpp | | | ++ -- | 
| M | src/alec.hpp | | | ++++++++++++++++++++++++++++++++ -------------------------------------------------- | 
3 files changed, 127 insertions(+), 195 deletions(-)
diff --git a/ CMakeLists.txt b/ CMakeLists.txt
          @@ -3,7 +3,7 @@ 
          set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
        
        
          project(
              Alec
          	VERSION 0.0.4
          	VERSION 0.0.5
              DESCRIPTION "Abstraction Layer for Escape Codes"
          	HOMEPAGE_URL https://git.dimitrijedobrota.com/alec.git
              LANGUAGES CXX
        
        diff --git a/ demo/demo.cpp b/ demo/demo.cpp
          @@ -7,10 +7,10 @@ 
          int main(void) {
        
        
              std::cout << ABUF_SHOW << CURSOR_HIDE;
              std::cout << CURSOR_POSITION<1, 1> << FOREGROUND<91> << "HELLO!\n";
              std::cout << CURSOR_POSITION<1, 1> << FOREGROUND_256<91> << "HELLO!\n";
              std::cout << CURSOR_DOWN<3>;
              std::cout << FOREGROUND<30> << BACKGROUND<196> << "WORLD!\n";
              std::cout << FOREGROUND_256<30> << BACKGROUND_256<196> << "WORLD!\n";
              std::cout << BACKGROUND<DEFAULT> << "testing 1...\n" << FOREGROUND<DEFAULT>;
              std::cout << DECOR_SET<INVERSE> << "testing 2...\n" << DECOR_RESET<INVERSE>;
        
        diff --git a/ src/alec.hpp b/ src/alec.hpp
@@ -1,10 +1,11 @@
#ifndef ALEC_ALEC_H
          #define ALEC_ALEC_H
          #include <algorithm>
          #include <array>
          #include <cstdint>
          #include <iostream>
          #include <string_view>
          #include <type_traits>
          namespace ALEC {
          
          @@ -47,233 +48,164 @@ 
          enum class DECOR {
        
        
          using enum COLOR;
          using enum DECOR;
          template <std::string_view const &...Strs> struct join {
              static constexpr auto arr = []() {
                  constexpr std::size_t len = (Strs.size() + ... + 0);
                  std::array<char, len + 1> arr{};
                  auto append = [i = 0, &arr](auto const &s) mutable {
                      for (auto c : s)
                          arr[i++] = c;
                  };
                  (append(Strs), ...);
          namespace details {
          template <std::size_t N> struct string_literal {
              consteval string_literal(const char (&str)[N]) { std::copy_n(str, N, value); }
              consteval std::size_t size() const { return N; }
              char value[N];
          };
          template <auto... Args> struct escape_t {
              template <typename T> static consteval std::size_t size(T val);
              template <typename T> static constexpr char *append(char *ptr, T val);
              template <std::size_t N> static constexpr std::size_t size(string_literal<N> val) { return val.size(); }
              static constexpr std::size_t size(char val) { return 1; }
              static constexpr std::size_t size(intmax_t val) {
                  std::size_t len = 1;
                  while (val /= 10)
                      len++;
                  return len;
              }
              template <std::size_t N> static constexpr char *append(char *ptr, string_literal<N> val) {
                  std::copy_n(val.value, N, ptr);
                  return ptr + N;
              }
              static constexpr char *append(char *ptr, char val) {
                  *ptr++ = val;
                  return ptr;
              }
              static constexpr char *append(char *ptr, intmax_t val) {
                  char *tmp = ptr += size(val);
                  do {
                      *--tmp = '0' + (val % 10);
                  } while (val /= 10);
                  return ptr;
              }
              static constexpr const auto value = []() {
                  constexpr std::size_t len = (size(Args) + ... + 2);
                  std::array<char, len + 1> arr{CTRL::ESC, '[', 0};
                  auto map = [ptr = arr.data() + 2](auto const &s) mutable { ptr = append(ptr, s); };
                  (map(Args), ...);
                  arr[len] = 0;
                  return arr;
              }();
              static constexpr std::string_view value{arr.data(), arr.size() - 1};
          };
          template <std::intmax_t N> class to_string_t {
            public:
              constexpr operator const auto &() const { return value; }
            private:
              static constexpr auto buf = []() {
                  constexpr const auto len = []() {
                      std::size_t len = 1;
                      for (auto n = N; n; len++, n /= 10)
                          ;
                      return len;
                  }();
          template <auto... Strs> static constexpr auto escape = escape_t<Strs...>::value.data();
                  std::array<char, len> arr{};
          } // namespace details
                  auto ptr = arr.data() + len;
                  *--ptr = '\0';
          // Tamplate parameter constraints
                  arr[0] = 0;
                  for (auto n = N; n; n /= 10)
                      *--ptr = '0' + n % 10;
          template <intmax_t n>
          concept limit_256 = n >= 0 && n < 256;
                  return arr;
              }();
              static constexpr std::string_view value{buf.data(), buf.size() - 1};
          };
          template <intmax_t n>
          concept limit_pos = n >= 0;
          template <char C> class to_string_c {
            public:
              constexpr operator const auto &() const { return value; }
            private:
              static constexpr auto c = C;
              static constexpr std::string_view value{&c, 1};
          };
          template <intmax_t n>
          concept limit_4 = n >= 0 && n <= 4;
          static constexpr const std::string_view buffer = "?1049";
          static constexpr const std::string_view cursor = "?25";
          static constexpr const std::string_view esc = "\033[";
          static constexpr const std::string_view sep = ";";
          // Move cursor up/down/frwd/back
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_UP = details::escape<n, 'A'>;
          template <std::string_view const &...Strs> static constexpr auto concatenate = join<Strs...>::value;
          template <std::string_view const &...Strs> static constexpr auto escape = join<esc, Strs...>::value;
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_DOWN = details::escape<n, 'B'>;
          template <std::intmax_t N> constexpr to_string_t<N> to_string;
          template <char C> constexpr to_string_c<C> to_stringc;
          template <std::intmax_t N> static constexpr auto to_stringp = join<to_string<N>, sep>::value;
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_FRWD = details::escape<n, 'C'>;
          // Move cursor up/down/frwd/back
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_UP(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'A'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_DOWN(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'B'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_FRWD(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'C'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_BACK(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'D'>>;
          }
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_BACK = details::escape<n, 'D'>;
          // Move cursor to the next/prev line
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_LINE_NEXT(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'E'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_LINE_PREV(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'F'>>;
          }
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_LINE_NEXT = details::escape<n, 'E'>;
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_LINE_PREV = details::escape<n, 'F'>;
          // Set cursor to specific column
          template <int n, class CharT, class Traits>
          static constexpr auto &CURSOR_COLUMN(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'G'>>;
          }
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto CURSOR_COLUMN = details::escape<n, 'G'>;
          // Erase functions
          template <int n, class CharT, class Traits>
          static constexpr auto &ERASE_DISPLAY(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0 && n <= 4, "invalid argument");
              return bos << escape<to_string<n>, to_stringc<'J'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &ERASE_LINE(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0 && n <= 4, "invalid argument");
              return bos << escape<to_string<n>, to_stringc<'K'>>;
          }
          template <intmax_t n>
              requires limit_4<n>
          static constexpr auto ERASE_DISPLAY = details::escape<n, 'J'>;
          template <intmax_t n>
              requires limit_4<n>
          static constexpr auto ERASE_LINE = details::escape<n, 'K'>;
          // Scroll up/down
          template <int n, class CharT, class Traits>
          static constexpr auto &SCROLL_UP(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'S'>>;
          }
          template <int n, class CharT, class Traits>
          static constexpr auto &SCROLL_DOWN(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0, "cant' use negative numbers");
              return bos << escape<to_string<n>, to_stringc<'T'>>;
          }
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto SCROLL_UP = details::escape<n, 'S'>;
          template <intmax_t n>
              requires limit_pos<n>
          static constexpr auto SCROLL_DOWN = details::escape<n, 'T'>;
          // Set cursor to a specific position
          template <int n, int m, class CharT, class Traits>
          static constexpr auto &CURSOR_POSITION(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(n >= 0 && m >= 0, "cant' use negative numbers");
              return bos << escape<to_stringp<n>, to_string<m>, to_stringc<'H'>>;
          }
          template <intmax_t n, intmax_t m>
              requires limit_pos<n> && limit_pos<m>
          static constexpr auto CURSOR_POSITION = details::escape<n, ';', m, 'H'>;
          // palet colors
          template <COLOR color, class CharT, class Traits>
          static constexpr auto &FOREGROUND(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_string<static_cast<uint>(color) + 30>, to_stringc<'m'>>;
          }
          template <COLOR color, class CharT, class Traits>
          static constexpr auto &BACKGROUND(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_string<static_cast<uint>(color) + 40>, to_stringc<'m'>>;
          }
          template <COLOR color> static constexpr auto FOREGROUND = details::escape<(intmax_t)color + 30, 'm'>;
          template <COLOR color> static constexpr auto BACKGROUND = details::escape<(intmax_t)color + 40, 'm'>;
          // 256-color palette
          template <int idx, class CharT, class Traits>
          static constexpr auto &FOREGROUND(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(idx >= 0 && idx < 256, "value must be between 0 and 255");
              return bos << escape<to_stringp<38>, to_stringp<5>, to_string<idx>, to_stringc<'m'>>;
          }
          template <int idx, class CharT, class Traits>
          static constexpr auto &BACKGROUND(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(idx >= 0 && idx < 256, "value must be between 0 and 255");
              return bos << escape<to_stringp<48>, to_stringp<5>, to_string<idx>, to_stringc<'m'>>;
          }
          template <intmax_t idx>
              requires limit_256<idx>
          static constexpr auto FOREGROUND_256 = details::escape<intmax_t(38), ';', intmax_t(5), ';', idx, 'm'>;
          template <intmax_t idx>
              requires limit_256<idx>
          static constexpr auto BACKGROUND_256 = details::escape<intmax_t(48), ';', intmax_t(5), ';', idx, 'm'>;
          // RGB colors
          template <int R, int G, int B, class CharT, class Traits>
          static constexpr auto &FOREGROUND(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(R >= 0 && R < 256, "R value must be between 0 and 255");
              static_assert(G >= 0 && G < 256, "G value must be between 0 and 255");
              static_assert(B >= 0 && B < 256, "B value must be between 0 and 255");
              return bos << escape<to_stringp<38>, to_stringp<5>, to_stringp<R>, to_stringp<G>, to_string<B>,
                                   to_stringc<'m'>>;
          }
          template <int R, int G, int B, class CharT, class Traits>
          static constexpr auto &BACKGROUND(std::basic_ostream<CharT, Traits> &bos) {
              static_assert(R >= 0 && R < 256, "R value must be between 0 and 255");
              static_assert(G >= 0 && G < 256, "G value must be between 0 and 255");
              static_assert(B >= 0 && B < 256, "B value must be between 0 and 255");
              return bos << escape<to_stringp<48>, to_stringp<5>, to_stringp<R>, to_stringp<G>, to_string<B>,
                                   to_stringc<'m'>>;
          }
          template <intmax_t R, intmax_t G, intmax_t B>
              requires limit_256<R> && limit_256<G> && limit_256<B>
          static constexpr auto FOREGROUND_RGB =
              details::escape<intmax_t(38), ';', intmax_t(5), ';', R, ';', G, ';', B, 'm'>;
          template <intmax_t R, intmax_t G, intmax_t B>
              requires limit_256<R> && limit_256<G> && limit_256<B>
          static constexpr auto BACKGROUND_RGB =
              details::escape<intmax_t(48), ';', intmax_t(5), ';', R, ';', G, ';', B, 'm'>;
          // Set/reset text decorators
          template <DECOR decor, class CharT, class Traits>
          static constexpr auto &DECOR_SET(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_string<static_cast<uint>(decor)>, to_stringc<'m'>>;
          }
          template <DECOR decor, class CharT, class Traits>
          static constexpr auto &DECOR_RESET(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_string<static_cast<uint>(decor) + 20>, to_stringc<'m'>>;
          }
          // Savle/load cursor position
          template <class CharT, class Traits>
          static constexpr auto &CURSOR_SAVE(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_stringc<'s'>>;
          }
          template <class CharT, class Traits>
          static constexpr auto &CURSOR_LOAD(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<to_stringc<'u'>>;
          }
          template <DECOR decor> static constexpr const char *DECOR_SET = details::escape<(intmax_t)decor, 'm'>;
          template <DECOR decor> static constexpr const char *DECOR_RESET = details::escape<(intmax_t)decor + 20, 'm'>;
          // Show/hide cursor
          template <class CharT, class Traits>
          static constexpr auto &CURSOR_SHOW(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<cursor, to_stringc<'h'>>;
          }
          // Savle/load cursor position;
          static constexpr const char *CURSOR_SAVE = details::escape<'s'>;
          static constexpr const char *CURSOR_LOAD = details::escape<'u'>;
          template <class CharT, class Traits>
          static constexpr auto &CURSOR_HIDE(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<cursor, to_stringc<'l'>>;
          }
          // Show/hide cursor
          static constexpr const char *CURSOR_SHOW = details::escape<details::string_literal("?25h")>;
          static constexpr const char *CURSOR_HIDE = details::escape<details::string_literal("?25l")>;
          // Show/hide alternate buffer
          template <class CharT, class Traits>
          static constexpr auto &ABUF_SHOW(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<buffer, to_stringc<'h'>>;
          }
          template <class CharT, class Traits>
          static constexpr auto &ABUF_HIDE(std::basic_ostream<CharT, Traits> &bos) {
              return bos << escape<buffer, to_stringc<'l'>>;
          }
          static constexpr const char *ABUF_SHOW = details::escape<details::string_literal("?1049h")>;
          static constexpr const char *ABUF_HIDE = details::escape<details::string_literal("?1049l")>;
          } // namespace ALEC