Kernel: Fix ANSI CSI @ and b for VirtualTTY

This commit is contained in:
Bananymous 2025-04-17 23:24:17 +03:00
parent 4409d0f03f
commit 439fb57d88
2 changed files with 78 additions and 69 deletions

View File

@ -31,6 +31,7 @@ namespace Kernel
void reset_ansi(); void reset_ansi();
void handle_ansi_csi(uint8_t ch); void handle_ansi_csi(uint8_t ch);
void handle_ansi_csi_color(uint8_t ch); void handle_ansi_csi_color(uint8_t ch);
void putcodepoint(uint32_t codepoint);
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
void render_from_buffer(uint32_t x, uint32_t y); void render_from_buffer(uint32_t x, uint32_t y);
void set_cursor_position(uint32_t x, uint32_t y); void set_cursor_position(uint32_t x, uint32_t y);

View File

@ -329,23 +329,24 @@ namespace Kernel
case '@': case '@':
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
m_ansi_state.nums[0] = 1; m_ansi_state.nums[0] = 1;
reset_ansi(); m_ansi_state.nums[0] = BAN::Math::min<uint32_t>(m_ansi_state.nums[0], m_width - m_column);
memmove(
&m_buffer[m_row * m_width + m_column],
&m_buffer[m_row * m_width + m_column + m_ansi_state.nums[0]],
m_width - m_column - m_ansi_state.nums[0]
);
for (int i = 0; i < m_ansi_state.nums[0]; i++) for (int i = 0; i < m_ansi_state.nums[0]; i++)
putchar_impl(' '); putchar_at(' ', m_column + i, m_row);
return; for (uint32_t x = m_column + m_ansi_state.nums[0]; x < m_width; x++)
render_from_buffer(x, m_row);
return reset_ansi();
case 'b': case 'b':
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
m_ansi_state.nums[0] = 1; m_ansi_state.nums[0] = 1;
reset_ansi();
if (m_last_graphic_char) if (m_last_graphic_char)
{
char buffer[5] {};
BAN::UTF8::from_codepoints(&m_last_graphic_char, 1, buffer);
for (int i = 0; i < m_ansi_state.nums[0]; i++) for (int i = 0; i < m_ansi_state.nums[0]; i++)
for (int j = 0; buffer[j]; j++) putcodepoint(m_last_graphic_char);
putchar_impl(buffer[j]); return reset_ansi();
}
return;
case 'd': case 'd':
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
m_ansi_state.nums[0] = 1; m_ansi_state.nums[0] = 1;
@ -396,6 +397,70 @@ namespace Kernel
m_terminal_driver->putchar_at(codepoint, x, y, m_foreground, m_background); m_terminal_driver->putchar_at(codepoint, x, y, m_foreground, m_background);
} }
void VirtualTTY::putcodepoint(uint32_t codepoint)
{
ASSERT(m_write_lock.current_processor_has_lock());
switch (codepoint)
{
case BEL: // TODO
break;
case BS:
if (m_column > 0)
putchar_at(' ', --m_column, m_row);
break;
case HT:
m_column++;
while (m_column % 8)
m_column++;
break;
case LF:
m_column = 0;
m_row++;
break;
case FF:
m_row++;
break;
case CR:
m_column = 0;
break;
case ESC:
m_state = State::WaitingAnsiEscape;
break;
default:
putchar_at(codepoint, m_column, m_row);
m_last_graphic_char = codepoint;
m_column++;
break;
}
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
}
void VirtualTTY::putchar_impl(uint8_t ch) void VirtualTTY::putchar_impl(uint8_t ch)
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
@ -465,64 +530,7 @@ namespace Kernel
m_show_cursor = false; m_show_cursor = false;
set_cursor_position(m_column, m_row); set_cursor_position(m_column, m_row);
switch (codepoint) putcodepoint(codepoint);
{
case BEL: // TODO
break;
case BS:
if (m_column > 0)
putchar_at(' ', --m_column, m_row);
break;
case HT:
m_column++;
while (m_column % 8)
m_column++;
break;
case LF:
m_column = 0;
m_row++;
break;
case FF:
m_row++;
break;
case CR:
m_column = 0;
break;
case ESC:
m_state = State::WaitingAnsiEscape;
break;
default:
putchar_at(codepoint, m_column, m_row);
m_last_graphic_char = codepoint;
m_column++;
break;
}
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
while (m_row >= m_height)
{
memmove(m_buffer, m_buffer + m_width, m_width * (m_height - 1) * sizeof(Cell));
// Clear last line in buffer
for (uint32_t x = 0; x < m_width; x++)
m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' };
if (!m_terminal_driver->scroll(m_background))
{
// No fast scrolling, render the whole buffer to the screen
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
render_from_buffer(x, y);
}
m_column = 0;
m_row--;
}
m_show_cursor = old_show_cursor; m_show_cursor = old_show_cursor;
set_cursor_position(m_column, m_row); set_cursor_position(m_column, m_row);