Compare commits

..

No commits in common. "9f4cb5c4dd5cd80fedd4d1ae47810d8fdba3ec91" and "95a80bfe81d535d5d50150525db3f9f2dcc30c6c" have entirely different histories.

18 changed files with 189 additions and 349 deletions

View File

@ -18,78 +18,78 @@ namespace BAN
using const_iterator = ConstIteratorSimple<T, Array>;
public:
constexpr Array() = default;
constexpr Array(const T&);
Array() = default;
Array(const T&);
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + size()); }
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + size()); }
constexpr const T& operator[](size_type) const;
constexpr T& operator[](size_type);
const T& operator[](size_type) const;
T& operator[](size_type);
constexpr const T& back() const;
constexpr T& back();
constexpr const T& front() const;
constexpr T& front();
const T& back() const;
T& back();
const T& front() const;
T& front();
Span<T> span() { return Span(m_data, size()); }
const Span<T> span() const { return Span(m_data, size()); }
constexpr size_type size() const;
constexpr const T* data() const { return m_data; }
constexpr T* data() { return m_data; }
const T* data() const { return m_data; }
T* data() { return m_data; }
private:
T m_data[S] {};
};
template<typename T, size_t S>
constexpr Array<T, S>::Array(const T& value)
Array<T, S>::Array(const T& value)
{
for (size_type i = 0; i < S; i++)
m_data[i] = value;
}
template<typename T, size_t S>
constexpr const T& Array<T, S>::operator[](size_type index) const
const T& Array<T, S>::operator[](size_type index) const
{
ASSERT(index < S);
return m_data[index];
}
template<typename T, size_t S>
constexpr T& Array<T, S>::operator[](size_type index)
T& Array<T, S>::operator[](size_type index)
{
ASSERT(index < S);
return m_data[index];
}
template<typename T, size_t S>
constexpr const T& Array<T, S>::back() const
const T& Array<T, S>::back() const
{
ASSERT(S != 0);
return m_data[S - 1];
}
template<typename T, size_t S>
constexpr T& Array<T, S>::back()
T& Array<T, S>::back()
{
ASSERT(S != 0);
return m_data[S - 1];
}
template<typename T, size_t S>
constexpr const T& Array<T, S>::front() const
const T& Array<T, S>::front() const
{
ASSERT(S != 0);
return m_data[0];
}
template<typename T, size_t S>
constexpr T& Array<T, S>::front()
T& Array<T, S>::front()
{
ASSERT(S != 0);
return m_data[0];

View File

@ -27,10 +27,9 @@ namespace Kernel
const LibFont::Font& font() const override { return m_font; };
private:
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device, const Palette& palette)
: TerminalDriver(palette)
, m_framebuffer_device(framebuffer_device)
{}
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
: m_framebuffer_device(framebuffer_device)
{ }
void read_cursor();
void show_cursor(bool use_data);
@ -43,7 +42,7 @@ namespace Kernel
uint32_t m_cursor_y { 0 };
bool m_cursor_shown { true };
BAN::Vector<uint32_t> m_cursor_data;
static constexpr Color m_cursor_color = TerminalColor::WHITE;
static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE;
};
}

View File

@ -20,7 +20,7 @@ namespace Kernel
BAN::ErrorOr<BAN::String> ptsname();
bool putchar(uint8_t ch);
void putchar(uint8_t ch);
protected:
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
@ -61,7 +61,7 @@ namespace Kernel
void clear() override;
protected:
bool putchar_impl(uint8_t ch) override;
void putchar_impl(uint8_t ch) override;
BAN::ErrorOr<long> ioctl_impl(int, void*) override;

View File

@ -53,7 +53,7 @@ namespace Kernel
protected:
virtual BAN::StringView name() const override { return m_name; }
virtual bool putchar_impl(uint8_t) override;
virtual void putchar_impl(uint8_t) override;
private:
SerialTTY(Serial);

View File

@ -58,14 +58,14 @@ namespace Kernel
protected:
TTY(mode_t mode, uid_t uid, gid_t gid);
virtual bool putchar_impl(uint8_t ch) = 0;
virtual void putchar_impl(uint8_t ch) = 0;
virtual void update_cursor() {}
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
private:
bool putchar(uint8_t ch);
void putchar(uint8_t ch);
void do_backspace();
protected:

View File

@ -12,28 +12,20 @@ namespace Kernel
public:
struct Color
{
constexpr Color()
: rgb(0)
{ }
constexpr Color(uint32_t rgb)
: rgb(rgb)
{ }
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
{ }
constexpr uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
constexpr uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
constexpr uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
uint32_t rgb;
};
using Palette = BAN::Array<Color, 16>;
public:
static BAN::ErrorOr<void> initialize_from_boot_info();
TerminalDriver(const Palette& palette)
: m_palette(palette)
{}
virtual ~TerminalDriver() {}
virtual uint32_t width() const = 0;
virtual uint32_t height() const = 0;
@ -48,19 +40,29 @@ namespace Kernel
virtual bool has_font() const { return false; }
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); }
const Palette& palette() const { return m_palette; }
protected:
Palette m_palette;
};
extern BAN::RefPtr<TerminalDriver> g_terminal_driver;
namespace TerminalColor
{
constexpr TerminalDriver::Color BLACK = 0x000000;
constexpr TerminalDriver::Color WHITE = 0xFFFFFF;
static constexpr TerminalDriver::Color BLACK = 0x000000;
static constexpr TerminalDriver::Color RED = 0xFF0000;
static constexpr TerminalDriver::Color GREEN = 0x00FF00;
static constexpr TerminalDriver::Color YELLOW = 0xFFFF00;
static constexpr TerminalDriver::Color BLUE = 0x0000FF;
static constexpr TerminalDriver::Color MAGENTA = 0xFF00FF;
static constexpr TerminalDriver::Color CYAN = 0x00FFFF;
static constexpr TerminalDriver::Color WHITE = 0xBFBFBF;
static constexpr TerminalDriver::Color BRIGHT_BLACK = 0x3F3F3F;
static constexpr TerminalDriver::Color BRIGHT_RED = 0xFF7F7F;
static constexpr TerminalDriver::Color BRIGHT_GREEN = 0x7FFF7F;
static constexpr TerminalDriver::Color BRIGHT_YELLOW = 0xFFFF7F;
static constexpr TerminalDriver::Color BRIGHT_BLUE = 0x7F7FFF;
static constexpr TerminalDriver::Color BRIGHT_MAGENTA = 0xFF7FFF;
static constexpr TerminalDriver::Color BRIGHT_CYAN = 0x7FFFFF;
static constexpr TerminalDriver::Color BRIGHT_WHITE = 0xFFFFFF;
}
}

View File

@ -21,9 +21,8 @@ namespace Kernel
void set_cursor_position(uint32_t, uint32_t) override;
private:
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, const Palette& palette)
: TerminalDriver(palette)
, m_paddr(paddr)
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
: m_paddr(paddr)
, m_width(width)
, m_height(height)
, m_pitch(pitch)
@ -37,7 +36,7 @@ namespace Kernel
const uint32_t m_height;
const uint32_t m_pitch;
vaddr_t m_vaddr { 0 };
static constexpr Color s_cursor_color = TerminalColor::WHITE;
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
};
}

View File

@ -11,9 +11,6 @@ namespace Kernel
class VirtualTTY : public TTY
{
public:
using Palette = TerminalDriver::Palette;
public:
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
@ -26,7 +23,7 @@ namespace Kernel
protected:
virtual BAN::StringView name() const override { return m_name; }
virtual bool putchar_impl(uint8_t ch) override;
virtual void putchar_impl(uint8_t ch) override;
void update_cursor() override;
private:
@ -38,7 +35,6 @@ namespace Kernel
void putcodepoint(uint32_t codepoint);
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
void render_from_buffer(uint32_t x, uint32_t y);
void scroll_if_needed();
private:
enum class State
@ -51,15 +47,11 @@ namespace Kernel
struct AnsiState
{
static constexpr size_t max_nums = 5;
int32_t nums[max_nums] { -1, -1, -1, -1, -1 };
size_t index { 0 };
int32_t nums[2] { -1, -1 };
int32_t index { 0 };
bool question { false };
};
BAN::Optional<TerminalDriver::Color> get_8bit_color();
BAN::Optional<TerminalDriver::Color> get_24bit_color();
struct UTF8State
{
uint32_t codepoint { 0 };
@ -68,16 +60,14 @@ namespace Kernel
struct Cell
{
TerminalDriver::Color foreground;
TerminalDriver::Color background;
TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color background { TerminalColor::BLACK };
uint32_t codepoint { ' ' };
};
private:
BAN::String m_name;
BAN::RefPtr<TerminalDriver> m_terminal_driver;
State m_state { State::Normal };
AnsiState m_ansi_state { };
UTF8State m_utf8_state { };
@ -94,11 +84,11 @@ namespace Kernel
uint32_t m_column { 0 };
Cell* m_buffer { nullptr };
const Palette& m_palette;
TerminalDriver::Color m_foreground;
TerminalDriver::Color m_background;
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color m_background { TerminalColor::BLACK };
bool m_colors_inverted { false };
BAN::RefPtr<TerminalDriver> m_terminal_driver;
};
}

View File

@ -104,7 +104,7 @@ namespace Debug
{
if (!isprint(ch))
ch = '?';
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::WHITE, TerminalColor::BLACK);
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
col++;
if (col >= g_terminal_driver->width())
@ -121,9 +121,9 @@ namespace Debug
{
for (uint32_t i = col; i < g_terminal_driver->width(); i++)
{
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::WHITE, TerminalColor::BLACK);
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
if (row + 1 < g_terminal_driver->height())
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::WHITE, TerminalColor::BLACK);
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
}
}
}

View File

@ -360,7 +360,7 @@ namespace Kernel
[&x, y](char ch)
{
if (x < g_terminal_driver->width() && y < g_terminal_driver->height())
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::WHITE, TerminalColor::BLACK);
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
};
BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000);

View File

@ -3,38 +3,15 @@
namespace Kernel
{
static consteval TerminalDriver::Palette default_palette()
{
TerminalDriver::Palette palette;
palette[ 0] = 0x000000;
palette[ 1] = 0xFF0000;
palette[ 2] = 0x00FF00;
palette[ 3] = 0xFFFF00;
palette[ 4] = 0x0000FF;
palette[ 5] = 0xFF00FF;
palette[ 6] = 0x00FFFF;
palette[ 7] = 0xBFBFBF;
palette[ 8] = 0x3F3F3F;
palette[ 9] = 0xFF7F7F;
palette[10] = 0x7FFF7F;
palette[11] = 0xFFFF7F;
palette[12] = 0x7F7FFF;
palette[13] = 0xFF7FFF;
palette[14] = 0x7FFFFF;
palette[15] = 0xFFFFFF;
return palette;
}
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
{
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device, default_palette());
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
if (driver_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
driver->set_cursor_position(0, 0);
driver->clear(driver->m_palette[0]);
driver->clear(TerminalColor::BLACK);
return driver;
}
@ -83,9 +60,6 @@ namespace Kernel
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
m_framebuffer_device->set_pixel(x, y, color.rgb);
m_framebuffer_device->sync_pixels_full();
if (m_cursor_shown)
show_cursor(false);
}
void FramebufferTerminalDriver::read_cursor()
@ -104,11 +78,6 @@ namespace Kernel
void FramebufferTerminalDriver::show_cursor(bool use_data)
{
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (m_cursor_x == width())
return;
if (!use_data)
read_cursor();

View File

@ -85,19 +85,16 @@ namespace Kernel
return BAN::Error::from_errno(ENODEV);
}
bool PseudoTerminalMaster::putchar(uint8_t ch)
void PseudoTerminalMaster::putchar(uint8_t ch)
{
SpinLockGuard _(m_buffer_lock);
if (m_buffer_size >= m_buffer->size())
return false;
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
m_buffer_size++;
m_buffer_blocker.unblock();
return true;
if (m_buffer_size < m_buffer->size())
m_buffer_size++;
else
m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
}
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
@ -169,11 +166,10 @@ namespace Kernel
(void)write_impl(0, BAN::ConstByteSpan::from(message));
}
bool PseudoTerminalSlave::putchar_impl(uint8_t ch)
void PseudoTerminalSlave::putchar_impl(uint8_t ch)
{
if (auto master = m_master.lock())
return master->putchar(ch);
return false;
master->putchar(ch);
}
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)

View File

@ -258,10 +258,9 @@ namespace Kernel
return m_serial.height();
}
bool SerialTTY::putchar_impl(uint8_t ch)
void SerialTTY::putchar_impl(uint8_t ch)
{
m_serial.putchar(ch);
return true;
}
}

View File

@ -327,12 +327,11 @@ namespace Kernel
}
}
bool TTY::putchar(uint8_t ch)
void TTY::putchar(uint8_t ch)
{
SpinLockGuard _(m_write_lock);
if (m_tty_ctrl.draw_graphics)
return putchar_impl(ch);
return true;
putchar_impl(ch);
}
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
@ -366,12 +365,10 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
{
SpinLockGuard _(m_write_lock);
size_t written = 0;
for (; written < buffer.size(); written++)
if (!putchar(buffer[written]))
break;
for (size_t i = 0; i < buffer.size(); i++)
putchar(buffer[i]);
update_cursor();
return written;
return buffer.size();
}
void TTY::putchar_current(uint8_t ch)

View File

@ -7,39 +7,36 @@
namespace Kernel
{
static consteval TerminalDriver::Palette default_palette()
{
TerminalDriver::Palette palette;
palette[ 0] = 0x000000;
palette[ 1] = 0x0000AA;
palette[ 2] = 0x00AA00;
palette[ 3] = 0x00AAAA;
palette[ 4] = 0xAA0000;
palette[ 5] = 0xAA00AA;
palette[ 6] = 0xAA5500;
palette[ 7] = 0xAAAAAA;
palette[ 8] = 0x555555;
palette[ 9] = 0x5555FF;
palette[10] = 0x55FF55;
palette[11] = 0x55FFFF;
palette[12] = 0xFF5555;
palette[13] = 0xFF55FF;
palette[14] = 0xFFFF55;
palette[15] = 0xFFFFFF;
return palette;
}
static constexpr TerminalDriver::Color s_palette[] {
TerminalColor::BLACK,
TerminalColor::BLUE,
TerminalColor::GREEN,
TerminalColor::CYAN,
TerminalColor::RED,
TerminalColor::MAGENTA,
TerminalColor::YELLOW,
TerminalColor::WHITE,
TerminalColor::BRIGHT_BLACK,
TerminalColor::BRIGHT_BLUE,
TerminalColor::BRIGHT_GREEN,
TerminalColor::BRIGHT_CYAN,
TerminalColor::BRIGHT_RED,
TerminalColor::BRIGHT_MAGENTA,
TerminalColor::BRIGHT_YELLOW,
TerminalColor::BRIGHT_WHITE,
};
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
{
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
uint8_t closest = 0;
static_assert(default_palette().size() == 16);
static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
for (size_t i = 0; i < 16; i++)
{
const auto rdiff = color.red() - default_palette()[i].red();
const auto gdiff = color.green() - default_palette()[i].green();
const auto bdiff = color.blue() - default_palette()[i].blue();
const auto rdiff = color.red() - s_palette[i].red();
const auto gdiff = color.green() - s_palette[i].green();
const auto bdiff = color.blue() - s_palette[i].blue();
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
if (diff >= min_diff)
continue;
@ -59,8 +56,7 @@ namespace Kernel
g_boot_info.framebuffer.address,
g_boot_info.framebuffer.width,
g_boot_info.framebuffer.height,
g_boot_info.framebuffer.pitch,
default_palette()
g_boot_info.framebuffer.pitch
);
if (driver_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
@ -87,7 +83,7 @@ namespace Kernel
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
set_cursor_position(0, 0);
clear(m_palette[0]);
clear(TerminalColor::BLACK);
return {};
}
@ -118,7 +114,7 @@ namespace Kernel
{
for (uint32_t y = 0; y < m_height; y++)
for (uint32_t x = 0; x < m_width; x++)
putchar_at(' ', x, y, color, color);
putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
}
void TextModeTerminalDriver::set_cursor_shown(bool shown)
@ -140,10 +136,6 @@ namespace Kernel
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
{
// NOTE: cursor is allowed to be on width as scrolling only
// happens after character gets printed to next line
if (x == m_width)
return;
const uint16_t pos = y * m_width + x;
IO::outb(0x3D4, 0x0F);
IO::outb(0x3D5, pos & 0xFF);

View File

@ -39,9 +39,6 @@ namespace Kernel
: TTY(0600, 0, 0)
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
, m_terminal_driver(driver)
, m_palette(driver->palette())
, m_foreground(m_palette[15])
, m_background(m_palette[0])
{
m_width = m_terminal_driver->width();
m_height = m_terminal_driver->height();
@ -98,11 +95,10 @@ namespace Kernel
void VirtualTTY::reset_ansi()
{
ASSERT(m_write_lock.current_processor_has_lock());
m_ansi_state = {
.nums = { -1, -1, -1, -1, -1 },
.index = 0,
.question = false,
};
m_ansi_state.index = 0;
m_ansi_state.nums[0] = -1;
m_ansi_state.nums[1] = -1;
m_ansi_state.question = false;
m_state = State::Normal;
}
@ -112,76 +108,64 @@ namespace Kernel
switch (ch)
{
case 0:
m_foreground = m_palette[15];
m_background = m_palette[0];
m_foreground = TerminalColor::BRIGHT_WHITE;
m_background = TerminalColor::BLACK;
m_colors_inverted = false;
break;
case 7: m_colors_inverted = true; break;
case 27: m_colors_inverted = false; break;
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
m_foreground = m_palette[ch - 30];
break;
case 30: m_foreground = TerminalColor::BLACK; break;
case 31: m_foreground = TerminalColor::RED; break;
case 32: m_foreground = TerminalColor::GREEN; break;
case 33: m_foreground = TerminalColor::YELLOW; break;
case 34: m_foreground = TerminalColor::BLUE; break;
case 35: m_foreground = TerminalColor::MAGENTA; break;
case 36: m_foreground = TerminalColor::CYAN; break;
case 37: m_foreground = TerminalColor::WHITE; break;
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
m_background = m_palette[ch - 40];
break;
case 40: m_background = TerminalColor::BLACK; break;
case 41: m_background = TerminalColor::RED; break;
case 42: m_background = TerminalColor::GREEN; break;
case 43: m_background = TerminalColor::YELLOW; break;
case 44: m_background = TerminalColor::BLUE; break;
case 45: m_background = TerminalColor::MAGENTA; break;
case 46: m_background = TerminalColor::CYAN; break;
case 47: m_background = TerminalColor::WHITE; break;
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
m_foreground = m_palette[ch - 90 + 8];
break;
case 90: m_foreground = TerminalColor::BRIGHT_BLACK; break;
case 91: m_foreground = TerminalColor::BRIGHT_RED; break;
case 92: m_foreground = TerminalColor::BRIGHT_GREEN; break;
case 93: m_foreground = TerminalColor::BRIGHT_YELLOW; break;
case 94: m_foreground = TerminalColor::BRIGHT_BLUE; break;
case 95: m_foreground = TerminalColor::BRIGHT_MAGENTA; break;
case 96: m_foreground = TerminalColor::BRIGHT_CYAN; break;
case 97: m_foreground = TerminalColor::BRIGHT_WHITE; break;
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107:
m_background = m_palette[ch - 100 + 8];
break;
case 100: m_background = TerminalColor::BRIGHT_BLACK; break;
case 101: m_background = TerminalColor::BRIGHT_RED; break;
case 102: m_background = TerminalColor::BRIGHT_GREEN; break;
case 103: m_background = TerminalColor::BRIGHT_YELLOW; break;
case 104: m_background = TerminalColor::BRIGHT_BLUE; break;
case 105: m_background = TerminalColor::BRIGHT_MAGENTA; break;
case 106: m_background = TerminalColor::BRIGHT_CYAN; break;
case 107: m_background = TerminalColor::BRIGHT_WHITE; break;
}
}
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)
{
constexpr size_t max_ansi_args = sizeof(m_ansi_state.nums) / sizeof(*m_ansi_state.nums);
ASSERT(m_write_lock.current_processor_has_lock());
switch (ch)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
if (m_ansi_state.index >= m_ansi_state.max_nums)
dwarnln("Only {} arguments supported with ANSI codes", m_ansi_state.max_nums);
if ((size_t)m_ansi_state.index >= max_ansi_args)
dwarnln("Only {} arguments supported with ANSI codes", max_ansi_args);
else
{
int32_t& val = m_ansi_state.nums[m_ansi_state.index];
@ -190,7 +174,7 @@ namespace Kernel
return;
}
case ';':
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, m_ansi_state.max_nums);
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args);
return;
case 'A': // Cursor Up
if (m_ansi_state.nums[0] == -1)
@ -322,22 +306,7 @@ namespace Kernel
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
return;
case 'm':
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++)
for (int i = 0; i <= m_ansi_state.index && i < static_cast<int>(max_ansi_args); i++)
handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0));
return reset_ansi();
case 's':
@ -432,29 +401,6 @@ namespace Kernel
m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background);
}
void VirtualTTY::scroll_if_needed()
{
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::putcodepoint(uint32_t codepoint)
{
ASSERT(m_write_lock.current_processor_has_lock());
@ -486,22 +432,40 @@ namespace Kernel
m_state = State::WaitingAnsiEscape;
break;
default:
if (m_column >= m_width)
{
m_column = 0;
m_row++;
}
scroll_if_needed();
putchar_at(codepoint, m_column, m_row);
m_last_graphic_char = codepoint;
m_column++;
break;
}
scroll_if_needed();
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--;
}
}
bool VirtualTTY::putchar_impl(uint8_t ch)
void VirtualTTY::putchar_impl(uint8_t ch)
{
ASSERT(m_write_lock.current_processor_has_lock());
@ -531,10 +495,10 @@ namespace Kernel
{
reset_ansi();
dprintln_if(DEBUG_VTTY, "invalid utf8");
return true;
return;
}
m_state = State::WaitingUTF8;
return true;
return;
case State::WaitingAnsiEscape:
if (ch == CSI)
m_state = State::WaitingAnsiCSI;
@ -543,21 +507,21 @@ namespace Kernel
reset_ansi();
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
}
return true;
return;
case State::WaitingAnsiCSI:
handle_ansi_csi(ch);
return true;
return;
case State::WaitingUTF8:
if ((ch & 0xC0) != 0x80)
{
m_state = State::Normal;
dprintln_if(DEBUG_VTTY, "invalid utf8");
return true;
return;
}
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
m_utf8_state.bytes_missing--;
if (m_utf8_state.bytes_missing)
return true;
return;
m_state = State::Normal;
codepoint = m_utf8_state.codepoint;
break;
@ -566,7 +530,6 @@ namespace Kernel
}
putcodepoint(codepoint);
return true;
}
void VirtualTTY::update_cursor()

View File

@ -185,8 +185,6 @@ void Terminal::run()
void Terminal::hide_cursor()
{
if (m_cursor.x == cols())
return;
const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++)
@ -197,8 +195,6 @@ void Terminal::hide_cursor()
void Terminal::show_cursor()
{
if (m_cursor.x == cols())
return;
const uint32_t cursor_base_x = m_cursor.x * m_font.width();
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
for (uint32_t y = 0; y < m_font.height(); y++)
@ -325,42 +321,6 @@ void Terminal::handle_sgr(int32_t value)
}
}
BAN::Optional<uint32_t> Terminal::get_8bit_color()
{
ASSERT(m_csi_info.fields[1] == 5);
if (m_csi_info.fields[2] < 1)
return {};
const uint8_t code = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
if (code < 8)
return s_colors_dark[code];
if (code < 16)
return s_colors_bright[code - 8];
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 b | (g << 8) | (r << 16) | (0xCC << 24);
}
const uint8_t gray = (code - 232) * 10 + 8;
return gray | (gray << 8) | (gray << 16) | (0xCC << 24);
}
BAN::Optional<uint32_t> Terminal::get_24bit_color()
{
ASSERT(m_csi_info.fields[1] == 2);
if (m_csi_info.fields[2] < 1) return {};
if (m_csi_info.fields[3] < 1) return {};
if (m_csi_info.fields[4] < 1) return {};
const uint8_t r = BAN::Math::min(m_csi_info.fields[2], 256) - 1;
const uint8_t g = BAN::Math::min(m_csi_info.fields[3], 256) - 1;
const uint8_t b = BAN::Math::min(m_csi_info.fields[4], 256) - 1;
return b | (g << 8) | (r << 16) | (0xCC << 24);
}
Rectangle Terminal::handle_csi(char ch)
{
if (ch == ';')
@ -544,20 +504,6 @@ Rectangle Terminal::handle_csi(char ch)
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
break;
case 'm':
if (m_csi_info.fields[0] == 38 || m_csi_info.fields[0] == 48)
{
if (m_csi_info.fields[1] != 5 && m_csi_info.fields[1] != 2)
{
dprintln("unsupported ANSI SGR {}", m_csi_info.fields[1]);
break;
}
const auto color = (m_csi_info.fields[1] == 5)
? get_8bit_color()
: get_24bit_color();
if (color.has_value())
(m_csi_info.fields[0] == 38 ? m_fg_color : m_bg_color) = *color;
break;
}
for (size_t i = 0; i <= m_csi_info.index && i < m_csi_info.max_fields; i++)
handle_sgr(m_csi_info.fields[i]);
break;
@ -617,20 +563,6 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
break;
default:
{
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() };
}
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;
@ -648,6 +580,12 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
}
}
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;
@ -670,11 +608,10 @@ Rectangle Terminal::putchar(uint8_t ch)
return {};
}
m_state = State::CSI;
m_csi_info = {
.fields = { -1, -1, -1, -1, -1 },
.index = 0,
.question = false,
};
m_csi_info.index = 0;
m_csi_info.fields[0] = -1;
m_csi_info.fields[1] = -1;
m_csi_info.question = false;
return {};
}

View File

@ -41,9 +41,6 @@ private:
Rectangle putchar(uint8_t ch);
bool read_shell();
BAN::Optional<uint32_t> get_8bit_color();
BAN::Optional<uint32_t> get_24bit_color();
void hide_cursor();
void show_cursor();
@ -73,7 +70,7 @@ private:
struct CSIInfo
{
static constexpr size_t max_fields = 5;
static constexpr size_t max_fields = 2;
int32_t fields[max_fields];
size_t index;
bool question;