#include "os/tty.hpp" #include #include #include "drivers/ps2.hpp" #include "libs/psf.hpp" #include "os/draw.hpp" #include "os/resources/lat9-08.psf.hpp" namespace tty { namespace { size_t gTerminalRow = 0; size_t gTerminalColumn = 0; size_t gTerminalWidth = 0; size_t gTerminalHeight = 0; VgaDoubleColor gTerminalColor = VgaDoubleColor(); // uint16_t* gTerminalBuffer = reinterpret_cast(0xB8000); std::vector gTerminalBuffer; psf::Font gTerminalFont; std::string gReadBuffer; constexpr uint8_t vgaEntryColor(VgaDoubleColor color) { return static_cast(color.foreground) | static_cast(color.background) << 4; } constexpr uint16_t vgaEntry(const unsigned char chr, const VgaDoubleColor color) { return static_cast(chr) | static_cast(vgaEntryColor(color) << 8); } void newline() { gTerminalColumn = 0; if (gTerminalRow < gTerminalHeight - 1) { ++gTerminalRow; } else { draw::scrollBy(0, static_cast(gTerminalFont.getGlyphHeight()) + 1); std::memmove(&gTerminalBuffer[0], &gTerminalBuffer[gTerminalWidth], (gTerminalHeight - 1) * gTerminalWidth * sizeof(VgaCharacter)); for (std::size_t posX = 0; posX < gTerminalWidth; ++posX) { putEntryAt('\0', gTerminalColor, posX, gTerminalHeight - 1); } } } } void initialize() noexcept { setPSFFont(&LAT9_08[0], LAT9_08_SIZE); } void setColor(VgaDoubleColor color) noexcept { gTerminalColor = color; } const VgaDoubleColor& getColor() noexcept { return gTerminalColor; } void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) noexcept { draw::character( /* posX = */ (gTerminalFont.getGlyphWidth() + 1) * posX, /* posY = */ (gTerminalFont.getGlyphHeight() + 1) * posY, /* font = */ gTerminalFont, /* chr = */ chr ? chr : ' ', /* fgColor = */ draw::VGA_PIXELS[static_cast(color.foreground)], /* bgColor = */ draw::VGA_PIXELS[static_cast(color.background)] ); gTerminalBuffer[posY * gTerminalHeight + posX] = { .character = chr, .color = color }; } VgaCharacter getEntryAt(size_t posX, size_t posY) noexcept { return gTerminalBuffer[posY * gTerminalHeight + posX]; } void putChar(char chr) noexcept { putChar(chr, gTerminalColor); } void putChar(char chr, VgaDoubleColor color) noexcept { if (chr == '\n') { newline(); return; } putEntryAt(chr, color, gTerminalColumn, gTerminalRow); if (++gTerminalColumn == gTerminalWidth) { newline(); } } void deleteChar() noexcept { if (gTerminalColumn > 0) { --gTerminalColumn; putEntryAt(' ', gTerminalColor, gTerminalColumn, gTerminalRow); // TODO: store the length of each line so we can return to the previous one } } void write(const char* data, size_t size) noexcept { for (size_t idx = 0; idx < size; idx++) { putChar(data[idx]); } } void write(const char* data) noexcept { write(data, std::strlen(data)); } unsigned rowLength(unsigned row) { unsigned length = 0; for (; length < gTerminalWidth; ++length) { if (getEntryAt(length, row).character == '\0') { break; } } return length; } const std::string& readLine() noexcept { gReadBuffer.clear(); while(true) { char chr = '\0'; putChar(' ', gTerminalColor.swapped()); while (!baos::ps2::readChar(chr)); // TODO: arrow key navigation and stuff deleteChar(); if (chr == '\b') { if (!gReadBuffer.empty()) { gReadBuffer.pop_back(); deleteChar(); } continue; } gReadBuffer += chr; putChar(chr); if (chr == '\n') { return gReadBuffer; } } } bool setPSFFont(const void* data, size_t length) noexcept { psf::Font newFont; if (!psf::Font::create(data, length, newFont)) { return false; } gTerminalFont = newFont; gTerminalWidth = draw::getPrimaryFramebuffer().getWidth() / (gTerminalFont.getGlyphWidth() + 1); gTerminalHeight = draw::getPrimaryFramebuffer().getHeight() / (gTerminalFont.getGlyphHeight() + 1); gTerminalBuffer.resize(gTerminalWidth * gTerminalHeight); return true; } }