Files
tools/ved/src/editor.c
T
2026-04-08 16:37:32 +02:00

231 lines
7.1 KiB
C

#include "editor.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <libgen.h>
static char statusmsg[256];
static void load_desc(Editor *e)
{
e->desc[0] = '\0';
if (!e->buf.filename) return;
char tmp[512];
strncpy(tmp, e->buf.filename, sizeof(tmp) - 1);
tmp[sizeof(tmp) - 1] = '\0';
char *dir = dirname(tmp);
char path[512];
snprintf(path, sizeof(path), "%s/desc.txt", dir);
FILE *f = fopen(path, "r");
if (!f) return;
int pos = 0;
int c;
while ((c = fgetc(f)) != EOF && pos < (int)sizeof(e->desc) - 1)
e->desc[pos++] = (char)c;
e->desc[pos] = '\0';
fclose(f);
}
void editor_init(Editor *e)
{
buf_init(&e->buf);
e->cx = e->cy = 0;
e->rowoff = e->coloff = 0;
e->mode = MODE_NORMAL;
e->ft = FT_NONE;
e->ghost[0] = '\0';
e->idle_count = 0;
e->nano_mode = 0;
e->cutbuf = (Line){NULL, 0, 0};
e->desc[0] = '\0';
e->autocomplete_row = -1;
e->autocomplete_col = 0;
getmaxyx(stdscr, e->screenrows, e->screencols);
e->screenrows -= 2; /* reserve status + command line */
statusmsg[0] = '\0';
}
void editor_open(Editor *e, const char *filename)
{
buf_load(&e->buf, filename);
e->ft = syntax_detect(filename);
load_desc(e);
}
void editor_scroll(Editor *e)
{
if (e->cy < e->rowoff)
e->rowoff = e->cy;
if (e->cy >= e->rowoff + e->screenrows)
e->rowoff = e->cy - e->screenrows + 1;
if (e->cx < e->coloff)
e->coloff = e->cx;
if (e->cx >= e->coloff + e->screencols)
e->coloff = e->cx - e->screencols + 1;
}
void editor_set_status(Editor *e, const char *fmt, ...)
{
(void)e;
va_list ap;
va_start(ap, fmt);
vsnprintf(statusmsg, sizeof(statusmsg), fmt, ap);
va_end(ap);
}
void editor_draw(Editor *e)
{
editor_scroll(e);
erase();
if (e->nano_mode) {
/* nano layout: title bar row 0, content rows 1..screenrows,
status at screenrows+1, shortcut bars at screenrows+2..+3 */
int content_start = 1;
for (int y = 0; y < e->screenrows; y++) {
int filerow = y + e->rowoff;
int sy = y + content_start;
if (filerow < e->buf.numlines) {
Line *l = &e->buf.lines[filerow];
int len = l->len - e->coloff;
if (len < 0) len = 0;
if (len > e->screencols) len = e->screencols;
if (len > 0 && l->chars) {
if (e->ft != FT_NONE) {
int bc = syntax_line_in_block_comment(
&e->buf, filerow, e->ft);
syntax_draw_line(l->chars + e->coloff, len,
sy, 0, e->screencols, e->ft, bc);
} else {
mvaddnstr(sy, 0, l->chars + e->coloff, len);
}
}
}
}
/* ghost text */
if (e->ghost[0] != '\0') {
int gy = e->cy - e->rowoff + content_start;
int gx = e->cx - e->coloff;
if (gy > 0 && gy <= e->screenrows && gx >= 0) {
attron(A_DIM);
int glen = (int)strlen(e->ghost);
if (gx + glen > e->screencols) glen = e->screencols - gx;
if (glen > 0) mvaddnstr(gy, gx, e->ghost, glen);
attroff(A_DIM);
}
}
/* status message line */
if (statusmsg[0])
mvaddnstr(e->screenrows + 1, 0, statusmsg, e->screencols);
/* nano title bar + shortcut bars */
nano_draw_bars(e);
/* cursor */
move(e->cy - e->rowoff + content_start, e->cx - e->coloff);
} else {
/* vi layout */
for (int y = 0; y < e->screenrows; y++) {
int filerow = y + e->rowoff;
if (filerow < e->buf.numlines) {
Line *l = &e->buf.lines[filerow];
int len = l->len - e->coloff;
if (len < 0) len = 0;
if (len > e->screencols) len = e->screencols;
if (len > 0 && l->chars) {
if (e->ft != FT_NONE) {
int bc = syntax_line_in_block_comment(
&e->buf, filerow, e->ft);
syntax_draw_line(l->chars + e->coloff, len,
y, 0, e->screencols, e->ft, bc);
} else {
mvaddnstr(y, 0, l->chars + e->coloff, len);
}
}
} else {
mvaddch(y, 0, '~');
}
}
/* ghost text */
if (e->mode == MODE_INSERT && e->ghost[0] != '\0') {
int gy = e->cy - e->rowoff;
int gx = e->cx - e->coloff;
if (gy >= 0 && gy < e->screenrows && gx >= 0) {
attron(A_DIM);
int glen = (int)strlen(e->ghost);
if (gx + glen > e->screencols) glen = e->screencols - gx;
if (glen > 0) mvaddnstr(gy, gx, e->ghost, glen);
attroff(A_DIM);
}
}
/* status bar */
attron(A_REVERSE);
char status[256];
const char *modestr = e->mode == MODE_INSERT ? "-- INSERT --" :
e->mode == MODE_COMMAND ? ":" : "";
const char *fname = e->buf.filename ? e->buf.filename : "[No Name]";
int slen = snprintf(status, sizeof(status), " %s %s%s",
modestr, fname, e->buf.dirty ? " [+]" : "");
char rinfo[64];
int rlen = snprintf(rinfo, sizeof(rinfo), "%d/%d ",
e->cy + 1, e->buf.numlines);
for (int i = slen; i < e->screencols - rlen; i++)
status[i] = ' ';
memcpy(status + e->screencols - rlen, rinfo, rlen);
status[e->screencols] = '\0';
mvaddnstr(e->screenrows, 0, status, e->screencols);
attroff(A_REVERSE);
/* message/command line */
mvaddnstr(e->screenrows + 1, 0, statusmsg, e->screencols);
/* cursor */
move(e->cy - e->rowoff, e->cx - e->coloff);
}
refresh();
}
void editor_prompt_desc(Editor *e)
{
int row = e->nano_mode ? e->screenrows + 1 : e->screenrows + 1;
char buf[sizeof(e->desc)];
int len = 0;
/* pre-fill with current desc */
if (e->desc[0]) {
len = (int)strlen(e->desc);
memcpy(buf, e->desc, len);
}
buf[len] = '\0';
editor_set_status(e, "Desc: %s", buf);
editor_draw(e);
move(row, 6 + len);
refresh();
for (;;) {
int c = getch();
if (c == '\r' || c == '\n' || c == KEY_ENTER) break;
if (c == 27) { return; } /* ESC cancels */
if ((c == KEY_BACKSPACE || c == 127) && len > 0) {
buf[--len] = '\0';
} else if (c >= 32 && c < 127 && len < (int)sizeof(buf) - 1) {
buf[len++] = (char)c;
buf[len] = '\0';
}
editor_set_status(e, "Desc: %s", buf);
editor_draw(e);
move(row, 6 + len);
refresh();
}
memcpy(e->desc, buf, len);
e->desc[len] = '\0';
editor_set_status(e, len > 0 ? "[Description set]" : "[Description cleared]");
}