nshell/src/term.c

182 lines
4.3 KiB
C

#include "term.h"
#include <gint/display.h>
#include <gint/rtc.h>
#include <ctype.h>
#include <printf.h>
#include <stdarg.h>
#include <string.h>
#include "utf8.h"
extern font_t uf5x7;
struct tcell {
char chr[4];
int fg;
int bg;
};
static struct tcell tgrid[UNS_TERM_ROWS][UNS_TERM_COLS];
static void tgrid_set(int row, int col, int fg, int bg, char c[4]) {
tgrid[row][col].chr[0] = c[0];
tgrid[row][col].chr[1] = c[1];
tgrid[row][col].chr[2] = c[2];
tgrid[row][col].chr[3] = c[3];
tgrid[row][col].fg = fg;
tgrid[row][col].bg = bg;
}
static int tgrid_sets(int *row, int *col, int fg, int bg, const char *s) {
int i = 0;
while (s[i] != '\0') {
// boundary check
if (*row >= UNS_TERM_ROWS)
return i;
if (*col >= UNS_TERM_COLS)
return i;
int charlen = charlen_utf8(s[i]);
char unichar[4];
int j;
for (j = 0; j < charlen; j++)
unichar[j] = s[i + j];
for (; j < 4; j++)
unichar[j] = '\0';
i += charlen;
const int char_is_newline = (strncmp(unichar, "\n", 4) == 0);
if (char_is_newline) {
// clear line end
for (; *col < UNS_TERM_COLS; *col = *col + 1)
tgrid_set(*row, *col, C_WHITE, C_BLACK, " \0\0");
} else {
tgrid_set(*row, *col, fg, bg, unichar);
*col = *col + 1;
}
}
return i;
}
int term_writeat(int row, int col, int fg, int bg, const char *s) { return tgrid_sets(&row, &col, fg, bg, s); }
void tgrid_display(void) {
dfont(&uf5x7);
int y = 3;
for (int row = 0; row < UNS_TERM_ROWS; row++) {
int x = 2;
for (int col = 0; col < UNS_TERM_COLS; col++) {
const struct tcell cell = tgrid[row][col];
// unpack unicode
char buf[5];
buf[0] = cell.chr[0];
buf[1] = cell.chr[1];
buf[2] = cell.chr[2];
buf[3] = cell.chr[3];
buf[4] = '\0';
drect(x - 1, y - 1, x + 6, y + 8, cell.bg);
dtext_opt(x, y, cell.fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, (char *)&buf, -1);
x += 1 + 5;
}
y += 1 + 7 + 2;
}
}
void term_scroll_down(void) {
// clear last line
for (int i = 0; i < UNS_TERM_COLS; i++) {
tgrid[UNS_TERM_ROWS - 1][i].chr[0] = ' ';
tgrid[UNS_TERM_ROWS - 1][i].chr[1] = '\0';
tgrid[UNS_TERM_ROWS - 1][i].chr[2] = '\0';
tgrid[UNS_TERM_ROWS - 1][i].chr[3] = '\0';
tgrid[UNS_TERM_ROWS - 1][i].fg = C_WHITE;
tgrid[UNS_TERM_ROWS - 1][i].bg = C_BLACK;
}
for (int i = 1; i < UNS_TERM_ROWS - 1; i++) {
memcpy(tgrid[i], tgrid[i + 1], UNS_TERM_COLS * sizeof(struct tcell));
}
}
static int term_print_opt(const char *str, int fg, int bg) {
static int row = 1;
static int col = 0;
int i = 0;
while (str[i] != '\0') {
// handle cursor overflow (column)
if (col >= UNS_TERM_COLS) {
col = 0;
row++;
}
// handle cursor overflow (row)
if (row >= UNS_TERM_ROWS - 1) {
term_scroll_down();
row = UNS_TERM_ROWS - 2;
}
i += tgrid_sets(&row, &col, fg, bg, str + i);
}
return i;
}
int term_print(const char *str) { return term_print_opt(str, C_WHITE, C_BLACK); }
int term_printf(const char *restrict format, ...) {
va_list argp;
va_start(argp, format);
char buf[256];
const int n = vsnprintf(buf, sizeof(buf), format, argp);
term_print(buf);
va_end(argp);
return n;
}
int term_eprint(const char *str) { return term_print_opt(str, C_RED, C_BLACK); }
int term_eprintf(const char *restrict format, ...) {
va_list argp;
va_start(argp, format);
char buf[256];
const int n = vsnprintf(buf, sizeof(buf), format, argp);
term_eprint(buf);
va_end(argp);
return n;
}
int term_kprint(const char *str) {
int t = rtc_ticks();
char kstr[256];
sprintf(kstr, "[%5d.%03d] %s\n", t / 128, (t % 128) * 100 / 128, str);
const int ret = term_print_opt(kstr, C_RED | C_GREEN, C_BLACK);
return ret;
}
int term_kprintf(const char *restrict format, ...) {
va_list argp;
va_start(argp, format);
char buf[256];
const int n = vsnprintf(buf, sizeof(buf), format, argp);
term_kprint(buf);
va_end(argp);
return n;
}