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 | e584d30759cc8d1233906f107c9c2e07683a66ca |
parent | b02e0ba34e3a27238bfa660bedf1e87fb6313f15 |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Sun, 15 Jun 2025 18:18:50 +0200 |
Greatly simplify the implementation
M | CMakeLists.txt | | | + - |
M | example/alec_runtime.cpp | | | + - |
M | include/alec/alec.hpp | | | +++++++++++++++++++++++++++++++++++++ --------------------------------------------- |
3 files changed, 156 insertions(+), 189 deletions(-)
diff --git a/ CMakeLists.txt b/ CMakeLists.txt
@@ -4,7 +4,7 @@
include(cmake/prelude.cmake)
project(
alec
VERSION 0.2.0
VERSION 0.2.1
DESCRIPTION "Abstraction Layer for Escape Codes"
HOMEPAGE_URL "git://git.dimitrijedobrota.com/alec.git"
LANGUAGES CXX
diff --git a/ example/alec_runtime.cpp b/ example/alec_runtime.cpp
@@ -12,7 +12,7 @@
int main()
std::cout << cursor_position(1, 1) << foreground(91) << "HELLO!\n";
std::cout << cursor_down(3);
std::cout << foreground(30) << background(96, 53, 64) << "WORLD!\n";
std::cout << foreground(30) << background(196, 53, 64) << "WORLD!\n";
std::cout << background(color::def) << "testing 1...\n"
<< foreground(color::def);
diff --git a/ include/alec/alec.hpp b/ include/alec/alec.hpp
@@ -1,13 +1,13 @@
#pragma once
#include <algorithm>
#include <array>
#include <cassert>
#include <string>
#include <based/enum/enum.hpp>
#include <based/string/literal.hpp>
#include <based/string/to_string.hpp>
#include <based/types/types.hpp>
#include <based/utility/static_view.hpp>
namespace alec
{
@@ -32,198 +32,63 @@
BASED_DEFINE_ENUM(motion, based::bu8, 0, ENUM_MOTION)
namespace detail
{
template<std::size_t n>
static constexpr std::size_t size(based::string_literal<n> /*val*/)
{
return n;
}
static constexpr std::size_t size(char /*val*/)
{
return 1;
}
static constexpr std::string start = "\x01B[";
template<class T>
static constexpr std::size_t size(T val)
constexpr void append(std::string& res, const auto& arg)
{
std::size_t len = 1;
while ((val /= 10) != 0) {
len++;
}
return len;
res += based::to_string(arg);
res += ';';
}
template<std::size_t n>
static constexpr char* append(char* ptr, based::string_literal<n> val)
template<class... Args>
constexpr std::string test(char chr, Args... args)
{
std::copy_n(val.data(), n, ptr);
return ptr + n; // NOLINT
}
auto res = start;
static constexpr char* append(char* ptr, char val)
{
*ptr++ = val; // NOLINT
return ptr;
}
template<class T>
static constexpr char* append(char* ptr, T val)
{
char* tmp = ptr += size(val); // NOLINT
do { // NOLINT
*--tmp = '0' + static_cast<char>(val % 10); // NOLINT
} while ((val /= 10) != 0);
return ptr;
}
(append(res, args), ...);
res.back() = chr;
static constexpr std::string make(auto... args)
{
std::string res((size(args) + ... + 2), 0);
res[0] = 0x1B, res[1] = '[';
auto* ptr = res.data() + 2; // NOLINT
((ptr = append(ptr, args)), ...);
return res;
}
template<auto... args>
struct escape_t
{
static constexpr const auto value = []()
{
std::array<char, (size(args) + ... + 3)> arr = {};
arr[0] = 0x1B, arr[1] = '[';
auto* ptr = arr.data() + 2;
((ptr = append(ptr, args)), ...);
return arr;
}();
static constexpr auto data = value.data();
};
template<auto... args>
static constexpr auto escape = alec::detail::escape_t<args...>::data;
template<based::string_literal... strs>
static constexpr auto escape_literal = escape<strs...>;
template<auto func, auto... args>
static constexpr std::string_view escape = based::to_string_view(
[]()
{
return func(args...);
}
);
template<based::string_literal str>
static constexpr std::string_view escape_literal = based::to_string_view(
[]
{
return start + std::string(str);
}
);
} // namespace detail
// Template compile-time variables
// Forward-declare templates
template<auto... val>
static const char* const background_v = "";
template<auto... val>
static const char* const foreground_v = "";
// Template specializations
// Move cursor up/down/frwd/back
template<unsigned cnt>
static constexpr auto cursor_up_v = detail::escape<cnt, 'A'>;
template<unsigned cnt>
static constexpr auto cursor_down_v = detail::escape<cnt, 'B'>;
template<unsigned cnt>
static constexpr auto cursor_frwd_v = detail::escape<cnt, 'C'>;
template<unsigned cnt>
static constexpr auto cursor_back_v = detail::escape<cnt, 'D'>;
// Move cursor to the next/prev line
template<unsigned cnt>
static constexpr auto cursor_line_next_v = detail::escape<cnt, 'E'>;
template<unsigned cnt>
static constexpr auto cursor_line_prev_v = detail::escape<cnt, 'F'>;
// Set cursor to specific column
template<unsigned col>
static constexpr auto cursor_column_v = detail::escape<col, 'G'>;
// Erase functions
template<motion::enum_type motion>
static constexpr auto erase_display_v = detail::escape<motion(), 'J'>;
template<motion::enum_type motion>
static constexpr auto erase_line_v = detail::escape<motion(), 'K'>;
// Scroll up/down
template<unsigned cnt>
static constexpr auto scroll_up_v = detail::escape<cnt, 'S'>;
template<unsigned cnt>
static constexpr auto scroll_down_v = detail::escape<cnt, 'T'>;
// Set cursor to a specific position
template<unsigned row, unsigned col>
static constexpr auto cursor_position_v = detail::escape<row, ';', col, 'H'>;
// color
// palet colors
template<color::enum_type color>
static constexpr auto foreground_v<color> = detail::escape<color() + 30, 'm'>;
template<color::enum_type color>
static constexpr auto background_v<color> = detail::escape<color() + 40, 'm'>;
// 256-color palette
template<based::bu8 idx>
static constexpr auto foreground_v<idx> =
detail::escape<38, ';', 5, ';', idx, 'm'>;
template<based::bu8 idx>
static constexpr auto background_v<idx> =
detail::escape<48, ';', 5, ';', idx, 'm'>;
// RGB colors
template<based::bu8 red, based::bu8 green, based::bu8 blue>
static constexpr auto foreground_v<red, green, blue> =
detail::escape<38, ';', 2, ';', red, ';', green, ';', blue, 'm'>;
template<based::bu8 red, based::bu8 green, based::bu8 blue>
static constexpr auto background_v<red, green, blue> =
detail::escape<48, ';', 2, ';', red, ';', green, ';', blue, 'm'>;
// Set/reset text decorators
template<decor::enum_type decor>
static constexpr auto decor_set_v = detail::escape<decor(), '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'>;
static constexpr auto cursor_restore_v = detail::escape<'u'>;
// Set screen modes
template<unsigned mode>
static constexpr auto screen_mode_set_v = detail::escape<'=', mode, 'h'>;
template<unsigned mode>
static constexpr auto screen_mode_reset_v = detail::escape<'=', mode, 'l'>;
// Private screen modes supported by most terminals
// Save/restore screen
static constexpr auto screen_save_v = detail::escape_literal<"?47h">;
static constexpr auto screen_restore_v = detail::escape_literal<"?47l">;
// Show/hide cursor
static constexpr auto cursor_show_v = detail::escape_literal<"?25h">;
static constexpr auto cursor_hide_v = detail::escape_literal<"?25l">;
// Save/restore cursor
static constexpr auto cursor_save_v = detail::escape_literal<"s">;
static constexpr auto cursor_restore_v = detail::escape_literal<"u">;
// Enable/disable alternate buffer
static constexpr auto abuf_enable_v = detail::escape_literal<"?1049h">;
static constexpr auto abuf_disable_v = detail::escape_literal<"?1049l">;
// Enable/disable bracketed paste mode
static constexpr auto paste_enable_v = detail::escape_literal<"?2004h">;
static constexpr auto paste_disable_v = detail::escape_literal<"?2004l">;
// Run-time functions
@@ -231,90 +96,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::make(cnt, 'A');
return detail::test('A', cnt);
}
static constexpr auto cursor_down(unsigned cnt)
{
return detail::make(cnt, 'B');
return detail::test('B', cnt);
}
static constexpr auto cursor_frwd(unsigned cnt)
{
return detail::make(cnt, 'C');
return detail::test('C', cnt);
}
static constexpr auto cursor_back(unsigned cnt)
{
return detail::make(cnt, 'D');
return detail::test('D', cnt);
}
// Move cursor to the next/prev line
static constexpr auto cursor_line_next(unsigned cnt)
{
return detail::make(cnt, 'E');
return detail::test('E', cnt);
}
static constexpr auto cursor_line_prev(unsigned cnt)
{
return detail::make(cnt, 'F');
return detail::test('F', cnt);
}
// Set cursor to specific column
static constexpr auto cursor_column(unsigned col)
{
return detail::make(col, 'G');
return detail::test('G', col);
}
// Erase functions
static constexpr auto erase_display(motion::enum_type motion)
{
return detail::make(motion(), 'J');
return detail::test('J', motion());
}
static constexpr auto erase_line(motion::enum_type motion)
{
return detail::make(motion(), 'K');
return detail::test('K', motion());
}
// Scroll up/down
static constexpr auto scroll_up(unsigned cnt)
{
return detail::make(cnt, 'S');
return detail::test('S', cnt);
}
static constexpr auto scroll_down(unsigned cnt)
{
return detail::make(cnt, 'T');
return detail::test('T', cnt);
}
// Set cursor to a specific position
static constexpr auto cursor_position(unsigned row, unsigned col)
{
return detail::make(row, ';', col, 'H');
return detail::test('H', row, col);
}
// color
// palet colors
static constexpr auto foreground(color::enum_type color)
{
return detail::make(color() + 30, 'm');
return detail::test('m', color() + 30);
}
static constexpr auto background(color::enum_type color)
{
return detail::make(color() + 40, 'm');
return detail::test('m', color() + 40);
}
// 256-color palette
static constexpr auto foreground(based::bu8 idx)
{
return detail::make(38, ';', 5, ';', idx, 'm');
return detail::test('m', 38, 5, idx);
}
static constexpr auto background(based::bu8 idx)
{
return detail::make(48, ';', 5, ';', idx, 'm');
return detail::test('m', 48, 5, idx);
}
// RGB colors
@@ -322,36 +187,138 @@
static constexpr auto foreground(
based::bu8 red, based::bu8 green, based::bu8 blue
)
{
return detail::make(38, ';', 2, ';', red, ';', green, ';', blue, 'm');
return detail::test('m', 38, 2, red, green, blue);
}
static constexpr auto background(
based::bu8 red, based::bu8 green, based::bu8 blue
)
{
return detail::make(48, ';', 2, ';', red, ';', green, ';', blue, 'm');
return detail::test('m', 48, 2, red, green, blue);
}
// Set/reset text decorators
static constexpr auto decor_set(decor::enum_type decor)
{
return detail::make(decor(), 'm');
return detail::test('m', decor());
}
static constexpr auto decor_reset(decor::enum_type decor)
{
return detail::make(decor() + 20, 'm');
return detail::test('m', decor() + 20);
}
// Set screen modes
static constexpr auto screen_mode_set(unsigned mode)
{
return detail::make('=', mode, 'h');
return detail::test('h', '=', mode);
}
static constexpr auto screen_mode_reset(unsigned mode)
{
return detail::make('=', mode, 'l');
return detail::test('l', '=', mode);
}
// Template specializations
// Move cursor up/down/frwd/back
template<unsigned cnt>
static constexpr auto cursor_up_v = detail::escape<cursor_up, cnt>;
template<unsigned cnt>
static constexpr auto cursor_down_v = detail::escape<cursor_down, cnt>;
template<unsigned cnt>
static constexpr auto cursor_frwd_v = detail::escape<cursor_frwd, cnt>;
template<unsigned cnt>
static constexpr auto cursor_back_v = detail::escape<cursor_back, cnt>;
// Move cursor to the next/prev line
template<unsigned cnt>
static constexpr auto cursor_line_next_v =
detail::escape<cursor_line_next, cnt>;
template<unsigned cnt>
static constexpr auto cursor_line_prev_v =
detail::escape<cursor_line_prev, cnt>;
// Set cursor to specific column
template<unsigned cnt>
static constexpr auto cursor_column_v = detail::escape<cursor_column, cnt>;
// Erase functions
template<motion::enum_type motion>
static constexpr auto erase_display_v = detail::escape<erase_display, motion>;
template<motion::enum_type motion>
static constexpr auto erase_line_v = detail::escape<erase_line, motion>;
// Scroll up/down
template<unsigned cnt>
static constexpr auto scroll_up_v = detail::escape<scroll_up, cnt>;
template<unsigned cnt>
static constexpr auto scroll_down_v = detail::escape<scroll_down, cnt>;
// Set cursor to a specific position
template<unsigned row, unsigned col>
static constexpr auto cursor_position_v =
detail::escape<cursor_position, row, col>;
// Color
template<auto... val>
static constexpr std::string_view foreground_v;
template<auto... val>
static constexpr std::string_view background_v;
template<color::enum_type color>
static constexpr auto foreground_v<color> = detail::
escape<static_cast<std::string (*)(color::enum_type)>(foreground), color>;
template<color::enum_type color>
static constexpr auto background_v<color> = detail::
escape<static_cast<std::string (*)(color::enum_type)>(background), color>;
template<based::bu8 idx>
static constexpr auto foreground_v<idx> =
detail::escape<static_cast<std::string (*)(based::bu8)>(foreground), idx>;
template<based::bu8 idx>
static constexpr auto background_v<idx> =
detail::escape<static_cast<std::string (*)(based::bu8)>(background), idx>;
template<based::bu8 red, based::bu8 green, based::bu8 blue>
static constexpr auto foreground_v<red, green, blue> = detail::escape<
static_cast<std::string (*)(based::bu8, based::bu8, based::bu8)>(foreground
),
red,
green,
blue>;
template<based::bu8 red, based::bu8 green, based::bu8 blue>
static constexpr auto background_v<red, green, blue> = detail::escape<
static_cast<std::string (*)(based::bu8, based::bu8, based::bu8)>(background
),
red,
green,
blue>;
// Set/reset text decorators
template<decor::enum_type decor>
static constexpr auto decor_set_v = detail::escape<decor_set, decor>;
template<decor::enum_type decor>
static constexpr auto decor_reset_v = detail::escape<decor_reset, decor>;
// Set screen modes
template<unsigned mode>
static constexpr auto screen_mode_set_v = detail::escape<screen_mode_set, mode>;
template<unsigned mode>
static constexpr auto screen_mode_reset_v =
detail::escape<screen_mode_reset, mode>;
} // namespace alec