231 lines
7.1 KiB
C
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]");
|
|
}
|