Compare commits
7 Commits
95a80bfe81
...
9f4cb5c4dd
Author | SHA1 | Date |
---|---|---|
|
9f4cb5c4dd | |
|
73f9de6635 | |
|
12b9c82086 | |
|
a8edb8870e | |
|
dabc3c6cc4 | |
|
cc7c1ad30d | |
|
4d840a8d9a |
|
@ -18,78 +18,78 @@ namespace BAN
|
||||||
using const_iterator = ConstIteratorSimple<T, Array>;
|
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array() = default;
|
constexpr Array() = default;
|
||||||
Array(const T&);
|
constexpr Array(const T&);
|
||||||
|
|
||||||
iterator begin() { return iterator(m_data); }
|
iterator begin() { return iterator(m_data); }
|
||||||
iterator end() { return iterator(m_data + size()); }
|
iterator end() { return iterator(m_data + size()); }
|
||||||
const_iterator begin() const { return const_iterator(m_data); }
|
const_iterator begin() const { return const_iterator(m_data); }
|
||||||
const_iterator end() const { return const_iterator(m_data + size()); }
|
const_iterator end() const { return const_iterator(m_data + size()); }
|
||||||
|
|
||||||
const T& operator[](size_type) const;
|
constexpr const T& operator[](size_type) const;
|
||||||
T& operator[](size_type);
|
constexpr T& operator[](size_type);
|
||||||
|
|
||||||
const T& back() const;
|
constexpr const T& back() const;
|
||||||
T& back();
|
constexpr T& back();
|
||||||
const T& front() const;
|
constexpr const T& front() const;
|
||||||
T& front();
|
constexpr T& front();
|
||||||
|
|
||||||
Span<T> span() { return Span(m_data, size()); }
|
Span<T> span() { return Span(m_data, size()); }
|
||||||
const Span<T> span() const { return Span(m_data, size()); }
|
const Span<T> span() const { return Span(m_data, size()); }
|
||||||
|
|
||||||
constexpr size_type size() const;
|
constexpr size_type size() const;
|
||||||
|
|
||||||
const T* data() const { return m_data; }
|
constexpr const T* data() const { return m_data; }
|
||||||
T* data() { return m_data; }
|
constexpr T* data() { return m_data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_data[S] {};
|
T m_data[S] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
Array<T, S>::Array(const T& value)
|
constexpr Array<T, S>::Array(const T& value)
|
||||||
{
|
{
|
||||||
for (size_type i = 0; i < S; i++)
|
for (size_type i = 0; i < S; i++)
|
||||||
m_data[i] = value;
|
m_data[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::operator[](size_type index) const
|
constexpr const T& Array<T, S>::operator[](size_type index) const
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::operator[](size_type index)
|
constexpr T& Array<T, S>::operator[](size_type index)
|
||||||
{
|
{
|
||||||
ASSERT(index < S);
|
ASSERT(index < S);
|
||||||
return m_data[index];
|
return m_data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::back() const
|
constexpr const T& Array<T, S>::back() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::back()
|
constexpr T& Array<T, S>::back()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[S - 1];
|
return m_data[S - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
const T& Array<T, S>::front() const
|
constexpr const T& Array<T, S>::front() const
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t S>
|
template<typename T, size_t S>
|
||||||
T& Array<T, S>::front()
|
constexpr T& Array<T, S>::front()
|
||||||
{
|
{
|
||||||
ASSERT(S != 0);
|
ASSERT(S != 0);
|
||||||
return m_data[0];
|
return m_data[0];
|
||||||
|
|
|
@ -27,9 +27,10 @@ namespace Kernel
|
||||||
const LibFont::Font& font() const override { return m_font; };
|
const LibFont::Font& font() const override { return m_font; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
FramebufferTerminalDriver(BAN::RefPtr<FramebufferDevice> framebuffer_device, const Palette& palette)
|
||||||
: m_framebuffer_device(framebuffer_device)
|
: TerminalDriver(palette)
|
||||||
{ }
|
, m_framebuffer_device(framebuffer_device)
|
||||||
|
{}
|
||||||
|
|
||||||
void read_cursor();
|
void read_cursor();
|
||||||
void show_cursor(bool use_data);
|
void show_cursor(bool use_data);
|
||||||
|
@ -42,7 +43,7 @@ namespace Kernel
|
||||||
uint32_t m_cursor_y { 0 };
|
uint32_t m_cursor_y { 0 };
|
||||||
bool m_cursor_shown { true };
|
bool m_cursor_shown { true };
|
||||||
BAN::Vector<uint32_t> m_cursor_data;
|
BAN::Vector<uint32_t> m_cursor_data;
|
||||||
static constexpr Color m_cursor_color = TerminalColor::BRIGHT_WHITE;
|
static constexpr Color m_cursor_color = TerminalColor::WHITE;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::String> ptsname();
|
BAN::ErrorOr<BAN::String> ptsname();
|
||||||
|
|
||||||
void putchar(uint8_t ch);
|
bool putchar(uint8_t ch);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
@ -61,7 +61,7 @@ namespace Kernel
|
||||||
void clear() override;
|
void clear() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void putchar_impl(uint8_t ch) override;
|
bool putchar_impl(uint8_t ch) override;
|
||||||
|
|
||||||
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual BAN::StringView name() const override { return m_name; }
|
virtual BAN::StringView name() const override { return m_name; }
|
||||||
virtual void putchar_impl(uint8_t) override;
|
virtual bool putchar_impl(uint8_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SerialTTY(Serial);
|
SerialTTY(Serial);
|
||||||
|
|
|
@ -58,14 +58,14 @@ namespace Kernel
|
||||||
protected:
|
protected:
|
||||||
TTY(mode_t mode, uid_t uid, gid_t gid);
|
TTY(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
virtual void putchar_impl(uint8_t ch) = 0;
|
virtual bool putchar_impl(uint8_t ch) = 0;
|
||||||
virtual void update_cursor() {}
|
virtual void update_cursor() {}
|
||||||
|
|
||||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void putchar(uint8_t ch);
|
bool putchar(uint8_t ch);
|
||||||
void do_backspace();
|
void do_backspace();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -12,20 +12,28 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
struct Color
|
struct Color
|
||||||
{
|
{
|
||||||
|
constexpr Color()
|
||||||
|
: rgb(0)
|
||||||
|
{ }
|
||||||
constexpr Color(uint32_t rgb)
|
constexpr Color(uint32_t rgb)
|
||||||
: rgb(rgb)
|
: rgb(rgb)
|
||||||
{ }
|
{ }
|
||||||
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
|
constexpr Color(uint8_t r, uint8_t g, uint8_t b)
|
||||||
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
|
: rgb(((uint32_t)r << 16) | ((uint32_t)g << 8) | b)
|
||||||
{ }
|
{ }
|
||||||
uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
constexpr uint8_t red() const { return (rgb >> 0x10) & 0xFF; }
|
||||||
uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
constexpr uint8_t green() const { return (rgb >> 0x08) & 0xFF; }
|
||||||
uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
constexpr uint8_t blue() const { return (rgb >> 0x00) & 0xFF; }
|
||||||
uint32_t rgb;
|
uint32_t rgb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Palette = BAN::Array<Color, 16>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<void> initialize_from_boot_info();
|
static BAN::ErrorOr<void> initialize_from_boot_info();
|
||||||
|
TerminalDriver(const Palette& palette)
|
||||||
|
: m_palette(palette)
|
||||||
|
{}
|
||||||
virtual ~TerminalDriver() {}
|
virtual ~TerminalDriver() {}
|
||||||
virtual uint32_t width() const = 0;
|
virtual uint32_t width() const = 0;
|
||||||
virtual uint32_t height() const = 0;
|
virtual uint32_t height() const = 0;
|
||||||
|
@ -40,29 +48,19 @@ namespace Kernel
|
||||||
virtual bool has_font() const { return false; }
|
virtual bool has_font() const { return false; }
|
||||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
||||||
virtual const LibFont::Font& font() const { ASSERT_NOT_REACHED(); }
|
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;
|
extern BAN::RefPtr<TerminalDriver> g_terminal_driver;
|
||||||
|
|
||||||
namespace TerminalColor
|
namespace TerminalColor
|
||||||
{
|
{
|
||||||
static constexpr TerminalDriver::Color BLACK = 0x000000;
|
constexpr TerminalDriver::Color BLACK = 0x000000;
|
||||||
static constexpr TerminalDriver::Color RED = 0xFF0000;
|
constexpr TerminalDriver::Color WHITE = 0xFFFFFF;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,9 @@ namespace Kernel
|
||||||
void set_cursor_position(uint32_t, uint32_t) override;
|
void set_cursor_position(uint32_t, uint32_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch)
|
TextModeTerminalDriver(paddr_t paddr, uint32_t width, uint32_t height, uint32_t pitch, const Palette& palette)
|
||||||
: m_paddr(paddr)
|
: TerminalDriver(palette)
|
||||||
|
, m_paddr(paddr)
|
||||||
, m_width(width)
|
, m_width(width)
|
||||||
, m_height(height)
|
, m_height(height)
|
||||||
, m_pitch(pitch)
|
, m_pitch(pitch)
|
||||||
|
@ -36,7 +37,7 @@ namespace Kernel
|
||||||
const uint32_t m_height;
|
const uint32_t m_height;
|
||||||
const uint32_t m_pitch;
|
const uint32_t m_pitch;
|
||||||
vaddr_t m_vaddr { 0 };
|
vaddr_t m_vaddr { 0 };
|
||||||
static constexpr Color s_cursor_color = TerminalColor::BRIGHT_WHITE;
|
static constexpr Color s_cursor_color = TerminalColor::WHITE;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ namespace Kernel
|
||||||
|
|
||||||
class VirtualTTY : public TTY
|
class VirtualTTY : public TTY
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using Palette = TerminalDriver::Palette;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
|
static BAN::ErrorOr<BAN::RefPtr<VirtualTTY>> create(BAN::RefPtr<TerminalDriver>);
|
||||||
|
|
||||||
|
@ -23,7 +26,7 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual BAN::StringView name() const override { return m_name; }
|
virtual BAN::StringView name() const override { return m_name; }
|
||||||
virtual void putchar_impl(uint8_t ch) override;
|
virtual bool putchar_impl(uint8_t ch) override;
|
||||||
void update_cursor() override;
|
void update_cursor() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -35,6 +38,7 @@ namespace Kernel
|
||||||
void putcodepoint(uint32_t codepoint);
|
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 scroll_if_needed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class State
|
enum class State
|
||||||
|
@ -47,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 };
|
||||||
|
@ -60,14 +68,16 @@ namespace Kernel
|
||||||
|
|
||||||
struct Cell
|
struct Cell
|
||||||
{
|
{
|
||||||
TerminalDriver::Color foreground { TerminalColor::BRIGHT_WHITE };
|
TerminalDriver::Color foreground;
|
||||||
TerminalDriver::Color background { TerminalColor::BLACK };
|
TerminalDriver::Color background;
|
||||||
uint32_t codepoint { ' ' };
|
uint32_t codepoint { ' ' };
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::String m_name;
|
BAN::String m_name;
|
||||||
|
|
||||||
|
BAN::RefPtr<TerminalDriver> m_terminal_driver;
|
||||||
|
|
||||||
State m_state { State::Normal };
|
State m_state { State::Normal };
|
||||||
AnsiState m_ansi_state { };
|
AnsiState m_ansi_state { };
|
||||||
UTF8State m_utf8_state { };
|
UTF8State m_utf8_state { };
|
||||||
|
@ -84,11 +94,11 @@ namespace Kernel
|
||||||
uint32_t m_column { 0 };
|
uint32_t m_column { 0 };
|
||||||
Cell* m_buffer { nullptr };
|
Cell* m_buffer { nullptr };
|
||||||
|
|
||||||
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
|
const Palette& m_palette;
|
||||||
TerminalDriver::Color m_background { TerminalColor::BLACK };
|
|
||||||
bool m_colors_inverted { false };
|
|
||||||
|
|
||||||
BAN::RefPtr<TerminalDriver> m_terminal_driver;
|
TerminalDriver::Color m_foreground;
|
||||||
|
TerminalDriver::Color m_background;
|
||||||
|
bool m_colors_inverted { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ namespace Debug
|
||||||
{
|
{
|
||||||
if (!isprint(ch))
|
if (!isprint(ch))
|
||||||
ch = '?';
|
ch = '?';
|
||||||
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
g_terminal_driver->putchar_at(ch, col, row, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||||
|
|
||||||
col++;
|
col++;
|
||||||
if (col >= g_terminal_driver->width())
|
if (col >= g_terminal_driver->width())
|
||||||
|
@ -121,9 +121,9 @@ namespace Debug
|
||||||
{
|
{
|
||||||
for (uint32_t i = col; i < g_terminal_driver->width(); i++)
|
for (uint32_t i = col; i < g_terminal_driver->width(); i++)
|
||||||
{
|
{
|
||||||
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
g_terminal_driver->putchar_at(' ', i, row, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||||
if (row + 1 < g_terminal_driver->height())
|
if (row + 1 < g_terminal_driver->height())
|
||||||
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
g_terminal_driver->putchar_at(' ', i, row + 1, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ namespace Kernel
|
||||||
[&x, y](char ch)
|
[&x, y](char ch)
|
||||||
{
|
{
|
||||||
if (x < g_terminal_driver->width() && y < g_terminal_driver->height())
|
if (x < g_terminal_driver->width() && y < g_terminal_driver->height())
|
||||||
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::BRIGHT_WHITE, TerminalColor::BLACK);
|
g_terminal_driver->putchar_at(ch, x++, y, TerminalColor::WHITE, TerminalColor::BLACK);
|
||||||
};
|
};
|
||||||
|
|
||||||
BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000);
|
BAN::Formatter::print(proc_putc, "CPU { 2}: { 3}.{3}%", current_id(), load_x1000 / 1000, load_x1000 % 1000);
|
||||||
|
|
|
@ -3,15 +3,38 @@
|
||||||
namespace Kernel
|
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)
|
BAN::ErrorOr<BAN::RefPtr<FramebufferTerminalDriver>> FramebufferTerminalDriver::create(BAN::RefPtr<FramebufferDevice> framebuffer_device)
|
||||||
{
|
{
|
||||||
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device);
|
auto* driver_ptr = new FramebufferTerminalDriver(framebuffer_device, default_palette());
|
||||||
if (driver_ptr == nullptr)
|
if (driver_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
|
auto driver = BAN::RefPtr<FramebufferTerminalDriver>::adopt(driver_ptr);
|
||||||
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
|
TRY(driver->set_font(BAN::move(TRY(LibFont::Font::prefs()))));
|
||||||
driver->set_cursor_position(0, 0);
|
driver->set_cursor_position(0, 0);
|
||||||
driver->clear(TerminalColor::BLACK);
|
driver->clear(driver->m_palette[0]);
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +83,9 @@ namespace Kernel
|
||||||
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
|
for (uint32_t x = 0; x < m_framebuffer_device->width(); x++)
|
||||||
m_framebuffer_device->set_pixel(x, y, color.rgb);
|
m_framebuffer_device->set_pixel(x, y, color.rgb);
|
||||||
m_framebuffer_device->sync_pixels_full();
|
m_framebuffer_device->sync_pixels_full();
|
||||||
|
|
||||||
|
if (m_cursor_shown)
|
||||||
|
show_cursor(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramebufferTerminalDriver::read_cursor()
|
void FramebufferTerminalDriver::read_cursor()
|
||||||
|
@ -78,6 +104,11 @@ namespace Kernel
|
||||||
|
|
||||||
void FramebufferTerminalDriver::show_cursor(bool use_data)
|
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)
|
if (!use_data)
|
||||||
read_cursor();
|
read_cursor();
|
||||||
|
|
||||||
|
|
|
@ -85,16 +85,19 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(ENODEV);
|
return BAN::Error::from_errno(ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoTerminalMaster::putchar(uint8_t ch)
|
bool PseudoTerminalMaster::putchar(uint8_t ch)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_buffer_lock);
|
SpinLockGuard _(m_buffer_lock);
|
||||||
|
|
||||||
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
|
if (m_buffer_size >= m_buffer->size())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (m_buffer_size < m_buffer->size())
|
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
|
||||||
m_buffer_size++;
|
m_buffer_size++;
|
||||||
else
|
|
||||||
m_buffer_tail = (m_buffer_tail + 1) % m_buffer->size();
|
m_buffer_blocker.unblock();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
|
BAN::ErrorOr<size_t> PseudoTerminalMaster::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
@ -166,10 +169,11 @@ namespace Kernel
|
||||||
(void)write_impl(0, BAN::ConstByteSpan::from(message));
|
(void)write_impl(0, BAN::ConstByteSpan::from(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoTerminalSlave::putchar_impl(uint8_t ch)
|
bool PseudoTerminalSlave::putchar_impl(uint8_t ch)
|
||||||
{
|
{
|
||||||
if (auto master = m_master.lock())
|
if (auto master = m_master.lock())
|
||||||
master->putchar(ch);
|
return master->putchar(ch);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)
|
BAN::ErrorOr<long> PseudoTerminalSlave::ioctl_impl(int request, void* argument)
|
||||||
|
|
|
@ -258,9 +258,10 @@ namespace Kernel
|
||||||
return m_serial.height();
|
return m_serial.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialTTY::putchar_impl(uint8_t ch)
|
bool SerialTTY::putchar_impl(uint8_t ch)
|
||||||
{
|
{
|
||||||
m_serial.putchar(ch);
|
m_serial.putchar(ch);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,11 +327,12 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::putchar(uint8_t ch)
|
bool TTY::putchar(uint8_t ch)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_write_lock);
|
SpinLockGuard _(m_write_lock);
|
||||||
if (m_tty_ctrl.draw_graphics)
|
if (m_tty_ctrl.draw_graphics)
|
||||||
putchar_impl(ch);
|
return putchar_impl(ch);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
|
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
@ -365,10 +366,12 @@ namespace Kernel
|
||||||
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
|
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_write_lock);
|
SpinLockGuard _(m_write_lock);
|
||||||
for (size_t i = 0; i < buffer.size(); i++)
|
size_t written = 0;
|
||||||
putchar(buffer[i]);
|
for (; written < buffer.size(); written++)
|
||||||
|
if (!putchar(buffer[written]))
|
||||||
|
break;
|
||||||
update_cursor();
|
update_cursor();
|
||||||
return buffer.size();
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::putchar_current(uint8_t ch)
|
void TTY::putchar_current(uint8_t ch)
|
||||||
|
|
|
@ -7,36 +7,39 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr TerminalDriver::Color s_palette[] {
|
static consteval TerminalDriver::Palette default_palette()
|
||||||
TerminalColor::BLACK,
|
{
|
||||||
TerminalColor::BLUE,
|
TerminalDriver::Palette palette;
|
||||||
TerminalColor::GREEN,
|
palette[ 0] = 0x000000;
|
||||||
TerminalColor::CYAN,
|
palette[ 1] = 0x0000AA;
|
||||||
TerminalColor::RED,
|
palette[ 2] = 0x00AA00;
|
||||||
TerminalColor::MAGENTA,
|
palette[ 3] = 0x00AAAA;
|
||||||
TerminalColor::YELLOW,
|
palette[ 4] = 0xAA0000;
|
||||||
TerminalColor::WHITE,
|
palette[ 5] = 0xAA00AA;
|
||||||
TerminalColor::BRIGHT_BLACK,
|
palette[ 6] = 0xAA5500;
|
||||||
TerminalColor::BRIGHT_BLUE,
|
palette[ 7] = 0xAAAAAA;
|
||||||
TerminalColor::BRIGHT_GREEN,
|
palette[ 8] = 0x555555;
|
||||||
TerminalColor::BRIGHT_CYAN,
|
palette[ 9] = 0x5555FF;
|
||||||
TerminalColor::BRIGHT_RED,
|
palette[10] = 0x55FF55;
|
||||||
TerminalColor::BRIGHT_MAGENTA,
|
palette[11] = 0x55FFFF;
|
||||||
TerminalColor::BRIGHT_YELLOW,
|
palette[12] = 0xFF5555;
|
||||||
TerminalColor::BRIGHT_WHITE,
|
palette[13] = 0xFF55FF;
|
||||||
};
|
palette[14] = 0xFFFF55;
|
||||||
|
palette[15] = 0xFFFFFF;
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
|
static constexpr uint8_t color_to_text_mode_color(TerminalDriver::Color color)
|
||||||
{
|
{
|
||||||
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
|
uint32_t min_diff = BAN::numeric_limits<uint32_t>::max();
|
||||||
uint8_t closest = 0;
|
uint8_t closest = 0;
|
||||||
|
|
||||||
static_assert(sizeof(s_palette) / sizeof(*s_palette) == 16);
|
static_assert(default_palette().size() == 16);
|
||||||
for (size_t i = 0; i < 16; i++)
|
for (size_t i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
const auto rdiff = color.red() - s_palette[i].red();
|
const auto rdiff = color.red() - default_palette()[i].red();
|
||||||
const auto gdiff = color.green() - s_palette[i].green();
|
const auto gdiff = color.green() - default_palette()[i].green();
|
||||||
const auto bdiff = color.blue() - s_palette[i].blue();
|
const auto bdiff = color.blue() - default_palette()[i].blue();
|
||||||
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
|
const uint32_t diff = rdiff*rdiff + gdiff*gdiff + bdiff*bdiff;
|
||||||
if (diff >= min_diff)
|
if (diff >= min_diff)
|
||||||
continue;
|
continue;
|
||||||
|
@ -56,7 +59,8 @@ namespace Kernel
|
||||||
g_boot_info.framebuffer.address,
|
g_boot_info.framebuffer.address,
|
||||||
g_boot_info.framebuffer.width,
|
g_boot_info.framebuffer.width,
|
||||||
g_boot_info.framebuffer.height,
|
g_boot_info.framebuffer.height,
|
||||||
g_boot_info.framebuffer.pitch
|
g_boot_info.framebuffer.pitch,
|
||||||
|
default_palette()
|
||||||
);
|
);
|
||||||
if (driver_ptr == nullptr)
|
if (driver_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
@ -83,7 +87,7 @@ namespace Kernel
|
||||||
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
|
m_vaddr = vaddr + (m_paddr % PAGE_SIZE);
|
||||||
|
|
||||||
set_cursor_position(0, 0);
|
set_cursor_position(0, 0);
|
||||||
clear(TerminalColor::BLACK);
|
clear(m_palette[0]);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -114,7 +118,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
for (uint32_t y = 0; y < m_height; y++)
|
for (uint32_t y = 0; y < m_height; y++)
|
||||||
for (uint32_t x = 0; x < m_width; x++)
|
for (uint32_t x = 0; x < m_width; x++)
|
||||||
putchar_at(' ', x, y, TerminalColor::BRIGHT_WHITE, color);
|
putchar_at(' ', x, y, color, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextModeTerminalDriver::set_cursor_shown(bool shown)
|
void TextModeTerminalDriver::set_cursor_shown(bool shown)
|
||||||
|
@ -136,6 +140,10 @@ namespace Kernel
|
||||||
|
|
||||||
void TextModeTerminalDriver::set_cursor_position(uint32_t x, uint32_t y)
|
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;
|
const uint16_t pos = y * m_width + x;
|
||||||
IO::outb(0x3D4, 0x0F);
|
IO::outb(0x3D4, 0x0F);
|
||||||
IO::outb(0x3D5, pos & 0xFF);
|
IO::outb(0x3D5, pos & 0xFF);
|
||||||
|
|
|
@ -39,6 +39,9 @@ namespace Kernel
|
||||||
: TTY(0600, 0, 0)
|
: TTY(0600, 0, 0)
|
||||||
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
|
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
|
||||||
, m_terminal_driver(driver)
|
, 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_width = m_terminal_driver->width();
|
||||||
m_height = m_terminal_driver->height();
|
m_height = m_terminal_driver->height();
|
||||||
|
@ -95,10 +98,11 @@ namespace Kernel
|
||||||
void VirtualTTY::reset_ansi()
|
void VirtualTTY::reset_ansi()
|
||||||
{
|
{
|
||||||
ASSERT(m_write_lock.current_processor_has_lock());
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
m_ansi_state.index = 0;
|
m_ansi_state = {
|
||||||
m_ansi_state.nums[0] = -1;
|
.nums = { -1, -1, -1, -1, -1 },
|
||||||
m_ansi_state.nums[1] = -1;
|
.index = 0,
|
||||||
m_ansi_state.question = false;
|
.question = false,
|
||||||
|
};
|
||||||
m_state = State::Normal;
|
m_state = State::Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,64 +112,76 @@ namespace Kernel
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_foreground = TerminalColor::BRIGHT_WHITE;
|
m_foreground = m_palette[15];
|
||||||
m_background = TerminalColor::BLACK;
|
m_background = m_palette[0];
|
||||||
m_colors_inverted = false;
|
m_colors_inverted = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: m_colors_inverted = true; break;
|
case 7: m_colors_inverted = true; break;
|
||||||
case 27: m_colors_inverted = false; break;
|
case 27: m_colors_inverted = false; break;
|
||||||
|
|
||||||
case 30: m_foreground = TerminalColor::BLACK; break;
|
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||||
case 31: m_foreground = TerminalColor::RED; break;
|
m_foreground = m_palette[ch - 30];
|
||||||
case 32: m_foreground = TerminalColor::GREEN; break;
|
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: m_background = TerminalColor::BLACK; break;
|
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||||
case 41: m_background = TerminalColor::RED; break;
|
m_background = m_palette[ch - 40];
|
||||||
case 42: m_background = TerminalColor::GREEN; break;
|
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: m_foreground = TerminalColor::BRIGHT_BLACK; break;
|
case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97:
|
||||||
case 91: m_foreground = TerminalColor::BRIGHT_RED; break;
|
m_foreground = m_palette[ch - 90 + 8];
|
||||||
case 92: m_foreground = TerminalColor::BRIGHT_GREEN; break;
|
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: m_background = TerminalColor::BRIGHT_BLACK; break;
|
case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107:
|
||||||
case 101: m_background = TerminalColor::BRIGHT_RED; break;
|
m_background = m_palette[ch - 100 + 8];
|
||||||
case 102: m_background = TerminalColor::BRIGHT_GREEN; break;
|
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)
|
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];
|
||||||
|
@ -174,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)
|
||||||
|
@ -306,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':
|
||||||
|
@ -401,6 +432,29 @@ namespace Kernel
|
||||||
m_terminal_driver->putchar_at(codepoint, x, y, cell.foreground, cell.background);
|
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)
|
void VirtualTTY::putcodepoint(uint32_t codepoint)
|
||||||
{
|
{
|
||||||
ASSERT(m_write_lock.current_processor_has_lock());
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
|
@ -432,40 +486,22 @@ namespace Kernel
|
||||||
m_state = State::WaitingAnsiEscape;
|
m_state = State::WaitingAnsiEscape;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (m_column >= m_width)
|
||||||
|
{
|
||||||
|
m_column = 0;
|
||||||
|
m_row++;
|
||||||
|
}
|
||||||
|
scroll_if_needed();
|
||||||
putchar_at(codepoint, m_column, m_row);
|
putchar_at(codepoint, m_column, m_row);
|
||||||
m_last_graphic_char = codepoint;
|
m_last_graphic_char = codepoint;
|
||||||
m_column++;
|
m_column++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_column >= m_width)
|
scroll_if_needed();
|
||||||
{
|
|
||||||
m_column = 0;
|
|
||||||
m_row++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_row >= m_height)
|
bool VirtualTTY::putchar_impl(uint8_t ch)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
ASSERT(m_write_lock.current_processor_has_lock());
|
ASSERT(m_write_lock.current_processor_has_lock());
|
||||||
|
|
||||||
|
@ -495,10 +531,10 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
reset_ansi();
|
reset_ansi();
|
||||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
m_state = State::WaitingUTF8;
|
m_state = State::WaitingUTF8;
|
||||||
return;
|
return true;
|
||||||
case State::WaitingAnsiEscape:
|
case State::WaitingAnsiEscape:
|
||||||
if (ch == CSI)
|
if (ch == CSI)
|
||||||
m_state = State::WaitingAnsiCSI;
|
m_state = State::WaitingAnsiCSI;
|
||||||
|
@ -507,21 +543,21 @@ namespace Kernel
|
||||||
reset_ansi();
|
reset_ansi();
|
||||||
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
|
dprintln_if(DEBUG_VTTY, "unsupported byte after ansi escape {2H}", (uint8_t)ch);
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
case State::WaitingAnsiCSI:
|
case State::WaitingAnsiCSI:
|
||||||
handle_ansi_csi(ch);
|
handle_ansi_csi(ch);
|
||||||
return;
|
return true;
|
||||||
case State::WaitingUTF8:
|
case State::WaitingUTF8:
|
||||||
if ((ch & 0xC0) != 0x80)
|
if ((ch & 0xC0) != 0x80)
|
||||||
{
|
{
|
||||||
m_state = State::Normal;
|
m_state = State::Normal;
|
||||||
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
dprintln_if(DEBUG_VTTY, "invalid utf8");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
|
m_utf8_state.codepoint = (m_utf8_state.codepoint << 6) | (ch & 0x3F);
|
||||||
m_utf8_state.bytes_missing--;
|
m_utf8_state.bytes_missing--;
|
||||||
if (m_utf8_state.bytes_missing)
|
if (m_utf8_state.bytes_missing)
|
||||||
return;
|
return true;
|
||||||
m_state = State::Normal;
|
m_state = State::Normal;
|
||||||
codepoint = m_utf8_state.codepoint;
|
codepoint = m_utf8_state.codepoint;
|
||||||
break;
|
break;
|
||||||
|
@ -530,6 +566,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
putcodepoint(codepoint);
|
putcodepoint(codepoint);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualTTY::update_cursor()
|
void VirtualTTY::update_cursor()
|
||||||
|
|
|
@ -185,6 +185,8 @@ void Terminal::run()
|
||||||
|
|
||||||
void Terminal::hide_cursor()
|
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_x = m_cursor.x * m_font.width();
|
||||||
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
|
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
|
||||||
for (uint32_t y = 0; y < m_font.height(); y++)
|
for (uint32_t y = 0; y < m_font.height(); y++)
|
||||||
|
@ -195,6 +197,8 @@ void Terminal::hide_cursor()
|
||||||
|
|
||||||
void Terminal::show_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_x = m_cursor.x * m_font.width();
|
||||||
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
|
const uint32_t cursor_base_y = m_cursor.y * m_font.height();
|
||||||
for (uint32_t y = 0; y < m_font.height(); y++)
|
for (uint32_t y = 0; y < m_font.height(); y++)
|
||||||
|
@ -321,6 +325,42 @@ 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)
|
Rectangle Terminal::handle_csi(char ch)
|
||||||
{
|
{
|
||||||
if (ch == ';')
|
if (ch == ';')
|
||||||
|
@ -504,6 +544,20 @@ Rectangle Terminal::handle_csi(char ch)
|
||||||
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
m_cursor.y = BAN::Math::clamp<int32_t>(m_csi_info.fields[0], 1, rows()) - 1;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
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++)
|
for (size_t i = 0; i <= m_csi_info.index && i < m_csi_info.max_fields; i++)
|
||||||
handle_sgr(m_csi_info.fields[i]);
|
handle_sgr(m_csi_info.fields[i]);
|
||||||
break;
|
break;
|
||||||
|
@ -563,6 +617,20 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
|
||||||
break;
|
break;
|
||||||
default:
|
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_w = m_font.width();
|
||||||
const uint32_t cell_h = m_font.height();
|
const uint32_t cell_h = m_font.height();
|
||||||
const uint32_t cell_x = m_cursor.x * cell_w;
|
const uint32_t cell_x = m_cursor.x * cell_w;
|
||||||
|
@ -580,12 +648,6 @@ Rectangle Terminal::putcodepoint(uint32_t codepoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cursor.x >= cols())
|
|
||||||
{
|
|
||||||
m_cursor.x = 0;
|
|
||||||
m_cursor.y++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_cursor.y >= rows())
|
if (m_cursor.y >= rows())
|
||||||
{
|
{
|
||||||
const uint32_t scroll = m_cursor.y - rows() + 1;
|
const uint32_t scroll = m_cursor.y - rows() + 1;
|
||||||
|
@ -608,10 +670,11 @@ Rectangle Terminal::putchar(uint8_t ch)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
m_state = State::CSI;
|
m_state = State::CSI;
|
||||||
m_csi_info.index = 0;
|
m_csi_info = {
|
||||||
m_csi_info.fields[0] = -1;
|
.fields = { -1, -1, -1, -1, -1 },
|
||||||
m_csi_info.fields[1] = -1;
|
.index = 0,
|
||||||
m_csi_info.question = false;
|
.question = false,
|
||||||
|
};
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,9 @@ private:
|
||||||
Rectangle putchar(uint8_t ch);
|
Rectangle putchar(uint8_t ch);
|
||||||
bool read_shell();
|
bool read_shell();
|
||||||
|
|
||||||
|
BAN::Optional<uint32_t> get_8bit_color();
|
||||||
|
BAN::Optional<uint32_t> get_24bit_color();
|
||||||
|
|
||||||
void hide_cursor();
|
void hide_cursor();
|
||||||
void show_cursor();
|
void show_cursor();
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ private:
|
||||||
|
|
||||||
struct CSIInfo
|
struct CSIInfo
|
||||||
{
|
{
|
||||||
static constexpr size_t max_fields = 2;
|
static constexpr size_t max_fields = 5;
|
||||||
int32_t fields[max_fields];
|
int32_t fields[max_fields];
|
||||||
size_t index;
|
size_t index;
|
||||||
bool question;
|
bool question;
|
||||||
|
|
Loading…
Reference in New Issue