Terminal: Implement ANSI CSI A, B, b, d, @

This commit is contained in:
Bananymous 2025-04-17 23:16:22 +03:00
parent ebd00b1eb2
commit 4409d0f03f
2 changed files with 97 additions and 50 deletions

View File

@ -344,15 +344,25 @@ Rectangle Terminal::handle_csi(char ch)
Rectangle should_invalidate;
switch (ch)
{
case 'A':
if (m_csi_info.fields[0] == -1)
m_csi_info.fields[0] = 1;
m_cursor.y = BAN::Math::max<int32_t>(m_cursor.y - m_csi_info.fields[0], 0);
break;
case 'B':
if (m_csi_info.fields[0] == -1)
m_csi_info.fields[0] = 1;
m_cursor.y = BAN::Math::min<int32_t>(m_cursor.y + m_csi_info.fields[0], rows() - 1);
break;
case 'C':
if (m_csi_info.fields[0] == -1)
m_csi_info.fields[0] = 1;
m_cursor.x = BAN::Math::clamp<int32_t>(m_cursor.x + m_csi_info.fields[0], 0, cols() - 1);
m_cursor.x = BAN::Math::min<int32_t>(m_cursor.x + m_csi_info.fields[0], cols() - 1);
break;
case 'D':
if (m_csi_info.fields[0] == -1)
m_csi_info.fields[0] = 1;
m_cursor.x = BAN::Math::clamp<int32_t>((int32_t)m_cursor.x - m_csi_info.fields[0], 0, cols() - 1);
m_cursor.x = BAN::Math::max<int32_t>(m_cursor.x - m_csi_info.fields[0], 0);
break;
case 'G':
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, cols()) - 1;
@ -461,6 +471,34 @@ Rectangle Terminal::handle_csi(char ch)
break;
}
case '@':
{
const uint32_t count = (m_csi_info.fields[0] == -1) ? 1 : m_csi_info.fields[0];
const uint32_t dst_x = (m_cursor.x + count) * m_font.width();
const uint32_t src_x = m_cursor.x * m_font.width();
const uint32_t y = m_cursor.y * m_font.height();
m_window->copy_rect(dst_x, y, src_x, y, m_window->width() - dst_x, m_font.height(), m_bg_color);
m_window->fill_rect(src_x, y, count * m_font.width(), m_font.height(), m_bg_color);
should_invalidate = {
src_x,
y,
m_window->width() - src_x,
m_font.height()
};
break;
}
case 'b':
if (m_csi_info.fields[0] == -1)
m_csi_info.fields[0] = 1;
if (m_last_graphic_char)
for (int32_t i = 0; i < m_csi_info.fields[0]; i++)
should_invalidate = should_invalidate.get_bounding_box(putcodepoint(m_last_graphic_char));
break;
case 'd':
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
break;
case 'm':
handle_sgr();
break;
@ -488,6 +526,59 @@ Rectangle Terminal::handle_csi(char ch)
return should_invalidate;
}
Rectangle Terminal::putcodepoint(uint32_t codepoint)
{
Rectangle should_invalidate;
switch (codepoint)
{
case '\e':
m_state = State::ESC;
break;
case '\n':
m_cursor.x = 0;
m_cursor.y++;
break;
case '\r':
m_cursor.x = 0;
break;
case '\b':
if (m_cursor.x > 0)
m_cursor.x--;
break;
default:
{
const uint32_t cell_w = m_font.width();
const uint32_t cell_h = m_font.height();
const uint32_t cell_x = m_cursor.x * cell_w;
const uint32_t cell_y = m_cursor.y * cell_h;
m_window->fill_rect(cell_x, cell_y, cell_w, cell_h, m_bg_color);
m_window->draw_character(codepoint, m_font, cell_x, cell_y, m_fg_color);
m_last_graphic_char = codepoint;
should_invalidate = { cell_x, cell_y, cell_w, cell_h };
m_cursor.x++;
break;
}
}
if (m_cursor.x >= cols())
{
m_cursor.x = 0;
m_cursor.y++;
}
if (m_cursor.y >= rows())
{
const uint32_t scroll = m_cursor.y - rows() + 1;
m_cursor.y -= scroll;
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
}
return should_invalidate;
}
Rectangle Terminal::putchar(uint8_t ch)
{
if (m_state == State::ESC)
@ -550,54 +641,7 @@ Rectangle Terminal::putchar(uint8_t ch)
return {};
}
Rectangle should_invalidate;
switch (codepoint)
{
case '\e':
m_state = State::ESC;
break;
case '\n':
m_cursor.x = 0;
m_cursor.y++;
break;
case '\r':
m_cursor.x = 0;
break;
case '\b':
if (m_cursor.x > 0)
m_cursor.x--;
break;
default:
{
const uint32_t cell_w = m_font.width();
const uint32_t cell_h = m_font.height();
const uint32_t cell_x = m_cursor.x * cell_w;
const uint32_t cell_y = m_cursor.y * cell_h;
m_window->fill_rect(cell_x, cell_y, cell_w, cell_h, m_bg_color);
m_window->draw_character(codepoint, m_font, cell_x, cell_y, m_fg_color);
should_invalidate = { cell_x, cell_y, cell_w, cell_h };
m_cursor.x++;
break;
}
}
if (m_cursor.x >= cols())
{
m_cursor.x = 0;
m_cursor.y++;
}
if (m_cursor.y >= rows())
{
const uint32_t scroll = m_cursor.y - rows() + 1;
m_cursor.y -= scroll;
m_window->shift_vertical(-scroll * (int32_t)m_font.height(), m_bg_color);
should_invalidate = { 0, 0, m_window->width(), m_window->height() };
}
return should_invalidate;
return putcodepoint(codepoint);
}
void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent::event_t event)

View File

@ -37,6 +37,7 @@ public:
private:
void handle_sgr();
Rectangle handle_csi(char ch);
Rectangle putcodepoint(uint32_t codepoint);
Rectangle putchar(uint8_t ch);
bool read_shell();
@ -91,6 +92,8 @@ private:
uint8_t m_utf8_index { 0 };
uint8_t m_utf8_bytes[4] { };
uint32_t m_last_graphic_char { 0 };
Cursor m_saved_cursor { 0, 0 };
uint32_t m_fg_color { 0 };
uint32_t m_bg_color { 0 };