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 | b6aefc9b942a0f464448415670b8679298a51782 | 
| parent | d705309b300eaf8f7c60a6eb6774f21e5634789c | 
| author | Dimitrije Dobrota < mail@dimitrijedobrota.com > | 
| date | Tue, 20 May 2025 21:47:04 +0200 | 
Cleanup
| M | include/alec/alec.hpp | | | +++++++++++++++++++++++++++++++++++++++ ------------------------------------------- | 
| M | include/alec/terminal.hpp | | | ++++++++++++++++++++++++++++++++++++++++ ------------------------------------------ | 
2 files changed, 102 insertions(+), 111 deletions(-)
diff --git a/ include/alec/alec.hpp b/ include/alec/alec.hpp
          @@ -14,26 +14,24 @@ 
          namespace alec
        
        
          #define ENUM_COLOR                                                             \
            black, red, green, yellow, blue, magenta, cyan, white, unused_1, def
          BASED_DECLARE_ENUM(color, based::bi8, 0, ENUM_COLOR)
          BASED_DEFINE_ENUM(color, based::bi8, 0, ENUM_COLOR)
          BASED_DECLARE_ENUM(color, based::bu8, 0, ENUM_COLOR)
          BASED_DEFINE_ENUM(color, based::bu8, 0, ENUM_COLOR)
          #undef ENUM_COLOR
          #define ENUM_DECOR                                                             \
            reset, bold, dim, italic, underline, blink, unused_1, inverse, hide, strike
          BASED_DECLARE_ENUM(decor, based::bi8, 0, ENUM_DECOR)
          BASED_DEFINE_ENUM(decor, based::bi8, 0, ENUM_DECOR)
          BASED_DECLARE_ENUM(decor, based::bu8, 0, ENUM_DECOR)
          BASED_DEFINE_ENUM(decor, based::bu8, 0, ENUM_DECOR)
          #undef ENUM_DECOR
          #define ENUM_MOTION end, begin, whole
          BASED_DECLARE_ENUM(motion, based::bi8, 0, ENUM_MOTION)
          BASED_DEFINE_ENUM(motion, based::bi8, 0, ENUM_MOTION)
          BASED_DECLARE_ENUM(motion, based::bu8, 0, ENUM_MOTION)
          BASED_DEFINE_ENUM(motion, based::bu8, 0, ENUM_MOTION)
          #undef ENUM_MOTION
          namespace detail
          {
          namespace helper
          {
          template<std::size_t n>
          static constexpr std::size_t size(based::string_literal<n> /*val*/)
          {
        
        
          @@ -79,10 +77,10 @@ 
          static constexpr char* append(char* ptr, T val)
        
        
          static constexpr std::string make(auto... args)
          {
            std::string res((helper::size(args) + ... + 2), 0);
            std::string res((size(args) + ... + 2), 0);
            res[0] = 0x1B, res[1] = '[';
            auto* ptr = res.data() + 2;  // NOLINT
            ((ptr = helper::append(ptr, args)), ...);
            ((ptr = append(ptr, args)), ...);
            return res;
          }
          
          @@ -91,19 +89,17 @@ 
          struct escape_t
        
        
          {
            static constexpr const auto value = []()
            {
              std::array<char, (helper::size(args) + ... + 3)> arr = {};
              std::array<char, (size(args) + ... + 3)> arr = {};
              arr[0] = 0x1B, arr[1] = '[';
              auto* ptr = arr.data() + 2;
              ((ptr = helper::append(ptr, args)), ...);
              ((ptr = append(ptr, args)), ...);
              return arr;
            }();
            static constexpr auto data = value.data();
          };
          }  // namespace helper
          template<auto... args>
          static constexpr auto escape = alec::detail::helper::escape_t<args...>::data;
          static constexpr auto escape = alec::detail::escape_t<args...>::data;
          template<based::string_literal... strs>
          static constexpr auto escape_literal = escape<strs...>;
        
        
          @@ -147,11 +143,11 @@ 
          template<unsigned col>
        
        
          static constexpr auto cursor_column_v = detail::escape<col, 'G'>;
          // Erase functions
          template<motion::type motion>
          static constexpr auto erase_display_v = detail::escape<motion.value, 'J'>;
          template<motion::enum_type motion>
          static constexpr auto erase_display_v = detail::escape<motion(), 'J'>;
          template<motion::type motion>
          static constexpr auto erase_line_v = detail::escape<motion.value, 'K'>;
          template<motion::enum_type motion>
          static constexpr auto erase_line_v = detail::escape<motion(), 'K'>;
          // Scroll up/down
          template<unsigned cnt>
        
        
          @@ -166,13 +162,11 @@ 
          static constexpr auto cursor_position_v = detail::escape<row, ';', col, 'H'>;
        
        
          // color
          // palet colors
          template<color::type color>
          static constexpr auto foreground_v<color> =
              detail::escape<color.value + 30, 'm'>;
          template<color::enum_type color>
          static constexpr auto foreground_v<color> = detail::escape<color() + 30, 'm'>;
          template<color::type color>
          static constexpr auto background_v<color> =
              detail::escape<color.value + 40, 'm'>;
          template<color::enum_type color>
          static constexpr auto background_v<color> = detail::escape<color() + 40, 'm'>;
          // 256-color palette
          template<based::bu8 idx>
        
        
          @@ -193,11 +187,11 @@ 
          static constexpr auto background_v<red, green, blue> =
        
        
              detail::escape<48, ';', 2, ';', red, ';', green, ';', blue, 'm'>;
          // Set/reset text decorators
          template<decor::type decor>
          static constexpr auto decor_set_v = detail::escape<decor.value, 'm'>;
          template<decor::enum_type decor>
          static constexpr auto decor_set_v = detail::escape<decor(), 'm'>;
          template<decor::type decor>
          static constexpr auto decor_reset_v = detail::escape<decor.value + 20, 'm'>;
          template<decor::enum_type decor>
          static constexpr auto decor_reset_v = detail::escape<decor() + 20, 'm'>;
          // Save/restore cursor position;
          static constexpr auto cursor_save_v = detail::escape<'s'>;
        
        
          @@ -237,90 +231,90 @@ 
          static constexpr auto paste_disable_v = detail::escape_literal<"?2004l">;
        
        
          // Move cursor up/down/frwd/back
          static constexpr auto cursor_up(unsigned cnt)
          {
            return detail::helper::make(cnt, 'A');
            return detail::make(cnt, 'A');
          }
          static constexpr auto cursor_down(unsigned cnt)
          {
            return detail::helper::make(cnt, 'B');
            return detail::make(cnt, 'B');
          }
          static constexpr auto cursor_frwd(unsigned cnt)
          {
            return detail::helper::make(cnt, 'C');
            return detail::make(cnt, 'C');
          }
          static constexpr auto cursor_back(unsigned cnt)
          {
            return detail::helper::make(cnt, 'D');
            return detail::make(cnt, 'D');
          }
          // Move cursor to the next/prev line
          static constexpr auto cursor_line_next(unsigned cnt)
          {
            return detail::helper::make(cnt, 'E');
            return detail::make(cnt, 'E');
          }
          static constexpr auto cursor_line_prev(unsigned cnt)
          {
            return detail::helper::make(cnt, 'F');
            return detail::make(cnt, 'F');
          }
          // Set cursor to specific column
          static constexpr auto cursor_column(unsigned col)
          {
            return detail::helper::make(col, 'G');
            return detail::make(col, 'G');
          }
          // Erase functions
          static constexpr auto erase_display(motion::type motion)
          static constexpr auto erase_display(motion::enum_type motion)
          {
            return detail::helper::make(motion.value, 'J');
            return detail::make(motion(), 'J');
          }
          static constexpr auto erase_line(motion::type motion)
          static constexpr auto erase_line(motion::enum_type motion)
          {
            return detail::helper::make(motion.value, 'K');
            return detail::make(motion(), 'K');
          }
          // Scroll up/down
          static constexpr auto scroll_up(unsigned cnt)
          {
            return detail::helper::make(cnt, 'S');
            return detail::make(cnt, 'S');
          }
          static constexpr auto scroll_down(unsigned cnt)
          {
            return detail::helper::make(cnt, 'T');
            return detail::make(cnt, 'T');
          }
          // Set cursor to a specific position
          static constexpr auto cursor_position(unsigned row, unsigned col)
          {
            return detail::helper::make(row, ';', col, 'H');
            return detail::make(row, ';', col, 'H');
          }
          // color
          // palet colors
          static constexpr auto foreground(color::type color)
          static constexpr auto foreground(color::enum_type color)
          {
            return detail::helper::make(color.value + 30, 'm');
            return detail::make(color() + 30, 'm');
          }
          static constexpr auto background(color::type color)
          static constexpr auto background(color::enum_type color)
          {
            return detail::helper::make(color.value + 40, 'm');
            return detail::make(color() + 40, 'm');
          }
          // 256-color palette
          static constexpr auto foreground(based::bu8 idx)
          {
            return detail::helper::make(38, ';', 5, ';', idx, 'm');
            return detail::make(38, ';', 5, ';', idx, 'm');
          }
          static constexpr auto background(based::bu8 idx)
          {
            return detail::helper::make(48, ';', 5, ';', idx, 'm');
            return detail::make(48, ';', 5, ';', idx, 'm');
          }
          // RGB colors
        
        
          @@ -328,36 +322,36 @@ 
          static constexpr auto foreground(
        
        
              based::bu8 red, based::bu8 green, based::bu8 blue
          )
          {
            return detail::helper::make(38, ';', 2, ';', red, ';', green, ';', blue, 'm');
            return detail::make(38, ';', 2, ';', red, ';', green, ';', blue, 'm');
          }
          static constexpr auto background(
              based::bu8 red, based::bu8 green, based::bu8 blue
          )
          {
            return detail::helper::make(48, ';', 2, ';', red, ';', green, ';', blue, 'm');
            return detail::make(48, ';', 2, ';', red, ';', green, ';', blue, 'm');
          }
          // Set/reset text decorators
          static constexpr auto decor_set(decor::type decor)
          static constexpr auto decor_set(decor::enum_type decor)
          {
            return detail::helper::make(decor.value, 'm');
            return detail::make(decor(), 'm');
          }
          static constexpr auto decor_reset(decor::type decor)
          static constexpr auto decor_reset(decor::enum_type decor)
          {
            return detail::helper::make(decor.value + 20, 'm');
            return detail::make(decor() + 20, 'm');
          }
          // Set screen modes
          static constexpr auto screen_mode_set(unsigned mode)
          {
            return detail::helper::make('=', mode, 'h');
            return detail::make('=', mode, 'h');
          }
          static constexpr auto screen_mode_reset(unsigned mode)
          {
            return detail::helper::make('=', mode, 'l');
            return detail::make('=', mode, 'l');
          }
          }  // namespace alec
        
        diff --git a/ include/alec/terminal.hpp b/ include/alec/terminal.hpp
@@ -4,6 +4,9 @@
#include <optional>
          #include <stdexcept>
          #include <based/enum/enum.hpp>
          #include <based/enum/enum_flag.hpp>
          #include <based/types/types.hpp>
          #include <sys/ioctl.h>
          #include <termios.h>
          #include <unistd.h>
        
        
          @@ -20,18 +23,13 @@ 
          public:
        
        
            }
          };
          enum error_code_t  // NOLINT
          {
            FDNTERM,
            TERMIOSRD,
            TERMIOSWR,
            BUFFULL,
            CHARRD,
            IOCTL,
            SCREENSZ
          };
          #define ENUM_ERROR_CODE                                                        \
            fdnterm, termiosrd, termioswr, buffull, charrd, ioctl, screensz
          BASED_DECLARE_ENUM(error_code_t, based::bi8, 0, ENUM_ERROR_CODE)
          BASED_DEFINE_ENUM(error_code_t, based::bi8, 0, ENUM_ERROR_CODE)
          #undef ENUM_ERROR_CODE
          template<error_code_t e>
          template<error_code_t::enum_type e>
          class error : public runtime_error
          {
          public:
        
        
          @@ -41,26 +39,26 @@ 
          public:
        
        
            }
          private:
            static std::string error_get_message(error_code_t error)
            static std::string error_get_message(error_code_t::enum_type error)
            {
              switch (error) {
                case error_code_t::FDNTERM:
              switch (error()) {
                case error_code_t::fdnterm():
                  return "File descriptor is not associated with a terminal";
                case error_code_t::TERMIOSRD:
                case error_code_t::termiosrd():
                  return "Can't read termios";
                case error_code_t::TERMIOSWR:
                case error_code_t::termioswr():
                  return "Can't write termios";
                case error_code_t::BUFFULL:
                case error_code_t::buffull():
                  return "Buffer is full";
                case error_code_t::CHARRD:
                case error_code_t::charrd():
                  return "Can't read character";
                case error_code_t::IOCTL:
                case error_code_t::ioctl():
                  return "ioctl error";
                case error_code_t::SCREENSZ:
                case error_code_t::screensz():
                  return "Can't determine the screen size";
                default:
                  return "alec error, should not happen...";
              }
              return "alec error, should not happen...";
            }
          };
          
          @@ -72,11 +70,11 @@ 
          public:
        
        
                , m_orig_termios()
            {
              if (isatty(m_fd) == 0) {
                throw error<error_code_t::FDNTERM>();
                throw error<error_code_t::fdnterm>();
              }
              if (tcgetattr(m_fd, &m_orig_termios) == -1) {
                throw error<error_code_t::TERMIOSRD>();
                throw error<error_code_t::termiosrd>();
              }
              struct termios raw = m_orig_termios;
        
        
          @@ -92,7 +90,7 @@ 
          public:
        
        
              /* put terminal in raw mode after flushing */
              if (tcsetattr(m_fd, TCSAFLUSH, &raw) < 0) {
                throw error<error_code_t::TERMIOSWR>();
                throw error<error_code_t::termioswr>();
              }
            }
          
          @@ -137,7 +135,7 @@ 
          private:
        
        
            {
              ssize_t scnt = -1;
              if ((m_end + 1) % m_buffer.size() == m_start) {
                throw error<error_code_t::BUFFULL>();
                throw error<error_code_t::buffull>();
              }
              if (m_start <= m_end) {
        
        
          @@ -147,7 +145,7 @@ 
          private:
        
        
              }
              if (scnt == -1) {
                throw error<error_code_t::CHARRD>();
                throw error<error_code_t::charrd>();
              }
              const auto cnt = static_cast<size_t>(scnt);
        
        
          @@ -191,61 +189,60 @@ 
          inline std::pair<std::uint16_t, std::uint16_t> get_screen_size()
        
        
          #elif defined(TIOCGWINSZ)
            struct winsize tts = {};
            if (ioctl(STDIN_FILENO, TIOCGWINSZ, &tts) == -1) {  // NOLINT
              throw error<error_code_t::IOCTL>();
              throw error<error_code_t::ioctl>();
            }
            return {tts.ws_col, tts.ws_row};
          #endif /* TIOCGSIZE */
            throw error<error_code_t::SCREENSZ>();
            throw error<error_code_t::screensz>();
          }
          #define ENUM_EVENT_TYPE none, key, resize, mouse
          #define ENUM_EVENT_MOD none, alt, ctrl, shift, motion
          class event
          {
          public:
            enum class Type : std::uint8_t
            {
              NONE = 0,
              KEY = 1,
              RESIZE = 2,
              MOUSE = 3,
            };
            BASED_DECLARE_ENUM(type, based::bu8, 0, ENUM_EVENT_TYPE)
            BASED_DECLARE_ENUM_FLAG(mod, based::bu8, ENUM_EVENT_MOD)
            enum class Mod : std::uint8_t
            {
              ALT = 1,
              CTRL = 2,
              SHIFT = 4,
              MOTION = 8,
            };
            event(Type type, uint8_t mod_mask, uint8_t key)  // NOLINT
            event(type::enum_type type, uint8_t mod_mask, uint8_t key)  // NOLINT
                : m_type(type)
                , m_mod_mask(mod_mask)
                , m_key(key)
            {
            }
            const auto& type() const { return m_type; }
            auto& type() { return m_type; }
            [[nodiscard]] const auto& type() const { return m_type; }
            [[nodiscard]] auto& type() { return m_type; }
            const auto& key() const { return m_key; }
            auto& key() { return m_key; }
            [[nodiscard]] const auto& key() const { return m_key; }
            [[nodiscard]] auto& key() { return m_key; }
            const auto& mod_mask() const { return m_mod_mask; }
            auto& mod_mask() { return m_mod_mask; }
            [[nodiscard]] const auto& mod_mask() const { return m_mod_mask; }
            [[nodiscard]] auto& mod_mask() { return m_mod_mask; }
            bool is_set(uint8_t mask) const { return mask == (m_mod_mask & mask); }
            [[nodiscard]] bool is_set(uint8_t mask) const
            {
              return mask == (m_mod_mask & mask);
            }
          private:
            Type m_type = Type::NONE;
            type::enum_type m_type = type::none;
            uint8_t m_mod_mask = 0;
            uint8_t m_key = 0;
          };
          BASED_DEFINE_ENUM_FLAG_CLASS(event, mod, based::bu8, ENUM_EVENT_MOD)
          #undef ENUM_EVENT_MOD
          BASED_DEFINE_ENUM_CLASS(event, type, based::bu8, 0, ENUM_EVENT_TYPE)
          #undef ENUM_EVENT_TYPE
          inline event get_event()
          {
            const auto chr = get_buffer().value().read();
            return {chr != 0 ? event::Type::KEY : event::Type::NONE, 0, chr};
            return {chr != 0 ? event::type::key : event::type::none, 0, chr};
          }
          }  // namespace alec