Kernel: Add support for 8bit and 24bit ANSI SGR

This commit is contained in:
Bananymous 2025-04-23 19:19:00 +03:00
parent dabc3c6cc4
commit a8edb8870e
2 changed files with 59 additions and 8 deletions

View File

@ -51,11 +51,15 @@ namespace Kernel
struct AnsiState struct AnsiState
{ {
int32_t nums[2] { -1, -1 }; static constexpr size_t max_nums = 5;
int32_t index { 0 }; int32_t nums[max_nums] { -1, -1, -1, -1, -1 };
size_t index { 0 };
bool question { false }; bool question { false };
}; };
BAN::Optional<TerminalDriver::Color> get_8bit_color();
BAN::Optional<TerminalDriver::Color> get_24bit_color();
struct UTF8State struct UTF8State
{ {
uint32_t codepoint { 0 }; uint32_t codepoint { 0 };

View File

@ -138,18 +138,50 @@ namespace Kernel
} }
} }
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_8bit_color()
{
ASSERT(m_ansi_state.nums[1] == 5);
if (m_ansi_state.nums[2] < 1)
return {};
const uint8_t code = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
if (code < 16)
return m_palette[code];
if (code < 232)
{
const uint8_t r = (code - 16) / 36 % 6 * 40 + 55;
const uint8_t g = (code - 16) / 6 % 6 * 40 + 55;
const uint8_t b = (code - 16) / 1 % 6 * 40 + 55;
return TerminalDriver::Color(r, g, b);
}
const uint8_t gray = (code - 232) * 10 + 8;
return TerminalDriver::Color(gray, gray, gray);
}
BAN::Optional<TerminalDriver::Color> VirtualTTY::get_24bit_color()
{
ASSERT(m_ansi_state.nums[1] == 2);
if (m_ansi_state.nums[2] < 1) return {};
if (m_ansi_state.nums[3] < 1) return {};
if (m_ansi_state.nums[4] < 1) return {};
const uint8_t r = BAN::Math::min(m_ansi_state.nums[2], 256) - 1;
const uint8_t g = BAN::Math::min(m_ansi_state.nums[3], 256) - 1;
const uint8_t b = BAN::Math::min(m_ansi_state.nums[4], 256) - 1;
return TerminalDriver::Color(r, g, b);
}
void VirtualTTY::handle_ansi_csi(uint8_t ch) void VirtualTTY::handle_ansi_csi(uint8_t ch)
{ {
constexpr size_t max_ansi_args = sizeof(m_ansi_state.nums) / sizeof(*m_ansi_state.nums);
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
switch (ch) switch (ch)
{ {
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
{ {
if ((size_t)m_ansi_state.index >= max_ansi_args) if (m_ansi_state.index >= m_ansi_state.max_nums)
dwarnln("Only {} arguments supported with ANSI codes", max_ansi_args); dwarnln("Only {} arguments supported with ANSI codes", m_ansi_state.max_nums);
else else
{ {
int32_t& val = m_ansi_state.nums[m_ansi_state.index]; int32_t& val = m_ansi_state.nums[m_ansi_state.index];
@ -158,7 +190,7 @@ namespace Kernel
return; return;
} }
case ';': case ';':
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args); m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, m_ansi_state.max_nums);
return; return;
case 'A': // Cursor Up case 'A': // Cursor Up
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
@ -290,7 +322,22 @@ namespace Kernel
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f"); dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
return; return;
case 'm': case 'm':
for (int i = 0; i <= m_ansi_state.index && i < static_cast<int>(max_ansi_args); i++) if (m_ansi_state.nums[0] == 38 || m_ansi_state.nums[0] == 48)
{
if (m_ansi_state.nums[1] != 5 && m_ansi_state.nums[1] != 2)
{
reset_ansi();
dprintln_if(DEBUG_VTTY, "Unsupported ANSI SGR {}", m_ansi_state.nums[1]);
return;
}
const auto color = (m_ansi_state.nums[1] == 5)
? get_8bit_color()
: get_24bit_color();
if (color.has_value())
(m_ansi_state.nums[0] == 38 ? m_foreground : m_background) = *color;
return reset_ansi();
}
for (size_t i = 0; i <= m_ansi_state.index && i < m_ansi_state.max_nums; i++)
handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0)); handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0));
return reset_ansi(); return reset_ansi();
case 's': case 's':