#include "x86_64/vga/text.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/vga/crtc.hpp" #include #include #include #include #include namespace teachos::vga::x86_64::text { using boot::x86_64::vga_buffer_pointer; namespace { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit buffer_offset = std::ptrdiff_t{}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; constexpr auto CURSOR_ENABLED_BIT = 5U; auto write_char(char code_point, attribute attribute) -> void { vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; }; } // namespace auto device::clear(attribute attribute) -> void { buffer_offset = 0; std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void { auto cursor_disable_byte = std::byte{!enabled} << CURSOR_ENABLED_BIT; crtc::address::write(crtc::registers::cursor_start); crtc::data::write(crtc::data::read() | cursor_disable_byte); } auto device::newline() -> void { auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) { auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; std::ranges::move(begin, end, vga_buffer_pointer.get()); buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; } else { buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; } } auto device::write(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); } auto device::writeln(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); newline(); } } // namespace teachos::vga::x86_64::text