aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarno Mäkipää <jmakip87@gmail.com>2019-09-29 11:31:05 +0300
committerRob Landley <rob@landley.net>2019-10-04 16:20:41 -0500
commit3d0bb23d74f7ce3555dee6545a1e805aaf3d360e (patch)
treeca6d2aa962e840dc6c52dfc83e6b04f49951d0f3
parent38e5ab2b492b696656901d8121b60466a24d06c2 (diff)
downloadtoybox-3d0bb23d74f7ce3555dee6545a1e805aaf3d360e.tar.gz
vi: Scroll unmodified lines using escape codes
Scroll visual buffer up and down using standard escapes when content has not changed, instead of redrawing every keypress. Sidescroll now moves all the lines instead of only cursor one. Side scrolling long lines unfortunately causes redraw to whole screen. -Jarno
-rw-r--r--toys/pending/vi.c141
1 files changed, 86 insertions, 55 deletions
diff --git a/toys/pending/vi.c b/toys/pending/vi.c
index 50b8f0ab..9334e033 100644
--- a/toys/pending/vi.c
+++ b/toys/pending/vi.c
@@ -22,6 +22,9 @@ config VI
GLOBALS(
int cur_col;
int cur_row;
+ int scr_row;
+ int drawn_row;
+ int drawn_col;
unsigned screen_height;
unsigned screen_width;
int vi_mode;
@@ -91,6 +94,8 @@ struct yank_buf yank; //single yank
// 0x1 = Command needs argument (f,F,r...)
// 0x2 = Move 1 right on yank/delete/insert (e, $...)
// 0x4 = yank/delete last line fully
+// 0x10000000 = redraw after cursor needed
+// 0x20000000 = full redraw needed
// 0x40000000 = count0 not given
// 0x80000000 = move was reverse
@@ -211,7 +216,6 @@ int vi_dd(char reg, int count0, int count1)
vi_delete(reg, pos, 0, 0);
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}
@@ -287,7 +291,6 @@ next_line:
return vi_movw(count, 1, 0);
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}
@@ -319,7 +322,6 @@ exit_function:
return vi_movb(count, 1, 0);
TT.vi_mov_flag |= 0x80000000;
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}
@@ -338,7 +340,6 @@ static int vi_move(int count0, int count1, char *unused)
TT.vi_mov_flag |= 2;
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}
@@ -388,7 +389,6 @@ void i_split()
c_r->line = l;
TT.cur_col = 0;
check_cursor_bounds();
- adjust_screen_buffer();
}
@@ -415,10 +415,12 @@ static int vi_eol(int count0, int count1, char *unused)
//TODO check register where to push from
static int vi_push(char reg, int count0, int count1)
{
- char *start = yank.data;
- char *end = yank.data+strlen(yank.data);
+ char *start = yank.data, *end = yank.data+strlen(yank.data);
+ struct linelist *cursor = c_r;
+ int col = TT.cur_col;
//insert into new lines
if (*(end-1) == '\n') for (;start != end;) {
+ TT.vi_mov_flag |= 0x10000000;
char *next = strchr(start, '\n');
vi_eol(1, 1, 0);
i_split();
@@ -432,6 +434,7 @@ static int vi_push(char reg, int count0, int count1)
else for (;start != end;) {
char *next = strchr(start, '\n');
if (next) {
+ TT.vi_mov_flag |= 0x10000000;
i_insert(start, next-start);
i_split();
start = next+1;
@@ -440,6 +443,10 @@ static int vi_push(char reg, int count0, int count1)
start = end;
}
}
+ //if row changes during push original cursor position is kept
+ //vi inconsistancy
+ if (c_r != cursor) c_r = cursor, TT.cur_col = col;
+
return 1;
}
@@ -475,7 +482,6 @@ static int vi_go(int count0, int count1, char *symbol)
TT.cur_col = 0;
check_cursor_bounds(); //adjusts cursor column
- adjust_screen_buffer(); //adjusts screen buffer
if (prev_row>TT.cur_row) TT.vi_mov_flag |= 0x80000000;
return 1;
@@ -505,6 +511,7 @@ static int vi_delete(char reg, struct linelist *row, int col, int flags)
start = start->down;
full_line_delete:
+ TT.vi_mov_flag |= 0x10000000;
for (;start != end;) {
struct linelist* lst = start;
//struct linelist *lst = dlist_pop(&start);
@@ -518,6 +525,7 @@ full_line_delete:
free(lst);
}
last_line_delete:
+ TT.vi_mov_flag |= 0x10000000;
if (TT.vi_mov_flag&2) col_e = start->line->str_len;
if (TT.vi_mov_flag&4) {
if (!end->down && !end->up)
@@ -813,7 +821,6 @@ static int search_str(char *s)
c_r = lst;
TT.cur_col = c-c_r->line->str_data;
check_cursor_bounds();
- adjust_screen_buffer();
return 0;
}
@@ -882,6 +889,7 @@ void vi_main(void)
tty_esc("?1049h");
tty_esc("H");
xflush(1);
+ TT.vi_mov_flag = 0x20000000;
draw_page();
while(1) {
int key = scan_key(keybuf, -1);
@@ -1080,7 +1088,7 @@ int crunch_nstr(char **str, int width, int n, FILE *out, char *escmore,
static void draw_page()
{
- struct linelist *scr_buf = scr_r;
+ struct linelist *scr_buf = 0;
unsigned y = 0;
int x = 0;
@@ -1093,26 +1101,26 @@ static void draw_page()
//variables used only for cursor handling
int aw = 0, iw = 0, clip = 0, margin = 8;
- //clear screen
- tty_esc("2J");
- tty_esc("H");
+ int scroll = 0, redraw = 0;
- //draw lines until cursor row
+ adjust_screen_buffer();
+ scr_buf = scr_r;
+ redraw = (TT.vi_mov_flag & 0x30000000)>>28;
+
+ scroll = TT.drawn_row-TT.scr_row;
+ if (TT.drawn_row<0 || TT.cur_row<0 || TT.scr_row<0) redraw = 3;
+ else if (abs(scroll)>TT.screen_height/2) redraw = 3;
+
+ tty_jump(0, 0);
+ if (redraw&2) tty_esc("2J"), tty_esc("H"); //clear screen
+ else if (scroll>0) printf("\033[%dL", scroll); //scroll up
+ else if (scroll<0) printf("\033[%dM", -scroll); //scroll down
+
+ //jump until cursor
for (; y < TT.screen_height; y++ ) {
- tty_jump(0, y);
- if (scr_buf == c_r)
- break;
- if (scr_buf) {
- if (scr_buf->line->str_data && scr_buf->line->str_len) {
- line = scr_buf->line->str_data;
- bytes = scr_buf->line->str_len;
- scr_buf = scr_buf->down;
- crunch_str(&line, TT.screen_width-1, stdout, "\t", vi_crunch);
- if ( *line ) printf("@");
- } else scr_buf = scr_buf->down;
- }
+ if (scr_buf == c_r) break;
+ scr_buf = scr_buf->down;
}
-
//draw cursor row
/////////////////////////////////////////////////////////////
//for long lines line starts to scroll when cursor hits margin
@@ -1120,10 +1128,12 @@ static void draw_page()
bytes = TT.cur_col;
end = line;
+
+ tty_jump(0, y);
+ tty_esc("2K");
//find cursor position
aw = crunch_nstr(&end, 1024, bytes, 0, "\t", vi_crunch);
-
//if we need to render text that is not inserted to buffer yet
if (TT.vi_mode == 2 && il->str_len) {
char* iend = il->str_data; //input end
@@ -1167,26 +1177,52 @@ static void draw_page()
x += crunch_str(&end, TT.screen_width-x, stdout, "\t", vi_crunch);
}
- tty_jump(0, ++y);
if (scr_buf) scr_buf = scr_buf->down;
// drawing cursor row ends
///////////////////////////////////////////////////////////////////
-//draw until end
+ //start drawing all other rows that needs update
+ ///////////////////////////////////////////////////////////////////
+ y = 0, scr_buf = scr_r;
+
+ //if we moved around in long line might need to redraw everything
+ if (clip != TT.drawn_col) redraw = 3;
+
for (; y < TT.screen_height; y++ ) {
+ int draw_line = 0;
+ if (scr_buf == c_r) {
+ scr_buf = scr_buf->down;
+ continue;
+ } else if (redraw) draw_line++;
+ else if (scroll<0 && TT.screen_height-y-1<-scroll)
+ scroll++, draw_line++;
+ else if (scroll>0) scroll--, draw_line++;
+
tty_jump(0, y);
- if (scr_buf) {
- if (scr_buf->line->str_data && scr_buf->line->str_len) {
- line = scr_buf->line->str_data;
- bytes = scr_buf->line->str_len;
- scr_buf = scr_buf->down;
- crunch_str(&line, TT.screen_width-1, stdout, "\t", vi_crunch);
- if ( *line ) printf("@");
- } else scr_buf = scr_buf->down;
- } else printf("~");
+ if (draw_line) {
+
+ tty_esc("2K");
+ if (scr_buf) {
+ if (draw_line && scr_buf->line->str_data && scr_buf->line->str_len) {
+ line = scr_buf->line->str_data;
+ bytes = scr_buf->line->str_len;
+
+ aw = crunch_nstr(&line, clip, bytes, 0, "\t", vi_crunch);
+ crunch_str(&line, TT.screen_width-1, stdout, "\t", vi_crunch);
+ if ( *line ) printf("@");
+
+ }
+ } else if (draw_line) printf("~");
+ }
+ if (scr_buf) scr_buf = scr_buf->down;
}
+ TT.drawn_row = TT.scr_row, TT.drawn_col = clip;
+
+ //finished updating visual area
+
tty_jump(0, TT.screen_height);
+ tty_esc("2K");
switch (TT.vi_mode) {
case 0:
tty_esc("30;44m");
@@ -1214,10 +1250,12 @@ static void draw_page()
tty_jump(TT.screen_width-12, TT.screen_height);
printf("| %d, %d\n", TT.cur_row, TT.cur_col);
+
tty_esc("m");
+ tty_jump(0, TT.screen_height+1);
+ tty_esc("2K");
if (!TT.vi_mode) {
tty_esc("1m");
- tty_jump(0, TT.screen_height+1);
printf("%s", il->str_data);
tty_esc("m");
} else tty_jump(cx_scr, cy_scr);
@@ -1243,28 +1281,23 @@ static void adjust_screen_buffer()
struct linelist *t = text;
int c = -1, s = -1, i = 0;
//searching cursor and screen line numbers
- for (;;) {
- i++;
+ for (;((c == -1) || (s == -1)) && t != 0; i++, t = t->down) {
if (t == c_r) c = i;
if (t == scr_r) s = i;
-
- t = t->down;
- if ( ((c != -1) && (s != -1)) || t == 0)
- break;
}
//adjust screen buffer so cursor is on drawing area
- if (c <= s) scr_r = c_r; //scroll up
- else if (c > s) {
+ if (c <= s) scr_r = c_r, s = c; //scroll up
+ else {
//drawing does not have wrapping so no need to check width
- int distance = c - s + 1;
+ int distance = c-s+1;
- if (distance >= (int)TT.screen_height) {
- int adj = distance - TT.screen_height;
- while (adj--) scr_r = scr_r->down; //scroll down
+ if (distance > (int)TT.screen_height) {
+ int adj = distance-TT.screen_height;
+ for (;adj; adj--) scr_r = scr_r->down, s++; //scroll down
}
}
- TT.cur_row = c;
+ TT.cur_row = c, TT.scr_row = s;
}
@@ -1410,7 +1443,6 @@ static int cur_up(int count0, int count1, char* unused)
TT.vi_mov_flag |= 0x80000000;
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}
@@ -1421,7 +1453,6 @@ static int cur_down(int count0, int count1, char* unused)
c_r = c_r->down;
check_cursor_bounds();
- adjust_screen_buffer();
return 1;
}