aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarno Mäkipää <jmakip87@gmail.com>2019-04-13 15:25:59 +0300
committerRob Landley <rob@landley.net>2019-04-22 14:49:33 -0500
commit580a88f1a60c7f990cca703f54b8815fca1e918e (patch)
treec6612133afcfec736e82113738e5d4eb848a25b3
parent99bca934a1fef61753dcdb582003dc7d56150031 (diff)
downloadtoybox-580a88f1a60c7f990cca703f54b8815fca1e918e.tar.gz
vi.c changes to vi cmd execution
Reimplemented to command mode execution to follow vi cmd pattern. (REG)[COUNT0]{CMD}[COUNT1]<MOV>(SYM) Most of the moves can be executed intependently or before command, some require character after. (possibly with utf8) Some of the commands do not require move, such as D, J, dd, yy, x... There is also tons of special cases where move behaves differently depending on command. For example 1cw and 1ce appear to be the same but 1dw and 1de are not... Most of the operations still need reimplementing and lots of cleanup in order them to behave correctly refactored word move to work with utf-8
-rw-r--r--toys/pending/vi.c390
1 files changed, 320 insertions, 70 deletions
diff --git a/toys/pending/vi.c b/toys/pending/vi.c
index 2beedf49..f7edc074 100644
--- a/toys/pending/vi.c
+++ b/toys/pending/vi.c
@@ -25,6 +25,11 @@ GLOBALS(
unsigned screen_height;
unsigned screen_width;
int vi_mode;
+ int count0;
+ int count1;
+ int vi_mov_flag;
+ int modified;
+ char vi_reg;
)
/*
@@ -38,9 +43,6 @@ GLOBALS(
* ex callbacks
*
* FEATURE: ex: / ? % //atleast easy cases
- * vi: x dw d$ d0
- * vi: yw yy (y0 y$)
- * vi+ex: gg G //line movements
* ex: r
* ex: !external programs
* ex: w filename //only writes to same file now
@@ -59,17 +61,17 @@ static int draw_str_until(int *drawn, char *str, int width, int bytes);
static void draw_char(char c, int x, int y, int highlight);
//utf8 support
static int utf8_lnw(int* width, char* str, int bytes);
-static int utf8_dec(char key, char *utf8_scratch, int *sta_p) ;
+static int utf8_dec(char key, char *utf8_scratch, int *sta_p);
static int utf8_len(char *str);
static int utf8_width(char *str, int bytes);
static int draw_rune(char *c, int x, int y, int highlight);
static char* utf8_last(char* str, int size);
-static int cur_left(int count);
-static int cur_right(int count);
-static int cur_up(int count);
-static int cur_down(int count);
+static int cur_left(int count0, int count1, char* unused);
+static int cur_right(int count0, int count1, char* unused);
+static int cur_up(int count0, int count1, char* unused);
+static int cur_down(int count0, int count1, char* unused);
static void check_cursor_bounds();
static void adjust_screen_buffer();
@@ -92,7 +94,7 @@ struct str_line *il;
struct linelist *text; //file loaded into buffer
struct linelist *scr_r;//current screen coord 0 row
struct linelist *c_r;//cursor position row
-int modified;
+
void dlist_insert_nomalloc(struct double_list **list, struct double_list *new)
{
@@ -114,6 +116,7 @@ struct double_list *dlist_insert(struct double_list **list, char *data)
return new;
}
+//TODO implement
void linelist_unload()
{
@@ -126,7 +129,7 @@ void write_file(char *filename)
if (!filename)
filename = (char*)*toys.optargs;
fp = fopen(filename, "w");
- if (!fp) return ;
+ if (!fp) return;
while (lst) {
fprintf(fp, "%s\n", lst->line->str_data);
lst = lst->down;
@@ -188,9 +191,16 @@ int linelist_load(char *filename)
return 1;
}
+
+int vi_yy(char reg, int count0, int count1)
+{
+ return 1;
+}
+
//TODO this is overly complicated refactor with lib dllist
-int ex_dd(int count)
+int vi_dd(char reg, int count0, int count1)
{
+ int count = count0*count1;
struct linelist *lst = c_r;
if (c_r == text && text == scr_r) {
if (!text->down && !text->up && text->line) {
@@ -235,26 +245,17 @@ int ex_dd(int count)
recursion_exit:
count--;
//make this recursive
- if (count)
- return ex_dd(count);
+ if (count>0)
+ return vi_dd(reg, count, 1);
success_exit:
check_cursor_bounds();
adjust_screen_buffer();
return 1;
}
-
-int ex_dw(int count)
-{
- return 1;
-}
-
-int ex_deol(int count)
-{
- return 1;
-}
-
-int vi_x(int count)
+//TODO i think this thing has bug when removing >40 chars from 80 wide line
+static int vi_x(char reg, int count0, int count1)
{
+ int count = count0;
char *s;
char *last;
int *l;
@@ -293,7 +294,7 @@ int vi_x(int count)
}
if (remaining) {
memmove(start, end, remaining);
- memset(end+remaining,0,end-start);
+ memset(start+remaining,0,end-start);
} else {
memset(start,0,(*l)-TT.cur_col);
}
@@ -307,34 +308,55 @@ int vi_x(int count)
}
//move commands does not behave correct way yet.
-//only jump to next space for now.
-int vi_movw(int count)
+int vi_movw(int count0, int count1, char* unused)
{
+ int count = count0*count1;
+ const char *empties = " \t\n\r";
+ const char *specials = ",.=-+*/(){}<>[]";
+// char *current = 0;
if (!c_r)
return 0;
- //could we call moveend first
- while (c_r->line->str_data[TT.cur_col] > ' ')
- TT.cur_col++;
- while (c_r->line->str_data[TT.cur_col] <= ' ') {
+ if (TT.cur_col == c_r->line->str_len-1 || !c_r->line->str_len)
+ goto next_line;
+ if (strchr(empties, c_r->line->str_data[TT.cur_col]))
+ goto find_non_empty;
+ if (strchr(specials, c_r->line->str_data[TT.cur_col])) {
+ for (;strchr(specials, c_r->line->str_data[TT.cur_col]); ) {
+ TT.cur_col++;
+ if (TT.cur_col == c_r->line->str_len-1)
+ goto next_line;
+ }
+ } else for (;!strchr(specials, c_r->line->str_data[TT.cur_col]) &&
+ !strchr(empties, c_r->line->str_data[TT.cur_col]);) {
+ TT.cur_col++;
+ if (TT.cur_col == c_r->line->str_len-1)
+ goto next_line;
+ }
+
+ for (;strchr(empties, c_r->line->str_data[TT.cur_col]); ) {
TT.cur_col++;
- if (!c_r->line->str_data[TT.cur_col]) {
+find_non_empty:
+ if (TT.cur_col == c_r->line->str_len-1) {
+next_line:
//we could call j and g0
if (!c_r->down) return 0;
c_r = c_r->down;
TT.cur_col = 0;
+ if (!c_r->line->str_len) break;
}
}
count--;
- if (count>1)
- return vi_movw(count);
+ if (count>0)
+ return vi_movw(count, 1, 0);
check_cursor_bounds();
adjust_screen_buffer();
return 1;
}
-int vi_movb(int count)
+static int vi_movb(int count0, int count1, char* unused)
{
+ int count = count0*count1;
if (!c_r)
return 0;
if (!TT.cur_col) {
@@ -357,24 +379,26 @@ int vi_movb(int count)
exit_function:
count--;
if (count>1)
- return vi_movb(count);
+ return vi_movb(count, 1, 0);
check_cursor_bounds();
adjust_screen_buffer();
return 1;
}
-int vi_move(int count)
+static int vi_move(int count0, int count1, char *unused)
{
+ int count = count0*count1;
if (!c_r)
return 0;
if (TT.cur_col < c_r->line->str_len)
TT.cur_col++;
if (c_r->line->str_data[TT.cur_col] <= ' ' || count > 1)
- vi_movw(count); //find next word;
+ vi_movw(count, 1, 0); //find next word;
while (c_r->line->str_data[TT.cur_col] > ' ')
TT.cur_col++;
if (TT.cur_col) TT.cur_col--;
+ TT.vi_mov_flag |= 2;
check_cursor_bounds();
adjust_screen_buffer();
return 1;
@@ -426,46 +450,266 @@ void i_split()
adjust_screen_buffer();
}
+static int vi_zero(int count0, int count1, char *unused)
+{
+ TT.cur_col = 0;
+ return 1;
+}
+
+static int vi_eol(int count0, int count1, char *unused)
+{
+ int count = count0*count1;
+ for (;count > 1 && c_r->down; count--)
+ c_r = c_r->down;
+
+ if (c_r && c_r->line->str_len)
+ TT.cur_col = c_r->line->str_len-1;
+ TT.vi_mov_flag |= 2;
+ check_cursor_bounds();
+ return 1;
+}
+
+static int vi_find_c(int count0, int count1, char *symbol)
+{
+ int count = count0*count1;
+ if (c_r && c_r->line->str_len) {
+ while (count--) {
+ char* pos = strstr(&c_r->line->str_data[TT.cur_col], symbol);
+ if (pos) {
+ TT.cur_col = pos-c_r->line->str_data;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int vi_find_cb(int count0, int count1, char *symbol)
+{
+ //do backward search
+ return 1;
+}
+
+//if count is not spesified should go to last line
+static int vi_go(int count0, int count1, char *symbol)
+{
+ c_r = text;
+ while(--count0) {
+ if (c_r && c_r->down) c_r = c_r->down;
+ }
+ TT.cur_col = 0;
+ check_cursor_bounds();
+ adjust_screen_buffer();
+ return 1;
+}
+
+//need to refactor when implementing yank buffers
+static int vi_delete(char reg, struct linelist *row, int col, int flags)
+{
+ if (row == c_r) {
+ if (col < TT.cur_col) {
+ int distance = TT.cur_col - col;
+ TT.cur_col = col;
+ vi_x(reg, distance, 1);
+ } else {
+ int distance = col - TT.cur_col;
+ if (distance > 0) vi_x(reg, distance, 1);
+ }
+ if (TT.vi_mov_flag&2)
+ vi_x(reg, 1, 1);
+ }
+ return 1;
+}
+
+static int vi_D(char reg, int count0, int count1)
+{
+ int prev_col = TT.cur_col;
+ struct linelist *pos = c_r;
+ if (!count0) return 1;
+ vi_eol(1, 1, 0);
+ vi_delete(reg, pos, prev_col, 0);
+ count0--;
+ if (count0 && c_r->down) {
+ c_r = c_r->down;
+ vi_dd(reg, count0, 1);
+ }
+ return 1;
+}
+
+static int vi_join(char reg, int count0, int count1)
+{
+ while (count0--) {
+ if (c_r && c_r->down) {
+ int size = c_r->line->str_len+c_r->down->line->str_len;
+ if (size > c_r->line->alloc_len) {
+ if (size > c_r->down->line->alloc_len) {
+ c_r->line->str_data = xrealloc(c_r->line->str_data,
+ c_r->line->alloc_len*2+il->alloc_len*2);
+ memmove(&c_r->line->str_data[c_r->line->str_len],
+ c_r->down->line->str_data,c_r->down->line->str_len);
+ c_r->line->str_len = size;
+ c_r = c_r->down;
+ c_r->line->alloc_len = c_r->line->alloc_len*2+2*il->alloc_len;
+ vi_dd(0,1,1);
+ } else {
+ memmove(&c_r->down->line->str_data[c_r->line->str_len],
+ c_r->down->line->str_data,c_r->down->line->str_len);
+ memmove(c_r->down->line->str_data,c_r->line->str_data,
+ c_r->line->str_len);
+ c_r->down->line->str_len = size;
+ vi_dd(0,1,1);
+ }
+ } else {
+ memmove(&c_r->line->str_data[c_r->line->str_len],
+ c_r->down->line->str_data,c_r->down->line->str_len);
+ c_r->line->str_len = size;
+ c_r = c_r->down;
+ vi_dd(0,1,1);
+ }
+ c_r = c_r->up;
+
+ }
+ }
+ return 1;
+}
+
+static int vi_change(char reg, struct linelist *row, int col, int flags)
+{
+ vi_delete(reg, row, col, flags);
+ TT.vi_mode = 2;
+ return 1;
+}
+
+static int vi_yank(char reg, struct linelist *row, int col, int flags)
+{
+ return 1;
+}
+
+//NOTES
+//vi-mode cmd syntax is
+//("[REG])[COUNT0]CMD[COUNT1](MOV)
+//where:
+//-------------------------------------------------------------
+//"[REG] is optional buffer where deleted/yanked text goes REG can be
+// atleast 0-9, a-z or default "
+//[COUNT] is optional multiplier for cmd execution if there is 2 COUNT
+// operations they are multiplied together
+//CMD is operation to be executed
+//(MOV) is movement operation, some CMD does not require MOV and some
+// have special cases such as dd, yy, also movements can work without
+// CMD
+//ex commands can be even more complicated than this....
+//
struct vi_cmd_param {
+ const char* cmd;
+ unsigned flags;
+ int (*vi_cmd)(char, struct linelist*, int, int);//REG,row,col,FLAGS
+};
+struct vi_mov_param {
+ const char* mov;
+ unsigned flags;
+ int (*vi_mov)(int, int, char*);//COUNT0,COUNT1,params
+};
+//spesial cases without MOV and such
+struct vi_spesial_param {
const char *cmd;
- int (*vi_cmd_ptr)(int);
+ int (*vi_spesial)(char, int, int);//REG,COUNT0,COUNT1
};
-
-struct vi_cmd_param vi_cmds[11] =
+struct vi_spesial_param vi_spesial[5] =
{
- {"dd", &ex_dd},
- {"dw", &ex_dw},
- {"d$", &ex_deol},
- {"w", &vi_movw},
- {"b", &vi_movb},
- {"e", &vi_move},
+ {"dd", &vi_dd},
+ {"yy", &vi_yy},
+ {"D", &vi_D},
+ {"J", &vi_join},
{"x", &vi_x},
- {"h", &cur_left},
- {"j", &cur_down},
- {"k", &cur_up},
- {"l", &cur_right},
+};
+//there is around ~47 vi moves
+//some of them need extra params
+//such as f and '
+struct vi_mov_param vi_movs[12] =
+{
+ {"0", 0, &vi_zero},
+ {"b", 0, &vi_movb},
+ {"e", 0, &vi_move},
+ {"G", 0, &vi_go},
+ {"h", 0, &cur_left},
+ {"j", 0, &cur_down},
+ {"k", 0, &cur_up},
+ {"l", 0, &cur_right},
+ {"w", 0, &vi_movw},
+ {"$", 0, &vi_eol},
+ {"f", 1, &vi_find_c},
+ {"F", 1, &vi_find_cb},
+};
+//change and delete unfortunately behave different depending on move command,
+//such as ce cw are same, but dw and de are not...
+//also dw stops at w position and cw seem to stop at e pos+1...
+//so after movement we need to possibly set up some flags before executing
+//command, and command needs to adjust...
+struct vi_cmd_param vi_cmds[3] =
+{
+ {"c", 1, &vi_change},
+ {"d", 1, &vi_delete},
+ {"y", 1, &vi_yank},
};
int run_vi_cmd(char *cmd)
{
+ int i = 0;
int val = 0;
char *cmd_e;
- errno = 0;
- int i = 0;
+ int (*vi_cmd)(char, struct linelist*, int, int) = 0;
+ int (*vi_mov)(int, int, char*) = 0;
+ TT.count0 = 0;
+ TT.count1 = 0;
+ TT.vi_reg = '"';
+ TT.vi_mov_flag = 0;
+ if (*cmd == '"') {
+ cmd++;
+ TT.vi_reg = *cmd; //TODO check validity
+ cmd++;
+ }
val = strtol(cmd, &cmd_e, 10);
- if (errno || val == 0) {
- val = 1;
+ if (errno || val == 0) val = 1;
+ else cmd = cmd_e;
+ TT.count0 = val;
+
+ for (i = 0; i < 5; i++) {
+ if (strstr(cmd, vi_spesial[i].cmd)) {
+ return vi_spesial[i].vi_spesial(TT.vi_reg, TT.count0, TT.count1);
+ }
}
- else {
- cmd = cmd_e;
+
+ for (i = 0; i < 3; i++) {
+ if (!strncmp(cmd, vi_cmds[i].cmd, strlen(vi_cmds[i].cmd))) {
+ vi_cmd = vi_cmds[i].vi_cmd;
+ cmd += strlen(vi_cmds[i].cmd);
+ break;
+ }
}
- for (; i < 11; i++) {
- if (strstr(cmd, vi_cmds[i].cmd)) {
- return vi_cmds[i].vi_cmd_ptr(val);
+ val = strtol(cmd, &cmd_e, 10);
+ if (errno || val == 0) val = 1;
+ else cmd = cmd_e;
+ TT.count1 = val;
+
+ for (i = 0; i < 12; i++) {
+ if (!strncmp(cmd, vi_movs[i].mov, strlen(vi_movs[i].mov))) {
+ vi_mov = vi_movs[i].vi_mov;
+ TT.vi_mov_flag = vi_movs[i].flags;
+ cmd++;
+ if (TT.vi_mov_flag&1 && !(*cmd)) return 0;
+ break;
}
}
+ if (vi_mov) {
+ int prev_col = TT.cur_col;
+ struct linelist *pos = c_r;
+ if (vi_mov(TT.count0, TT.count1, cmd)) {
+ if (vi_cmd) return (vi_cmd(TT.vi_reg, pos, prev_col, TT.vi_mov_flag));
+ else return 1;
+ } else return 0; //return some error
+ }
return 0;
-
}
int search_str(char *s)
@@ -669,6 +913,7 @@ void vi_main(void)
}
cleanup_vi:
+ linelist_unload();
tty_reset();
tty_esc("?1049l");
}
@@ -858,8 +1103,8 @@ static void check_cursor_bounds()
{
if (c_r->line->str_len == 0) TT.cur_col = 0;
else if (c_r->line->str_len-1 < TT.cur_col) TT.cur_col = c_r->line->str_len-1;
- if(utf8_width(&c_r->line->str_data[TT.cur_col], c_r->line->str_len-TT.cur_col) <= 0)
- cur_left(1);
+ if (utf8_width(&c_r->line->str_data[TT.cur_col], c_r->line->str_len-TT.cur_col) <= 0)
+ cur_left(1, 1, 0);
}
static void adjust_screen_buffer()
@@ -889,7 +1134,7 @@ static void adjust_screen_buffer()
//for each iteration
if (distance >= (int)TT.screen_height) {
int adj = distance - TT.screen_height;
- while(adj--) {
+ while (adj--) {
scr_r = scr_r->down;
}
}
@@ -1025,8 +1270,9 @@ write_bytes:
return max_width-width;
}
-static int cur_left(int count)
+static int cur_left(int count0, int count1, char* unused)
{
+ int count = count0*count1;
for (;count--;) {
if (!TT.cur_col) return 1;
@@ -1036,8 +1282,9 @@ static int cur_left(int count)
return 1;
}
-static int cur_right(int count)
+static int cur_right(int count0, int count1, char* unused)
{
+ int count = count0*count1;
for (;count--;) {
if (c_r->line->str_len <= 1) return 1;
if (TT.cur_col >= c_r->line->str_len-1) {
@@ -1048,13 +1295,14 @@ static int cur_right(int count)
TT.cur_col++;
if (utf8_width(&c_r->line->str_data[TT.cur_col],
c_r->line->str_len-TT.cur_col) <= 0)
- cur_right(1);
+ cur_right(1, 1, 0);
}
return 1;
}
-static int cur_up(int count)
+static int cur_up(int count0, int count1, char* unused)
{
+ int count = count0*count1;
for (;count-- && c_r->up;)
c_r = c_r->up;
@@ -1063,8 +1311,9 @@ static int cur_up(int count)
return 1;
}
-static int cur_down(int count)
+static int cur_down(int count0, int count1, char* unused)
{
+ int count = count0*count1;
for (;count-- && c_r->down;)
c_r = c_r->down;
@@ -1072,3 +1321,4 @@ static int cur_down(int count)
adjust_screen_buffer();
return 1;
}
+