more undo work
This commit is contained in:
140
main.c
140
main.c
@@ -88,13 +88,13 @@ struct abuf {
|
|||||||
|
|
||||||
/* editor row */
|
/* editor row */
|
||||||
struct erow {
|
struct erow {
|
||||||
char *line;
|
char *line;
|
||||||
char *render;
|
char *render;
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
int rsize;
|
int rsize;
|
||||||
|
|
||||||
int cap;
|
int cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -284,7 +284,10 @@ int cursor_at_eol(void);
|
|||||||
void delete_row(int at);
|
void delete_row(int at);
|
||||||
void row_append_row(struct erow *row, char *s, int len);
|
void row_append_row(struct erow *row, char *s, int len);
|
||||||
void row_insert_ch(struct erow *row, int at, int16_t c);
|
void row_insert_ch(struct erow *row, int at, int16_t c);
|
||||||
|
void row_insert_block(struct erow *row, int at,
|
||||||
|
const char *data, size_t len);
|
||||||
void row_delete_ch(struct erow *row, int at);
|
void row_delete_ch(struct erow *row, int at);
|
||||||
|
void row_delete_block(struct erow *row, int at, size_t len);
|
||||||
void insertch(int16_t c);
|
void insertch(int16_t c);
|
||||||
void deletech(uint8_t op);
|
void deletech(uint8_t op);
|
||||||
void open_file(const char *filename);
|
void open_file(const char *filename);
|
||||||
@@ -1059,66 +1062,62 @@ editor_redo(void)
|
|||||||
void
|
void
|
||||||
undo_apply(const struct undo_node *node, const int direction)
|
undo_apply(const struct undo_node *node, const int direction)
|
||||||
{
|
{
|
||||||
|
struct erow *erow = NULL;
|
||||||
int row = node->row;
|
int row = node->row;
|
||||||
int col = node->col;
|
int col = node->col;
|
||||||
const char *data = node->text.b;
|
const char *data = node->text.b;
|
||||||
size_t len = node->text.len;
|
size_t len = node->text.len;
|
||||||
|
|
||||||
|
if (row >= editor.nrows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
erow = &editor.row[row];
|
||||||
|
|
||||||
jump_to_position(col, row);
|
jump_to_position(col, row);
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case UNDO_PASTE:
|
case UNDO_PASTE:
|
||||||
case UNDO_INSERT:
|
case UNDO_INSERT:
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
row_insert_block(erow, col, data, len);
|
||||||
insertch((unsigned char)data[i]);
|
editor.curx = col + len;
|
||||||
}
|
} else { /* UNDO = delete the whole block */
|
||||||
} else {
|
row_delete_block(erow, col, len);
|
||||||
for (size_t i = 0; i < len; i++) {
|
editor.curx = col;
|
||||||
deletech(KILLRING_NO_OP);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNDO_DELETE:
|
case UNDO_DELETE:
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
row_delete_block(erow, col, len);
|
||||||
deletech(KILLRING_NO_OP);
|
editor.curx = col;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < len; i++) {
|
row_insert_block(erow, col, data, len);
|
||||||
insertch((unsigned char)data[i]);
|
editor.curx = col + len;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNDO_NEWLINE:
|
case UNDO_NEWLINE:
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
newline();
|
newline();
|
||||||
} else {
|
} else {
|
||||||
if (editor.cury > 0) {
|
if (editor.cury > 0) {
|
||||||
editor.curx = editor.row[editor.cury - 1].size;
|
int prev = editor.cury - 1;
|
||||||
row_append_row(&editor.row[editor.cury - 1],
|
editor.curx = editor.row[prev].size;
|
||||||
editor.row[editor.cury].line,
|
row_append_row(&editor.row[prev],
|
||||||
editor.row[editor.cury].size);
|
editor.row[editor.cury].line,
|
||||||
|
editor.row[editor.cury].size);
|
||||||
delete_row(editor.cury);
|
delete_row(editor.cury);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNDO_DELETE_ROW:
|
case UNDO_DELETE_ROW:
|
||||||
if (direction > 0) {
|
if (direction > 0) {
|
||||||
/* redo = delete the whole row again */
|
|
||||||
delete_row(editor.cury);
|
delete_row(editor.cury);
|
||||||
} else {
|
} else {
|
||||||
/* undo = re-insert the saved row (including final '\n') */
|
if (len > 0 && data[len-1] == '\n') len--;
|
||||||
if (len > 0 && data[len - 1] == '\n') len--;
|
|
||||||
erow_insert(editor.cury, (char*)data, len);
|
erow_insert(editor.cury, (char*)data, len);
|
||||||
/* cursor goes to start of re-inserted row */
|
|
||||||
editor.curx = 0;
|
editor.curx = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNDO_INDENT:
|
case UNDO_INDENT:
|
||||||
case UNDO_KILL_REGION:
|
case UNDO_KILL_REGION:
|
||||||
/* These are more complex – you can implement later */
|
/* These are more complex – you can implement later */
|
||||||
@@ -1165,6 +1164,10 @@ killring_yank(void)
|
|||||||
insertch(ch);
|
insertch(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
undo_begin(UNDO_PASTE);
|
||||||
|
undo_append(editor.killring->line, editor.killring->size);
|
||||||
|
undo_commit(); /* atomic */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1793,6 +1796,38 @@ row_insert_ch(struct erow *row, int at, int16_t c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
row_insert_block(struct erow *row, int at, const char *data, size_t len)
|
||||||
|
{
|
||||||
|
if (at < 0) {
|
||||||
|
at = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at > row->size) {
|
||||||
|
at = row->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row->size + (int)len + 1 > row->cap) {
|
||||||
|
row->cap = cap_growth(row->cap, row->size + len + 1);
|
||||||
|
row->line = realloc(row->line, row->cap);
|
||||||
|
assert(row->line != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(row->line + at + len, row->line + at,
|
||||||
|
row->size - at + 1); /* +1 for NUL */
|
||||||
|
memcpy(row->line + at, data, len);
|
||||||
|
row->size += len;
|
||||||
|
row->line[row->size] = '\0';
|
||||||
|
|
||||||
|
erow_update(row);
|
||||||
|
editor.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
row_delete_ch(struct erow *row, int at)
|
row_delete_ch(struct erow *row, int at)
|
||||||
{
|
{
|
||||||
@@ -1807,9 +1842,32 @@ row_delete_ch(struct erow *row, int at)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
row_delete_block(struct erow *row, int at, size_t len)
|
||||||
|
{
|
||||||
|
if (at < 0 || at >= row->size || len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (at + (int)len > row->size) {
|
||||||
|
len = row->size - at;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(row->line + at, row->line + at + len,
|
||||||
|
row->size - (at + len) + 1);
|
||||||
|
row->size -= len;
|
||||||
|
row->line[row->size] = '\0';
|
||||||
|
|
||||||
|
erow_update(row);
|
||||||
|
editor.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
insertch(int16_t c)
|
insertch(int16_t c)
|
||||||
{
|
{
|
||||||
|
undo_begin(UNDO_INSERT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* insert_ch doesn't need to worry about how to update a
|
* insert_ch doesn't need to worry about how to update a
|
||||||
* a row; it can just figure out where the cursor is
|
* a row; it can just figure out where the cursor is
|
||||||
@@ -1826,6 +1884,7 @@ insertch(int16_t c)
|
|||||||
row_insert_ch(&editor.row[editor.cury],
|
row_insert_ch(&editor.row[editor.cury],
|
||||||
editor.curx,
|
editor.curx,
|
||||||
(int16_t)(c & 0xff));
|
(int16_t)(c & 0xff));
|
||||||
|
undo_append_char((char)c);
|
||||||
editor.curx++;
|
editor.curx++;
|
||||||
editor.dirty++;
|
editor.dirty++;
|
||||||
}
|
}
|
||||||
@@ -1852,9 +1911,12 @@ deletech(uint8_t op)
|
|||||||
dch = '\n';
|
dch = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
undo_begin(UNDO_DELETE);
|
||||||
|
|
||||||
if (editor.curx > 0) {
|
if (editor.curx > 0) {
|
||||||
row_delete_ch(row, editor.curx - 1);
|
row_delete_ch(row, editor.curx - 1);
|
||||||
editor.curx--;
|
editor.curx--;
|
||||||
|
undo_append_char(dch);
|
||||||
} else {
|
} else {
|
||||||
editor.curx = editor.row[editor.cury - 1].size;
|
editor.curx = editor.row[editor.cury - 1].size;
|
||||||
row_append_row(&editor.row[editor.cury - 1],
|
row_append_row(&editor.row[editor.cury - 1],
|
||||||
@@ -1866,6 +1928,7 @@ deletech(uint8_t op)
|
|||||||
delete_row(editor.cury);
|
delete_row(editor.cury);
|
||||||
editor.no_kill = prev;
|
editor.no_kill = prev;
|
||||||
editor.cury--;
|
editor.cury--;
|
||||||
|
undo_append_char('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == KILLRING_FLUSH) {
|
if (op == KILLRING_FLUSH) {
|
||||||
@@ -2378,8 +2441,10 @@ first_nonwhitespace(struct erow *row)
|
|||||||
void
|
void
|
||||||
move_cursor_once(int16_t c, int interactive)
|
move_cursor_once(int16_t c, int interactive)
|
||||||
{
|
{
|
||||||
struct erow *row;
|
struct erow *row;
|
||||||
int reps;
|
int reps = 0;
|
||||||
|
|
||||||
|
undo_commit();
|
||||||
|
|
||||||
row = (editor.cury >= editor.nrows) ? NULL : &editor.row[editor.cury];
|
row = (editor.cury >= editor.nrows) ? NULL : &editor.row[editor.cury];
|
||||||
|
|
||||||
@@ -2500,6 +2565,8 @@ newline(void)
|
|||||||
{
|
{
|
||||||
struct erow *row = NULL;
|
struct erow *row = NULL;
|
||||||
|
|
||||||
|
undo_begin(UNDO_NEWLINE);
|
||||||
|
|
||||||
if (editor.cury >= editor.nrows) {
|
if (editor.cury >= editor.nrows) {
|
||||||
erow_insert(editor.cury, "", 0);
|
erow_insert(editor.cury, "", 0);
|
||||||
editor.cury++;
|
editor.cury++;
|
||||||
@@ -2523,6 +2590,9 @@ newline(void)
|
|||||||
|
|
||||||
/* BREAK THE KILL CHAIN \m/ */
|
/* BREAK THE KILL CHAIN \m/ */
|
||||||
editor.kill = 0;
|
editor.kill = 0;
|
||||||
|
|
||||||
|
/* newlines aren't batched */
|
||||||
|
undo_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2584,6 +2654,8 @@ process_kcommand(int16_t c)
|
|||||||
int jumpy = 0;
|
int jumpy = 0;
|
||||||
int reps = 0;
|
int reps = 0;
|
||||||
|
|
||||||
|
undo_commit();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case BACKSPACE:
|
case BACKSPACE:
|
||||||
while (editor.curx > 0) {
|
while (editor.curx > 0) {
|
||||||
@@ -2775,6 +2847,8 @@ process_normal(int16_t c)
|
|||||||
{
|
{
|
||||||
int reps = 0;
|
int reps = 0;
|
||||||
|
|
||||||
|
undo_commit();
|
||||||
|
|
||||||
/* C-u handling – must be the very first thing */
|
/* C-u handling – must be the very first thing */
|
||||||
if (c == CTRL_KEY('u')) {
|
if (c == CTRL_KEY('u')) {
|
||||||
uarg_start();
|
uarg_start();
|
||||||
@@ -2876,6 +2950,8 @@ process_escape(int16_t c)
|
|||||||
{
|
{
|
||||||
editor_set_status("hi");
|
editor_set_status("hi");
|
||||||
|
|
||||||
|
undo_commit();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '>':
|
case '>':
|
||||||
editor.cury = editor.nrows;
|
editor.cury = editor.nrows;
|
||||||
|
|||||||
Reference in New Issue
Block a user