Terminal: Implement ANSI CSI A, B, b, d, @
This commit is contained in:
parent
ebd00b1eb2
commit
4409d0f03f
|
@ -344,15 +344,25 @@ Rectangle Terminal::handle_csi(char ch)
|
||||||
Rectangle should_invalidate;
|
Rectangle should_invalidate;
|
||||||
switch (ch)
|
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':
|
case 'C':
|
||||||
if (m_csi_info.fields[0] == -1)
|
if (m_csi_info.fields[0] == -1)
|
||||||
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;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
if (m_csi_info.fields[0] == -1)
|
if (m_csi_info.fields[0] == -1)
|
||||||
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;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
m_cursor.x = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, cols()) - 1;
|
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;
|
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':
|
case 'm':
|
||||||
handle_sgr();
|
handle_sgr();
|
||||||
break;
|
break;
|
||||||
|
@ -488,6 +526,59 @@ Rectangle Terminal::handle_csi(char ch)
|
||||||
return should_invalidate;
|
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)
|
Rectangle Terminal::putchar(uint8_t ch)
|
||||||
{
|
{
|
||||||
if (m_state == State::ESC)
|
if (m_state == State::ESC)
|
||||||
|
@ -550,54 +641,7 @@ Rectangle Terminal::putchar(uint8_t ch)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle should_invalidate;
|
return putcodepoint(codepoint);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent::event_t event)
|
void Terminal::on_key_event(LibGUI::EventPacket::KeyEvent::event_t event)
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void handle_sgr();
|
void handle_sgr();
|
||||||
Rectangle handle_csi(char ch);
|
Rectangle handle_csi(char ch);
|
||||||
|
Rectangle putcodepoint(uint32_t codepoint);
|
||||||
Rectangle putchar(uint8_t ch);
|
Rectangle putchar(uint8_t ch);
|
||||||
bool read_shell();
|
bool read_shell();
|
||||||
|
|
||||||
|
@ -91,6 +92,8 @@ private:
|
||||||
uint8_t m_utf8_index { 0 };
|
uint8_t m_utf8_index { 0 };
|
||||||
uint8_t m_utf8_bytes[4] { };
|
uint8_t m_utf8_bytes[4] { };
|
||||||
|
|
||||||
|
uint32_t m_last_graphic_char { 0 };
|
||||||
|
|
||||||
Cursor m_saved_cursor { 0, 0 };
|
Cursor m_saved_cursor { 0, 0 };
|
||||||
uint32_t m_fg_color { 0 };
|
uint32_t m_fg_color { 0 };
|
||||||
uint32_t m_bg_color { 0 };
|
uint32_t m_bg_color { 0 };
|
||||||
|
|
Loading…
Reference in New Issue