fixed the "dot" (i.e. '.') command, to properly re-init its
buffer between commands, not recalculate its length all the time,
and to not reallocate its fixed-length buffer frequently.
fixed the 'c', 'd', and 'y' commands to properly handle both motions
that are just part of a line, and those that are multiline. for
instance, now "c%" and "2cw" work correctly, whether the motions span
lines or not.
added some permissble motions for 'c', 'd', and 'y': namely 'h',
'l', SPACE, BS, and DEL
diff --git a/editors/vi.c b/editors/vi.c
index 31ad96c..d9db943 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -170,6 +170,7 @@
#if ENABLE_FEATURE_VI_DOT_CMD
static smallint adding2q; // are we currently adding user input to q
static char *last_modifying_cmd; // [MAX_INPUT_LEN] last modifying cmd for "."
+static smallint lmc_len; // length of last_modifying_cmd
static char *ioq, *ioq_start; // pointer to string for get_one_char to "read"
#endif
#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
@@ -262,7 +263,7 @@
static char *new_screen(int, int); // malloc virtual screen memory
static char *char_insert(char *, char); // insert the char c at 'p'
static char *stupid_insert(char *, char); // stupidly insert the char c at 'p'
-static char find_range(char **, char **, char); // return pointers for an object
+static int find_range(char **, char **, char); // return pointers for an object
static int st_test(char *, int, int, char *); // helper for skip_thing()
static char *skip_thing(char *, int, int, int); // skip some object
static char *find_pair(char *, char); // find matching pair () [] {}
@@ -526,9 +527,9 @@
offset = 0; // no horizontal offset
c = '\0';
#if ENABLE_FEATURE_VI_DOT_CMD
- free(last_modifying_cmd);
free(ioq_start);
- ioq = ioq_start = last_modifying_cmd = NULL;
+ ioq = ioq_start = NULL;
+ lmc_len = 0;
adding2q = 0;
#endif
redraw(FALSE); // dont force every col re-draw
@@ -1662,10 +1663,10 @@
return p;
}
-static char find_range(char ** start, char ** stop, char c)
+static int find_range(char ** start, char ** stop, char c)
{
- char *save_dot, *p, *q;
- int cnt;
+ char *save_dot, *p, *q, *t;
+ int cnt, multiline = 0;
save_dot = dot;
p = q = dot;
@@ -1677,7 +1678,7 @@
q = next_line(q);
}
q = end_line(q);
- } else if (strchr("^%$0bBeEft", c)) {
+ } else if (strchr("^%$0bBeEfth\b\177", c)) {
// These cmds operate on char positions
do_cmd(c); // execute movement cmd
q = dot;
@@ -1706,17 +1707,33 @@
dot_end(); // find NL
q = dot;
} else {
- c = 27; // error- return an ESC char
- //break;
+ // nothing -- this causes any other values of c to
+ // represent the one-character range under the
+ // cursor. this is correct for ' ' and 'l', but
+ // perhaps no others.
+ //
}
+ if (q < p) {
+ t = q;
+ q = p;
+ p = t;
+ }
+
+ // backward char movements don't include start position
+ if (q > p && strchr("^0bBh\b\177", c)) q--;
+
+ multiline = 0;
+ for (t = p; t <= q; t++) {
+ if (*t == '\n') {
+ multiline = 1;
+ break;
+ }
+ }
+
*start = p;
*stop = q;
- if (q < p) {
- *start = q;
- *stop = p;
- }
dot = save_dot;
- return c;
+ return multiline;
}
static int st_test(char * p, int type, int dir, char * tested)
@@ -1780,27 +1797,12 @@
level = 1;
dir = 1; // assume forward
switch (c) {
- case '(':
- match = ')';
- break;
- case '[':
- match = ']';
- break;
- case '{':
- match = '}';
- break;
- case ')':
- match = '(';
- dir = -1;
- break;
- case ']':
- match = '[';
- dir = -1;
- break;
- case '}':
- match = '{';
- dir = -1;
- break;
+ case '(': match = ')'; break;
+ case '[': match = ']'; break;
+ case '{': match = '}'; break;
+ case ')': match = '('; dir = -1; break;
+ case ']': match = '['; dir = -1; break;
+ case '}': match = '{'; dir = -1; break;
}
for (q = p + dir; text <= q && q < end; q += dir) {
// look for match, count levels of pairs (( ))
@@ -1976,10 +1978,10 @@
last_modifying_cmd = xzalloc(MAX_INPUT_LEN);
// if there is a current cmd count put it in the buffer first
if (cmdcnt > 0)
- sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);
+ lmc_len = sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);
else { // just save char c onto queue
last_modifying_cmd[0] = c;
- last_modifying_cmd[1] = '\0';
+ lmc_len = 1;
}
adding2q = 1;
}
@@ -2280,9 +2282,6 @@
char c;
#if ENABLE_FEATURE_VI_DOT_CMD
- // ! adding2q && ioq == 0 read()
- // ! adding2q && ioq != 0 *ioq
- // adding2q *last_modifying_cmd= read()
if (!adding2q) {
// we are not adding to the q.
// but, we may be reading from a q
@@ -2303,12 +2302,11 @@
// adding STDIN chars to q
c = readit(); // get the users input
if (last_modifying_cmd != NULL) {
- int len = strlen(last_modifying_cmd);
- if (len >= MAX_INPUT_LEN - 1) {
+ if (lmc_len >= MAX_INPUT_LEN - 1) {
status_line_bold("last_modifying_cmd overrun");
} else {
// add new char to q
- last_modifying_cmd[len] = c;
+ last_modifying_cmd[lmc_len++] = c;
}
}
}
@@ -2947,7 +2945,7 @@
char c1, *p, *q, *save_dot;
char buf[12];
int dir = dir; // for compiler
- int cnt, i, j, yf;
+ int cnt, i, j;
// c1 = c; // quiet the compiler
// cnt = yf = 0; // quiet the compiler
@@ -3282,7 +3280,8 @@
case '.': // .- repeat the last modifying command
// Stuff the last_modifying_cmd back into stdin
// and let it be re-executed.
- if (last_modifying_cmd != NULL) {
+ if (last_modifying_cmd != NULL && lmc_len > 0) {
+ last_modifying_cmd[lmc_len] = 0;
ioq = ioq_start = xstrdup(last_modifying_cmd);
}
break;
@@ -3668,6 +3667,8 @@
case 'y': // y- yank something
case 'Y': // Y- Yank a line
#endif
+ {
+ int yf, ml, whole = 0;
yf = YANKDEL; // assume either "c" or "d"
#if ENABLE_FEATURE_VI_YANKMARK
if (c == 'y' || c == 'Y')
@@ -3676,7 +3677,8 @@
c1 = 'y';
if (c != 'Y')
c1 = get_one_char(); // get the type of thing to delete
- find_range(&p, &q, c1);
+ // determine range, and whether it spans lines
+ ml = find_range(&p, &q, c1);
if (c1 == 27) { // ESC- user changed mind and wants out
c = c1 = 27; // Escape- do nothing
} else if (strchr("wW", c1)) {
@@ -3688,27 +3690,31 @@
q--;
}
}
- dot = yank_delete(p, q, 0, yf); // delete word
- } else if (strchr("^0bBeEft$", c1)) {
- // single line copy text into a register and delete
- dot = yank_delete(p, q, 0, yf); // delete word
- } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
- // multiple line copy text into a register and delete
- dot = yank_delete(p, q, 1, yf); // delete lines
+ dot = yank_delete(p, q, ml, yf); // delete word
+ } else if (strchr("^0bBeEft%$ lh\b\177", c1)) {
+ // partial line copy text into a register and delete
+ dot = yank_delete(p, q, ml, yf); // delete word
+ } else if (strchr("cdykjHL+-{}\r\n", c1)) {
+ // whole line copy text into a register and delete
+ dot = yank_delete(p, q, ml, yf); // delete lines
+ whole = 1;
+ } else {
+ // could not recognize object
+ c = c1 = 27; // error-
+ ml = 0;
+ indicate_error(c);
+ }
+ if (ml && whole) {
if (c == 'c') {
dot = char_insert(dot, '\n');
// on the last line of file don't move to prev line
- if (dot != (end-1)) {
+ if (whole && dot != (end-1)) {
dot_prev();
}
} else if (c == 'd') {
dot_begin();
dot_skip_over_ws();
}
- } else {
- // could not recognize object
- c = c1 = 27; // error-
- indicate_error(c);
}
if (c1 != 27) {
// if CHANGING, not deleting, start inserting after the delete
@@ -3734,6 +3740,7 @@
#endif
end_cmd_q(); // stop adding to q
}
+ }
break;
case 'k': // k- goto prev line, same col
case VI_K_UP: // cursor key Up