commit 9d053b9c82e28b2da4ad8a778ff1eb590cf5120d
parent ab1f1760a39941a79bfc650f0141409272036c46
Author: ssnf <ssnf@ssnf.xyz>
Date: Fri, 15 Oct 2021 11:41:07 +0000
improved do/undo reliability
Diffstat:
M | Makefile | | | 8 | ++++---- |
M | config.def.h | | | 51 | ++++++++++++++++++++++++++++++++------------------- |
M | sim.c | | | 427 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
3 files changed, 294 insertions(+), 192 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
-CC = c89
-CFLAGS = -Os -g -Wall -Wpedantic -Wno-deprecated-declarations -Wno-return-type
-SRC = ${wildcard *.c}
-OBJ = ${SRC:.c=.o}
+CC = c89
+CFLAGS = -Os -Wall -Wpedantic -Wno-deprecated-declarations -Wno-return-type
+SRC = ${wildcard *.c}
+OBJ = ${SRC:.c=.o}
all: sim
diff --git a/config.def.h b/config.def.h
@@ -1,6 +1,32 @@
-#define STATUS "0x%02x -%lu- %s%c", f->s->s[f->dot.p1], f - file, f->name->n ? f->name->s : "-unnamed-", f->dirty
+#define STATUS "%lu 0x%02x %s%c -%lu- %u", f->dot.p1, f->s->s[f->dot.p1], f->name->n ? f->name->s : "-unnamed-", f->dirty, f - file, counter
Key keys[] = {
+ { 'c', change },
+ { 'C', change , 'c' },
+ { 'r', change, 'x' },
+ { '0', count, 0 },
+ { '1', count, 1 },
+ { '2', count, 2 },
+ { '3', count, 3 },
+ { '4', count, 4 },
+ { '5', count, 5 },
+ { '6', count, 6 },
+ { '7', count, 7 },
+ { '8', count, 8 },
+ { '9', count, 9 },
+ { 'd', delete },
+ { 'x', delete , Letter },
+ { '.', dot },
+ { Esc, escape },
+ { 'E', file_open },
+ { 'q', file_close, -1 },
+ { 'S', file_save, -1 },
+ { 'i', insert },
+ { 'I', insert , StartLine},
+ { 'A', insert , EndLine },
+ { 'a', insert , Right },
+ { 'o', insert , Down },
+ { 'O', insert , Up },
{ 'h', move, Left },
{ 'j', move, Down },
{ 'k', move, Up },
@@ -8,33 +34,20 @@ Key keys[] = {
{ Ctrl + 'd', move, HalfDown },
{ Ctrl + 'u', move, HalfUp },
{ '$', move, EndLine },
- { '0', move, StartLine },
{ 'G', move, Bottom },
{ 'g', move, Top },
{ 'w', move, Word },
{ 'e', move, EndWord },
{ 'b', move, PrevWord },
- { 'i', insert },
- { 'I', insert , StartLine},
- { 'A', insert , EndLine },
- { 'a', insert , Right },
- { 'o', insert , Down },
- { 'O', insert , Up },
- { 'd', delete },
- { 'x', delete , 'x' },
- { 'c', change },
- { 'C', change , 'c' },
- { 'r', change, 'x' },
- { 'E', file_open },
- { 'q', file_close, -1 },
- { 'S', file_save, -1 },
{ 'Q', quit },
{ '/', search, '/' },
{ '?', search, '?' },
{ 'n', search, 'n' },
{ 'N', search, 'N' },
{ 'u', undo },
- { Ctrl + 'r', redo },
- { Esc, escape }
+ { Ctrl + 'r', redo }
+ /*TODO: yank command */
+ /*TODO: replace command */
+ /*TODO: dot command */
+ /*TODO: visual selection(?) */
};
-
diff --git a/sim.c b/sim.c
@@ -21,11 +21,14 @@ enum {
HalfDown,
Top,
Bottom,
- StartLine,
- EndLine,
+ Letter,
Word,
EndWord,
PrevWord,
+ Till,
+ Line,
+ StartLine,
+ EndLine,
Insert,
Delete,
Change,
@@ -45,17 +48,20 @@ typedef struct {
} String;
typedef struct {
- String s[2048];
- int c[2048];
+ String is[2048];
+ String ds[2048];
+ uint c[2048];
+ uint arg[2048];
+ uint count[2048];
Posn p0[2048];
- ushort n;
-} Buffer; /*yes, it is very big. absolutely no compromises*/
+ short n;
+} Buffer;
typedef struct {
String* s;
String* name;
Address dot;
- ushort i; /*buffer index*/
+ short i; /*buffer index*/
uchar dirty;
} File;
@@ -77,9 +83,11 @@ void* emalloc(ulong);
void* erealloc(void*, ulong);
static void blind_reader(Frame* fr, String* s, Posn p0);
static void blind_writer(String* s, Frame* fr, ushort line, ushort offset, ushort top, ushort bot);
-static void buf_add(Buffer* b, String* s, int c, Posn p0);
+static void buf_add(Buffer* b, String* is, String* ds, uint c, uint arg, uint count, Posn p0);
static void change(int arg);
+static void count(int arg);
static void delete(int arg);
+static void dot(int arg);
static void redo(int arg);
static void escape(int c);
static void init();
@@ -96,9 +104,10 @@ static void fr_close(Frame* fr);
static void fr_init(Frame* fr);
static void fr_insert(Frame* p, Frame* q, ushort n);
static void fr_insure(Frame* fr, ushort n);
-static void fr_update(int arg);
+static void fr_update();
static void fr_zero(Frame*);
static void search(int arg);
+static int select(int arg);
static void str_init(String* p);
static void str_close(String* p);
static void str_zero(String* p);
@@ -115,8 +124,9 @@ static void quit(int);
static Frame* fr, frame[FILECOUNT];
static File* f, file[FILECOUNT];
static Buffer* buf, buffer[FILECOUNT];
-static String srch;
+static String istr, srch;
static Window w;
+static uint counter;
#include "config.h"
@@ -141,7 +151,7 @@ die(char* fmt, ...)
file_save(i);
fprintf(stderr, "file saved to %s\n", file[i].name->s);
}
- *fmt = *(char*)0;
+ *fmt = *(char*)NULL;
}
void*
@@ -215,136 +225,161 @@ blind_writer(String* s, Frame* fr, ushort line, ushort offset, ushort top, ushor
}
static void
-buf_add(Buffer* b, String* s, int c, Posn p0)
+buf_add(Buffer* b, String* is, String* ds, uint c, uint arg, uint count, Posn p0)
{
- b->n = ++f->i;
- if (s != NULL) {
- str_zero(&b->s[b->n]);
- str_insert(&b->s[b->n], s, 0);
- }
- b->c[b->n] = c;
- b->p0[b->n] = p0;
+ b->n = ++f->i + 1;
+ str_zero(&b->is[f->i]);
+ str_zero(&b->ds[f->i]);
+ if (is != NULL)
+ str_insert(&b->is[f->i], is, 0);
+ if (ds != NULL)
+ str_insert(&b->ds[f->i], ds, 0);
+ b->c[f->i] = c;
+ b->arg[f->i] = arg;
+ b->count[f->i] = count;
+ b->p0[f->i] = p0;
+ f->dirty = '*';
}
static void
change(int arg)
{
+ String s;
+ uint count;
+
if (!arg)
arg = fgetc(stdin);
switch (arg) {
- case 'x':
- delete('x');
- break;
- case 'c':
- delete('d');
- insert(Up);
- buf_add(buf, NULL, Change, 0);
- return;
- case 'G':
- delete('G');
- insert(Down);
- buf_add(buf, NULL, Change, 0);
- return;
- case 'g':
- delete('g');
- break;
- case 'w':
- delete('w');
- break;
- case 't':
- delete('t');
- break;
- default:
- return;
+ case 'x': arg = Letter; break;
+ case 'c': arg = Line; break;
+ case 'G': arg = Bottom; break;
+ case 'g': arg = Top; break;
+ case 'w': arg = Word; break;
+ case 't': arg = Till; break;
+ }
+ count = counter;
+ arg = select(arg);
+ if (arg == Word || arg == Letter || arg > 0x7f)
+ ++f->dot.p1;
+ str_init(&s);
+ if (f->dot.p0 != f->dot.p1) {
+ str_adds(&s, f->s->s + f->dot.p0, f->dot.p1 - f->dot.p0);
+ str_delete(f->s, f->dot.p0, f->dot.p1);
}
+ f->dot.p0 = f->dot.p1 = f->dot.p0;
insert(0);
- if (buf->c[f->i] == Insert)
- arg = -1;
- buf_add(buf, NULL, Change, arg);
+ if (s.n)
+ str_insert(&buf->ds[f->i], &s, 0);
+ str_close(&s);
+ buf->c[f->i] = Change;
+ buf->arg[f->i] = arg;
+ buf->count[f->i] = count;
+ fr_update();
+}
+
+static void
+count(int arg)
+{
+ if (!counter && !arg) {
+ move(StartLine);
+ return;
+ }
+ counter *= 10;
+ counter += arg;
}
static void
delete(int arg)
{
String s;
- Posn m, n;
+ uint count;
if (!f->s->n)
return;
- if (!arg)
- arg = fgetc(stdin);
- switch (arg) {
- case 'x':
- m = f->dot.p0;
- n = f->dot.p1 + 1;
- if (f->dot.p1 == f->s->n)
- move(Left);
- break;
- case 'd':
- m = fr->a[fr->dot].p0;
- n = fr->a[fr->dot].p1 + 1;
- move(StartLine);
- if (fr->dot == fr->n - 1)
- move(Up);
- break;
- case 'G':
- m = fr->a[fr->dot].p0;
- n = f->s->n;
- move(Up);
- break;
- case 'g':
- m = 0;
- n = fr->a[fr->dot].p1 + 1;
- move(Top);
- break;
- case 'w':
- m = f->dot.p0;
- move(EndWord);
- move(Right);
- n = f->dot.p1;
- f->dot.p0 = f->dot.p1 = m;
- break;
- case 't':
- arg = fgetc(stdin);
- if (arg == Esc)
+ if (!arg) {
+ switch ((arg = fgetc(stdin))) {
+ case 'x': arg = Letter; break;
+ case 'd': arg = Line; break;
+ case 'G': arg = Bottom; break;
+ case 'g': arg = Top; break;
+ case 'w': arg = Word; break;
+ case 't': arg = Till; break;
+ default:
return;
- for (;++f->dot.p1, f->dot.p1 < f->s->n && f->s->s[f->dot.p1] != arg;);
- m = f->dot.p0;
- n = f->dot.p1;
- f->dot.p0 = f->dot.p1 = m;
- break;
- default:
- return;
+ }
}
+ count = counter;
+ if ((arg = select(arg)) < 0)
+ return;
str_init(&s);
- str_adds(&s, f->s->s + m, n - m);
- buf_add(buf, &s, Delete, m);
+ str_adds(&s, f->s->s + f->dot.p0, f->dot.p1 + 1 - f->dot.p0);
+ buf_add(buf, NULL, &s, Delete, arg, count, f->dot.p0);
+ str_delete(f->s, f->dot.p0, f->dot.p1 + 1);
str_close(&s);
- str_delete(f->s, m, n);
- f->dirty = '*';
- fr_update(1);
+ if (f->dot.p0 == f->s->n && f->dot.p0)
+ --f->dot.p0;
+ f->dot.p1 = f->dot.p0;
+ fr_update();
+}
+
+static void
+dot(int arg)
+{
+ String ds;
+
+ if (f->i < 0)
+ f->i = 0;
+ arg = buf->arg[f->i];
+ counter = buf->count[f->i];
+ switch (buf->c[f->i]) {
+ case Insert:
+ if (arg == Down)
+ move(EndLine);
+ else
+ move(arg);
+ str_insert(f->s, &istr, f->dot.p0);
+ buf_add(buf, &istr, NULL, Insert, arg, counter, f->dot.p0);
+ break;
+ case Delete:
+ delete(arg);
+ break;
+ case Change:
+ str_init(&ds);
+ if (buf->ds[f->i].n) {
+ select(arg);
+ if (arg == Word || arg == Letter || arg > 0x7f)
+ ++f->dot.p1;
+ str_adds(&ds, f->s->s + f->dot.p0, f->dot.p1 - f->dot.p0);
+ str_delete(f->s, f->dot.p0, f->dot.p1);
+ }
+ if (buf->is[f->i].n)
+ str_insert(f->s, &buf->is[f->i], f->dot.p0);
+ buf_add(buf, buf->is, &ds, Change, arg, buf->count[f->i], f->dot.p0);
+ str_close(&ds);
+ f->dot.p1 = f->dot.p0;
+ break;
+ }
+ fr_update();
}
static void
redo(int arg)
{
- if (f->i == buf->n)
+ if (f->i == buf->n - 1)
return;
- ++f->i;
- if (buf->c[f->i] == Insert)
- str_insert(f->s, &buf->s[f->i], buf->p0[f->i]);
- else if (buf->c[f->i] == Delete)
- str_delete(f->s, buf->p0[f->i], buf->s[f->i].n);
- else if (buf->c[f->i] == Change) {
- str_delete(f->s, buf->p0[f->i], buf->s[f->i].n);
- str_insert(f->s, &buf->s[f->i], buf->p0[f->i]);
- }
- fr_update(1);
+ if (buf->ds[++f->i].n)
+ str_delete(f->s, buf->p0[f->i], buf->p0[f->i] + buf->ds[f->i].n);
+ if (buf->is[f->i].n)
+ str_insert(f->s, &buf->is[f->i], buf->p0[f->i]);
+ f->dot.p0 = f->dot.p1 = buf->p0[f->i];
+ f->dirty = '*';
+ fr_update();
}
static void
escape(int c)
{
+ counter = 0;
c = fgetc(stdin) - 0x30;
if (c > 0 && c <= 8) {
--c;
@@ -383,13 +418,13 @@ static int
isword(uchar c)
{
switch (c) {
- case ' ':
- case '\t':
- case '\n':
- case '.':
- case '(':
- case ')':
- return 0;
+ case ' ': case '\t': case '\n': case '.':
+ case '(': case ')': case '{': case '}':
+ case '[': case ']': case ':': case ';':
+ case ',': case '<': case '>': case '#':
+ case '*': case '+': case '-': case '!':
+ case '%': case '\\': case '/': case '"':
+ return 0;
}
return 1;
}
@@ -397,16 +432,14 @@ isword(uchar c)
static void
insert(int arg)
{
- String s;
- uchar c;
+ String s, c;
- str_init(&s);
+ str_init(&s), str_init(&c);
+ str_addc(&c, '\0');
switch (arg) {
case StartLine:
- move(StartLine);
- break;
case EndLine:
- move(EndLine);
+ move(arg);
break;
case Right:
move(Right);
@@ -419,44 +452,38 @@ insert(int arg)
str_insert(f->s, &s, f->dot.p0);
++f->dot.p1;
break;
- case Up:
- move(StartLine);
- str_addc(&s, '\n');
- str_insert(f->s, &s, f->dot.p0);
- ++f->dot.p1;
- break;
}
for (;;) {
win_query(&w);
- fr_update(0);
- c = fgetc(stdin);
- switch (c) {
+ fr_update();
+ switch ((c.s[0] = fgetc(stdin))) {
case Esc:
- if (f->dot.p1 != f->dot.p0)
- str_delete(f->s, f->dot.p0, f->dot.p1);
- goto endloop;
+ goto endmode;
case Del:
- str_delc(&s);
+ if (f->dot.p1 != f->dot.p0) {
+ str_delc(&s);
+ str_delete(f->s, f->dot.p1 - 1, f->dot.p1);
+ --f->dot.p1;
+ }
break;
default:
- str_addc(&s, c);
+ str_addc(&s, c.s[0]);
+ str_insert(f->s, &c, f->dot.p1);
}
- if (f->dot.p1 != f->dot.p0)
- str_delete(f->s, f->dot.p0, f->dot.p1);
- str_insert(f->s, &s, f->dot.p0);
f->dot.p1 = f->dot.p0 + s.n;
}
- endloop:
- if (s.n) {
- if (arg == Up)
- str_addc(&s, '\n');
- buf_add(buf, &s, Insert, f->dot.p0);
+ endmode:
+ str_zero(&istr);
+ str_insert(&istr, &s, 0);
+ for (counter ? --counter : 0; counter; --counter) {
+ str_insert(&istr, &s, istr.n);
str_insert(f->s, &s, f->dot.p0);
- fr_update(0);
- f->dirty = '*';
}
- str_close(&s);
+ buf_add(buf, &istr, NULL, Insert, arg, counter, f->dot.p0);
+ str_close(&s), str_close(&c);
f->dot.p0 = f->dot.p1;
+ if (f->dot.p1 >= f->s->n)
+ move(Left);
}
static void
@@ -473,6 +500,7 @@ init()
fr = &frame[0];
buf = &buffer[0];
str_init(&srch);
+ str_init(&istr);
}
static void
@@ -498,7 +526,8 @@ file_init(File* f)
f->name = emalloc(sizeof(String));
str_init(f->s);
str_init(f->name);
- f->i = f->dirty = f->dot.p0 = f->dot.p1 = 0;
+ f->dirty = f->dot.p0 = f->dot.p1 = 0;
+ f->i = -1;
}
static void
@@ -514,7 +543,8 @@ file_load(File* f)
rewind(disk);
fread(f->s->s, f->s->n, 1, disk);
fclose(disk);
- f->i = f->dot.p0 = f->dot.p1 = 0;
+ f->dot.p0 = f->dot.p1 = 0;
+ f->i = -1;
}
static void
@@ -587,7 +617,7 @@ fr_insure(Frame* fr, ushort n)
}
static void
-fr_update(int arg)
+fr_update()
{
Frame fr0;
Posn p0, p1;
@@ -599,7 +629,7 @@ fr_update(int arg)
printf(ED);
goto status;
}
- if (arg || !fr->n || f->dot.p0 != f->dot.p1 || f->dot.p1 > fr->a[fr->n - 1].p1 || f->dot.p1 < fr->a[0].p0 || fr->n - fr->dot <= w.wy || fr->dot <= half) {
+ if (1 || !fr->n || f->dot.p0 != f->dot.p1 || f->dot.p1 > fr->a[fr->n - 1].p1 || f->dot.p1 < fr->a[0].p0 || fr->n - fr->dot <= w.wy || fr->dot <= half) {
fr_zero(fr);
for (p0 = f->dot.p1; p0; --p0)
if (f->s->s[p0 - 1] == '\n')
@@ -670,10 +700,12 @@ move(int arg)
f->dot.p1 = 0;
break;
case Down:
- if (fr->dot < fr->n - 1)
+ if (!f->s->n)
+ return;
+ else if (fr->dot < fr->n - 1)
f->dot.p1 = fr->a[fr->dot + 1].p0;
else
- f->dot.p1 = fr->a[fr->dot].p1;
+ f->dot.p1 = fr->a[fr->dot].p1 - 1;
break;
case HalfUp:
if (fr->dot < w.wy/2)
@@ -700,10 +732,12 @@ move(int arg)
f->dot.p1 = f->s->n - 1;
break;
case StartLine:
+ if (fr->dot)
+ for (;fr->dot > 1 && f->s->s[fr->a[fr->dot].p0 - 1] != '\n'; --fr->dot);
f->dot.p1 = fr->a[fr->dot].p0;
break;
case EndLine:
- f->dot.p1 = fr->a[fr->dot].p1;
+ for (;f->dot.p1 + 1 < f->s->n && f->s->s[f->dot.p1] != '\n'; ++f->dot.p1);
break;
case Word:
for (;f->dot.p1 < f->s->n && isword(f->s->s[f->dot.p1]); ++f->dot.p1);
@@ -777,6 +811,70 @@ search(int arg)
f->dot.p0 = f->dot.p1 = p - (uchar*)f->s->s;
}
+static int
+select(int arg)
+{
+ Posn p0;
+
+ if (arg > 0x7f) {
+ arg -= 0x7f;
+ goto till;
+ }
+ f->dot.p1 = f->dot.p0;
+ if (!counter)
+ ++counter;
+ switch (arg) {
+ case Letter:
+ p0 = f->dot.p0;
+ for (;counter > 1; --counter)
+ move(Right);
+ break;
+ case Line:
+ move(StartLine);
+ p0 = f->dot.p0;
+ for (;counter; --counter) {
+ move(EndLine);
+ move(Right);
+ }
+ if (f->dot.p1 + 1 < f->s->n)
+ move(Left);
+ break;
+ case Bottom:
+ move(StartLine);
+ move(Left);
+ p0 = f->dot.p0;
+ move(Bottom);
+ break;
+ case Top:
+ p0 = 0;
+ move(EndLine);
+ break;
+ case Word:
+ p0 = f->dot.p0;
+ for (;counter; --counter)
+ move(EndWord);
+ break;
+ case Till:
+ arg = fgetc(stdin);
+ if (arg == Esc)
+ return 0;
+ till:
+ p0 = f->dot.p0;
+ for (;counter; --counter)
+ if (f->dot.p1 + 1 < f->s->n)
+ for (++f->dot.p1; f->dot.p1 + 1 < f->s->n && f->s->s[f->dot.p1 + 1] != arg; ++f->dot.p1);
+ if (f->s->s[f->dot.p1 + 1] != arg) {
+ f->dot.p1 = f->dot.p0;
+ return -1;
+ }
+ arg += 0x7f;
+ break;
+ }
+ f->dot.p0 = p0;
+ counter = 0;
+ return arg;
+}
+
static void
str_init(String* p)
{
@@ -836,8 +934,6 @@ str_delc(String* p)
static void
str_insert(String* p, String* q, Posn p0)
{
- if (p0 > p->n)
- p0 = p->n;
str_insure(p, p->n + q->n);
memmove(p->s + p0 + q->n, p->s + p0, p->n - p0);
memmove(p->s + p0, q->s, q->n);
@@ -847,8 +943,6 @@ str_insert(String* p, String* q, Posn p0)
static void
str_delete(String* p, Posn p0, Posn p1)
{
- if (p1 > p->n)
- p1 = p->n;
memmove(p->s + p0, p->s + p1, p->n - p1);
p->n -= p1 - p0;
}
@@ -856,20 +950,15 @@ str_delete(String* p, Posn p0, Posn p1)
static void
undo(int arg)
{
- if (!f->i)
+ if (f->i < 0)
return;
- if (buf->c[f->i] == Insert)
- str_delete(f->s, buf->p0[f->i], buf->p0[f->i] + buf->s[f->i].n);
- else if (buf->c[f->i] == Delete)
- str_insert(f->s, &buf->s[f->i], buf->p0[f->i]);
- else if (buf->c[f->i] == Change) {
- if (buf->p0[f->i] == -1)
- --f->i, str_delete(f->s, buf->p0[f->i], buf->p0[f->i] + buf->s[f->i].n);
- --f->i, str_insert(f->s, &buf->s[f->i], buf->p0[f->i]);
- }
- f->dot.p0 = f->dot.p1 = buf->p0[f->i];
- --f->i;
- fr_update(1);
+ if (buf->is[f->i].n)
+ str_delete(f->s, buf->p0[f->i], buf->p0[f->i] + buf->is[f->i].n);
+ if (buf->ds[f->i].n)
+ str_insert(f->s, &buf->ds[f->i], buf->p0[f->i]);
+ f->dot.p0 = f->dot.p1 = buf->p0[f->i--];
+ f->dirty = '*';
+ fr_update();
}
int
@@ -885,7 +974,7 @@ main(int argc, char* argv[])
}
for (;;) {
win_query(&w);
- fr_update(0);
+ fr_update();
c = fgetc(stdin);
for (i = 0; i < LENGTH(keys); ++i) {
if (keys[i].key == c) {