Files
ke/display.cc
2025-11-25 09:17:50 -08:00

238 lines
5.8 KiB
C++

#include "display.h"
#include "ke_constants.h"
#include "abuf.h"
#include "erow.h"
#include <termios.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cassert>
// Need access to main.cc structures and functions
extern void erow_update(struct erow *row);
extern int erow_render_to_cursor(struct erow *row, int cx);
// erow definition (needed for accessing row fields)
struct erow {
char *line;
char *render;
int size;
int rsize;
int cap;
};
// editor_t definition (needed for display operations)
struct editor_t {
struct termios entry_term;
int rows, cols;
int curx, cury;
int rx;
int mode;
int nrows;
int rowoffs, coloffs;
struct erow *row;
struct erow *killring;
int kill;
int no_kill;
char *filename;
int dirty;
int dirtyex;
char msg[80];
int mark_set;
int mark_curx, mark_cury;
time_t msgtm;
};
namespace ke {
void Display::clear(ke::abuf* ab) {
if (ab == nullptr) {
(void)write(STDOUT_FILENO, ESCSEQ "2J", 4);
(void)write(STDOUT_FILENO, ESCSEQ "H", 3);
} else {
ab->append(ESCSEQ "2J", 4);
ab->append(ESCSEQ "H", 3);
}
}
void Display::draw_rows(editor_t* editor, ke::abuf* ab) {
assert(editor->cols >= 0);
char* buf = new char[editor->cols];
int buflen, filerow, padding;
int y;
for (y = 0; y < editor->rows; y++) {
filerow = y + editor->rowoffs;
if (filerow >= editor->nrows) {
if ((editor->nrows == 0) && (y == editor->rows / 3)) {
buflen = snprintf(buf,
editor->cols,
"%s",
KE_VERSION);
padding = (editor->rows - buflen) / 2;
if (padding) {
ab->append("|", 1);
padding--;
}
while (padding--)
ab->append(" ", 1);
ab->append(buf, buflen);
} else {
ab->append("|", 1);
}
} else {
erow_update(&editor->row[filerow]);
buflen = editor->row[filerow].rsize - editor->coloffs;
if (buflen < 0) {
buflen = 0;
}
if (buflen > editor->cols) {
buflen = editor->cols;
}
ab->append(editor->row[filerow].render + editor->coloffs,
buflen);
}
ab->append(ESCSEQ "K", 3);
ab->append("\r\n", 2);
}
delete[] buf;
}
char Display::status_mode_char(int mode) {
switch (mode) {
case MODE_NORMAL:
return 'N';
case MODE_KCOMMAND:
return 'K';
case MODE_ESCAPE:
return 'E';
default:
return '?';
}
}
void Display::draw_status_bar(editor_t* editor, ke::abuf* ab) {
char* status = new char[editor->cols];
char* rstatus = new char[editor->cols];
char* mstatus = new char[editor->cols];
int len, rlen;
len = snprintf(status,
editor->cols,
"%c%cke: %.20s - %d lines",
status_mode_char(editor->mode),
editor->dirty ? '!' : '-',
editor->filename ? editor->filename : "[no file]",
editor->nrows);
if (editor->mark_set) {
snprintf(mstatus,
editor->cols,
" | M: %d, %d ",
editor->mark_curx + 1,
editor->mark_cury + 1);
} else {
snprintf(mstatus, editor->cols, " | M:clear ");
}
rlen = snprintf(rstatus,
editor->cols,
"L%d/%d C%d %s",
editor->cury + 1,
editor->nrows,
editor->curx + 1,
mstatus);
if (len > editor->cols) {
len = editor->cols;
}
ab->append(ESCSEQ "7m", 4);
ab->append(status, len);
while (len < editor->cols) {
if (editor->cols - len == rlen) {
ab->append(rstatus, rlen);
break;
} else {
ab->append(" ", 1);
len++;
}
len++;
}
ab->append(ESCSEQ "m", 3);
ab->append("\r\n", 2);
delete[] status;
delete[] rstatus;
delete[] mstatus;
}
void Display::draw_message_line(editor_t* editor, ke::abuf* ab) {
int len = strlen(editor->msg);
ab->append(ESCSEQ "K", 3);
if (len > editor->cols) {
len = editor->cols;
}
if (len && ((time(nullptr) - editor->msgtm) < MSG_TIMEO)) {
ab->append(editor->msg, len);
}
}
void Display::scroll(editor_t* editor) {
editor->rx = 0;
if (editor->cury < editor->nrows) {
editor->rx = erow_render_to_cursor(
&editor->row[editor->cury],
editor->curx);
}
if (editor->cury < editor->rowoffs) {
editor->rowoffs = editor->cury;
}
if (editor->cury >= editor->rowoffs + editor->rows) {
editor->rowoffs = editor->cury - editor->rows + 1;
}
if (editor->rx < editor->coloffs) {
editor->coloffs = editor->rx;
}
if (editor->rx >= editor->coloffs + editor->cols) {
editor->coloffs = editor->rx - editor->cols + 1;
}
}
void Display::refresh(editor_t* editor) {
char buf[32];
ke::abuf ab;
scroll(editor);
ab.append(ESCSEQ "?25l", 6);
clear(&ab);
draw_rows(editor, &ab);
draw_status_bar(editor, &ab);
draw_message_line(editor, &ab);
snprintf(buf,
sizeof(buf),
ESCSEQ "%d;%dH",
(editor->cury - editor->rowoffs) + 1,
(editor->rx - editor->coloffs) + 1);
ab.append(buf, strnlen(buf, 32));
ab.append(ESCSEQ "?25h", 6);
(void)write(STDOUT_FILENO, ab.data(), ab.size());
}
} // namespace ke