Newer
Older
tree-os / src / kernel / drivers / textMode / terminal.c
#include <cursor.h>
#include <terminal.h>

uint16_t *framebuffer = (uint16_t *)FRAMEBUFFER_LOCATION;
uint8_t currentFormat = 0x0A;

void setTextStyle(uint8_t style) { currentFormat = style; }

void setCharAtOffset(uint16_t offset, char c, uint8_t format) {
    *((uint16_t *)FRAMEBUFFER_LOCATION + offset) = format << 8 | c;
}

uint16_t getOffset(uint8_t x, uint8_t y) { return VIDEO_WIDTH * y + x; }

void clearScreen() {
    setCursorOffset(0);
    for (int y = 0; y < VIDEO_HEIGHT; y++) {
        for (int x = 0; x < VIDEO_WIDTH; x++) {
            setCharAtOffset(getOffset(x, y), ' ', currentFormat);
        }
    }
}

void shiftUp() {
    for (int y = 1; y < VIDEO_HEIGHT; y++) {
        for (int x = 0; x < VIDEO_WIDTH; x++) {
            uint16_t old =
                *(uint16_t *)(FRAMEBUFFER_LOCATION + getOffset(x, y) * 2);
            setCharAtOffset(getOffset(x, y - 1), old, old >> 8);
        }
    }
    for (int x = 0; x < VIDEO_WIDTH; x++) {
        setCharAtOffset(getOffset(x, VIDEO_HEIGHT - 1), ' ', currentFormat);
    }
}

uint16_t cursorOffset = 0;

void newLine() {
    uint8_t x = cursorOffset % VIDEO_WIDTH;
    uint8_t y = cursorOffset / VIDEO_WIDTH;
    x = 0;
    y++;
    if (y >= VIDEO_HEIGHT) {
        shiftUp();
        y--;
    }
    setCursorPosition(x, y);
    cursorOffset = getOffset(x, y);
}

typedef enum { STANDARD, ANSI_ESCAPE } States;

typedef enum { BRACKET_OPEN, BUFFER } AnsiEscapeStates;

States currentState = STANDARD;

AnsiEscapeStates currentAnsiEscapeState = BRACKET_OPEN;

uint32_t ansiEscapeBuffer1 = 0;
uint32_t ansiEscapeBuffer2 = 0;

uint32_t *currentBuffer = &ansiEscapeBuffer1;

void writeChar(char c) {
    if (c == 0)
        return;
    switch (currentState) {
    case STANDARD:
        if (c == '\x1B') {
            currentState = ANSI_ESCAPE;
            currentAnsiEscapeState = BRACKET_OPEN;
        }
        break;
    case ANSI_ESCAPE:
        switch (currentAnsiEscapeState) {
        case BRACKET_OPEN:
            currentAnsiEscapeState = BUFFER;
            return;
        case BUFFER:
            switch (c) {
            case 'H':
                cursorOffset = 0;
                setCursorOffset(0);
                currentState = STANDARD;
                return;
            case 'J':
                clearScreen();
                currentState = STANDARD;
                return;
            }
        }
    }
    if (currentState != STANDARD) {
        return;
    }
    switch (c) {
    case '\n':
        newLine();
        return;
    case '\b':
        setCharAtOffset(--cursorOffset, ' ', currentFormat);
        setCursorOffset(cursorOffset);
        return;
    }
    setCharAtOffset(cursorOffset++, c, currentFormat);
    setCursorOffset(cursorOffset);
}