preliminary support for undo - gramscii - A simple editor for ASCII box-and-arr… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit 526ce3a130732d4a2374a6e36a689d9e0cf5cc34 | |
parent 6da2f3f89afda08eeba385da1c36414154113d47 | |
Author: KatolaZ <[email protected]> | |
Date: Wed, 31 Jul 2019 00:10:35 +0100 | |
preliminary support for undo | |
Diffstat: | |
M TODO | 2 +- | |
M draw.c | 55 ++++++++++++++++++++++++++++-… | |
M gramscii.h | 13 ++++++++++++- | |
M lineset.c | 43 ++++++++++++++++++++++++++++++ | |
M main.c | 6 ++++++ | |
M screen.c | 4 ++++ | |
6 files changed, 117 insertions(+), 6 deletions(-) | |
--- | |
diff --git a/TODO b/TODO | |
@@ -1,4 +1,5 @@ | |
+ optimize redraws (redraw only the modified rectangle) | |
++ undo (by storing lines changed across insert/remove operations) | |
- fix bug with 'g' commands in arrow mode | |
- add screen geometry option (-g 25x80?) | |
- read file at point | |
@@ -18,7 +19,6 @@ | |
* yank | |
* fill | |
* cut | |
-- undo (by storing lines changed across insert/remove operations) | |
- manage special chars (DEL/CANC) during text insert | |
(also do not print unmanaged chars!) | |
- allow scrolling (both vertical and horizontal) | |
diff --git a/draw.c b/draw.c | |
@@ -1,4 +1,5 @@ | |
#include <stdlib.h> | |
+#include <string.h> | |
#include "gramscii.h" | |
#include "config.h" | |
@@ -103,16 +104,19 @@ void draw_box(int x1, int y1, int fix){ | |
int i; | |
void (*f)(int, int, char); | |
- if (fix == FIX) | |
- f = set_xy; | |
- else | |
- f = draw_xy; | |
xmin = MIN(x, x1); | |
xmax = MAX(x, x1); | |
ymin = MIN(y, y1); | |
ymax = MAX(y, y1); | |
+ if (fix == FIX){ | |
+ f = set_xy; | |
+ copy_lines_to_ring(ymin, ymax, CUR); | |
+ } | |
+ else | |
+ f = draw_xy; | |
+ | |
for(i=xmin+1; i<=xmax; i++){ | |
f(i, ymin, line_h); | |
f(i, ymax, line_h); | |
@@ -125,6 +129,8 @@ void draw_box(int x1, int y1, int fix){ | |
f(xmin, ymax, corner); | |
f(xmax, ymin, corner); | |
f(xmax, ymax, corner); | |
+ if (fix == FIX) | |
+ copy_lines_to_ring(ymin, ymax, LST); | |
show_cursor(); | |
} | |
@@ -157,6 +163,7 @@ update_box: | |
void draw_arrow(int x, int y, char *a, int a_len, int fix){ | |
+ /* FIXME: copy affected lines to undo */ | |
int i, j, cur_dir; | |
char line; | |
void (*f)(int, int, char); | |
@@ -266,6 +273,7 @@ void do_erase(int x1, int y1){ | |
void erase(FILE *fc){ | |
+ /*FIXME: add affected lines to undo */ | |
char c; | |
int orig_x = x, orig_y = y; | |
status_bar(); | |
@@ -308,8 +316,11 @@ void visual_box(FILE *fc){ | |
case 'x':/* erase */ | |
if (c == 'x') | |
yank_region(MIN(orig_x,x), MIN(orig_y,… | |
+ copy_lines_to_ring(MIN(orig_y, y), MAX(orig_y,… | |
erase_box(orig_x, orig_y, f); | |
erase_blank_lines(MIN(y,orig_y), MAX(y, orig_y… | |
+ copy_lines_to_ring(MIN(orig_y, y), MAX(orig_y,… | |
+ | |
modified = 1; | |
goto vis_exit; | |
break; | |
@@ -331,6 +342,42 @@ vis_exit: | |
} | |
void paste(){ | |
+ int y2; | |
+ | |
+ y2 = y + cutbuf.num - 1; | |
+ copy_lines_to_ring(y, y2, CUR); | |
paste_region(x, y); | |
+ copy_lines_to_ring(y, y2, LST); | |
+ redraw(); | |
+} | |
+ | |
+void put_lines(lineset_t *u){ | |
+ int i, n; | |
+ | |
+ for (i=0; i< u->num; i++){ | |
+ n = u->l[i].n; | |
+ ensure_line_length(&(screen.l[i]), u->l[i].lst); | |
+ strcpy(screen.l[n].s, u->l[i].s); | |
+ screen.l[n].lst = u->l[i].lst; | |
+ } | |
+} | |
+ | |
+ | |
+void undo_change(){ | |
+ if (undo_cur >= 0){ | |
+ put_lines(& (undo[undo_cur])); | |
+ undo_cur --; | |
+ } | |
+ redraw(); | |
+ modified = 1; | |
+} | |
+ | |
+void redo_change(){ | |
+ if (undo_cur < undo_lst){ | |
+ undo_cur ++; | |
+ put_lines(& (undo[undo_cur])); | |
+ } | |
redraw(); | |
+ modified = 1; | |
} | |
+ | |
diff --git a/gramscii.h b/gramscii.h | |
@@ -44,6 +44,9 @@ | |
#define VIDEO_NRM 0 | |
#define VIDEO_REV 7 | |
+#define CUR 0x01 | |
+#define LST 0x02 | |
+ | |
/** types **/ | |
typedef struct{ | |
@@ -59,6 +62,7 @@ typedef struct{ | |
line_t *l; | |
} lineset_t; | |
+ | |
/** MACROS **/ | |
#define MIN(x,y) (x) < (y) ? (x) : (y) | |
@@ -73,6 +77,11 @@ typedef struct{ | |
lineset_t screen; | |
lineset_t cutbuf; | |
+lineset_t *undo; | |
+ | |
+int undo_sz; | |
+int undo_cur; | |
+int undo_lst; | |
int WIDTH, HEIGHT; | |
@@ -155,6 +164,8 @@ void ensure_line_length(line_t *l, int len); | |
void ensure_num_lines(lineset_t *ls, int n); | |
void yank_region(int x1, int y1, int x2, int y2); | |
void paste_region(int x1, int y1); | |
- | |
+void copy_lines_to_ring(int y1, int y2, int which); | |
+void undo_change(); | |
+void redo_change(); | |
#endif | |
diff --git a/lineset.c b/lineset.c | |
@@ -58,6 +58,7 @@ void ensure_num_lines(lineset_t *ls, int n){ | |
} | |
} | |
+ | |
void dump_lines(lineset_t ls, FILE *f){ | |
int i; | |
for (i=0; i<ls.num ;i++){ | |
@@ -124,3 +125,45 @@ void paste_region(int x1, int y1){ | |
} | |
redraw(); | |
} | |
+ | |
+void copy_lines_to_ring(int y1, int y2, int which){ | |
+ lineset_t *tmp; | |
+ int i, len, *idx; | |
+ | |
+ if (y1 > y2){ | |
+ y1 ^= y2; | |
+ y2 ^= y1; | |
+ y1 ^= y2; | |
+ } | |
+ if (which == CUR) | |
+ idx = &undo_cur; | |
+ else | |
+ idx = &undo_lst; | |
+ if (*idx == undo_sz - 1){ | |
+ undo_sz += 10; | |
+ tmp = realloc(undo, undo_sz * sizeof(lineset_t)); | |
+ if (tmp == NULL){ | |
+ fprintf(stderr, "Error allocating undo buffer"); | |
+ exit(1); | |
+ } | |
+ undo = tmp; | |
+ } | |
+ (*idx) ++; | |
+ ensure_num_lines(&(undo[*idx]), y2 - y1 + 1); | |
+ for(i=y1; i<=y2; i++){ | |
+ len = strlen(screen.l[i].s); | |
+ ensure_line_length(&(undo[*idx].l[i-y1]), len); | |
+ strcpy(undo[*idx].l[i-y1].s, screen.l[i].s); | |
+ undo[*idx].l[i-y1].n = i; | |
+ undo[*idx].l[i-y1].lst = screen.l[i].lst; | |
+ } | |
+ undo[*idx].num = y2 - y1 + 1; | |
+ if (which == CUR) | |
+ undo_lst = undo_cur; | |
+#ifdef DEBUG | |
+ fprintf(stderr, "undo_ring: y1: %d y2: %d idx: %d\n", y1, y2, *idx); | |
+ for(i=0; i<undo[undo_cur].num; i++){ | |
+ fprintf(stderr, "UU: %d| %s\n", undo[*idx].l[i].n, undo[*idx].… | |
+ } | |
+#endif | |
+} | |
diff --git a/main.c b/main.c | |
@@ -122,6 +122,12 @@ void commands(FILE *fc){ | |
case 'p': | |
paste(); | |
break; | |
+ case 'u': | |
+ undo_change(); | |
+ break; | |
+ case 'U': | |
+ redo_change(); | |
+ break; | |
case 'q': | |
check_modified(fc);/** FALLTHROUGH **/ | |
case 'Q': | |
diff --git a/screen.c b/screen.c | |
@@ -408,6 +408,10 @@ void init_screen(){ | |
cutbuf.sz = 0; | |
cutbuf.l = NULL; | |
cutbuf.num = 0; | |
+ | |
+ undo_sz = 0; | |
+ undo_cur = -1; | |
+ undo_lst = -1; | |
} | |
void find_nonblank_rect(int *x1, int *y1, int *x2, int *y2){ |