diff options
Diffstat (limited to 'apps/system/vi')
-rw-r--r-- | apps/system/vi/vi.c | 185 |
1 files changed, 136 insertions, 49 deletions
diff --git a/apps/system/vi/vi.c b/apps/system/vi/vi.c index d580f57c6..4d8528913 100644 --- a/apps/system/vi/vi.c +++ b/apps/system/vi/vi.c @@ -309,6 +309,8 @@ static off_t vi_cursorright(FAR struct vi_s *vi, off_t curpos, int ncolumns); static void vi_delforward(FAR struct vi_s *vi); static void vi_delbackward(FAR struct vi_s *vi); +static void vi_linerange(FAR struct vi_s *vi, off_t *start, off_t *end); +static void vi_delline(FAR struct vi_s *vi); static void vi_yank(FAR struct vi_s *vi); static void vi_paste(FAR struct vi_s *vi); static void vi_gotoline(FAR struct vi_s *vi); @@ -367,7 +369,7 @@ static const char g_blinkon[] = VT100_BLINK; static const char g_boldoff[] = VT100_BOLDOFF; static const char g_reverseoff[] = VT100_REVERSEOFF; static const char g_blinkoff[] = VT100_BLINKOFF; -#endif +#endif static const char g_fmtcursorpos[] = VT100_FMT_CURSORPOS; @@ -799,7 +801,7 @@ static off_t vi_linebegin(FAR struct vi_s *vi, off_t pos) * Name: vi_prevline * * Description: - * Search backward for the end of the previous line + * Search backward for the beginning of the previous line * ****************************************************************************/ @@ -1375,10 +1377,10 @@ static void vi_scrollcheck(FAR struct vi_s *vi) while (curline < vi->winpos) { - /* Yes.. move the window position up by one line and check again */ + /* Yes.. move the window position up to the beginning of the previous + * line line and check again */ - pos = vi_prevline(vi, vi->winpos); - vi->winpos = vi_linebegin(vi, pos); + vi->winpos = vi_prevline(vi, vi->winpos); } /* Reset the cursor row position so that it is relative to the @@ -1654,13 +1656,12 @@ static void vi_cusorup(FAR struct vi_s *vi, int nlines) int remaining; off_t start; off_t end; - off_t pos; vivdbg("nlines=%d\n", nlines); /* How many lines do we need to move? Zero means 1 (so does 1) */ - remaining = (nlines == 0 ? 1 : nlines); + remaining = (nlines < 1 ? 1 : nlines); /* Get the offset to the start of the current line */ @@ -1670,14 +1671,15 @@ static void vi_cusorup(FAR struct vi_s *vi, int nlines) for (; remaining > 0; remaining--) { - /* Get the start and end offset of the line */ + /* Get the start position of the previous line */ - pos = vi_prevline(vi, start); - start = vi_linebegin(vi, pos); - end = start + vi->cursor.column + vi->hscroll; + start = vi_prevline(vi, start); - /* Get the text buffer position to the horizontal cursor position */ + /* Find the cursor position on the next line corresponding to the + * cursor position on the current line. + */ + end = start + vi->cursor.column + vi->hscroll; vi_windowpos(vi, start, end, NULL, &vi->curpos); } } @@ -1700,7 +1702,7 @@ static void vi_cursordown(FAR struct vi_s *vi, int nlines) /* How many lines do we need to move? Zero means 1 (so does 1) */ - remaining = (nlines == 0 ? 1 : nlines); + remaining = (nlines < 1 ? 1 : nlines); /* Get the offset to the start of the current line */ @@ -1710,18 +1712,15 @@ static void vi_cursordown(FAR struct vi_s *vi, int nlines) for (; remaining > 0; remaining--) { - if (!vi_lineend(vi, vi->curpos) < vi->textsize) - { - break; - } - - /* Get the start and end offset of the line */ + /* Get the start of the next line. */ start = vi_nextline(vi, start); - end = start + vi->cursor.column + vi->hscroll; - /* Get the text buffer position to the horizontal cursor position */ + /* Find the cursor position on the next line corresponding to the + * cursor position on the current line. + */ + end = start + vi->cursor.column + vi->hscroll; vi_windowpos(vi, start, end, NULL, &vi->curpos); } } @@ -1742,8 +1741,13 @@ static off_t vi_cursorleft(FAR struct vi_s *vi, off_t curpos, int ncolumns) vivdbg("curpos=%ld ncolumns=%d\n", curpos, ncolumns); + /* Loop decrementing the cursor position for each repitition count. Break + * out early if we hit either the beginning of the text buffer, or the end + * of the previous line. + */ + for (remaining = (ncolumns < 1 ? 1 : ncolumns); - curpos > 0 && remaining > 0 && vi->text[curpos] != '\n'; + curpos > 0 && remaining > 0 && vi->text[curpos - 1] != '\n'; curpos--, remaining--); return curpos; @@ -1765,6 +1769,10 @@ static off_t vi_cursorright(FAR struct vi_s *vi, off_t curpos, int ncolumns) vivdbg("curpos=%ld ncolumns=%d\n", curpos, ncolumns); + /* Loop incrementing the cursor position for each repitition count. Break + * out early if we hit either the end of the text buffer, or the end of the line. + */ + for (remaining = (ncolumns < 1 ? 1 : ncolumns); curpos < vi->textsize && remaining > 0 && vi->text[curpos] != '\n'; curpos++, remaining--); @@ -1787,8 +1795,17 @@ static void vi_delforward(FAR struct vi_s *vi) vivdbg("curpos=%ld value=%ld\n", (long)vi->curpos, vi->value); + /* Get the cursor position as if we would have move the cursor right N + * times (which might be <N characters). + */ + end = vi_cursorright(vi, vi->curpos, vi->value); - size = end - vi->curpos - 1; + + /* The difference from the current position then is the number of + * characters to be deleted. + */ + + size = end - vi->curpos; vi_shrinktext(vi, vi->curpos, size); } @@ -1808,46 +1825,104 @@ static void vi_delbackward(FAR struct vi_s *vi) vivdbg("curpos=%ld value=%ld\n", (long)vi->curpos, vi->value); - start = vi_cursorleft(vi, vi->curpos, 1); - end = vi_cursorleft(vi, start, vi->value); - size = end - start - 1; + /* Back up one character. This is where the deletion will end */ + + end = vi_cursorleft(vi, vi->curpos, 1); + + /* Get the cursor position as if we would have move the cursor left N + * times (which might be <N characters). + */ + + start = vi_cursorleft(vi, end, vi->value); + + /* The difference from the current position then is the number of + * characters to be deleted. + */ + + size = end - start; vi_shrinktext(vi, start, size); } /**************************************************************************** - * Name: vi_yank + * Name: vi_linerange * * Description: - * Remove N lines from the text buffer, beginning at the current line and - * copy the lines to an allocated yank buffer. + * Return the start and end positions for N lines int the text buffer, + * beginning at the current line. This is logic common to yanking and + * deleting lines. * ****************************************************************************/ -static void vi_yank(FAR struct vi_s *vi) +static void vi_linerange(FAR struct vi_s *vi, off_t *start, off_t *end) { - off_t start; - off_t end; off_t next; int nlines; /* Get the offset in the text buffer to the beginning of the current line */ - start = vi_linebegin(vi, vi->curpos); + *start = vi_linebegin(vi, vi->curpos); /* Move one line unless a repetition count was provided */ nlines = (vi->value > 0 ? vi->value : 1); - vivdbg("start=%ld nlines=%d\n", (long)start, nlines); - /* Search ahead to find the end of the last line to yank */ - for (next = start; nlines > 1; nlines--) + for (next = *start; nlines > 1; nlines--) { next = vi_nextline(vi, next); } - end = vi_lineend(vi, next); + *end = vi_lineend(vi, next); +} + +/**************************************************************************** + * Name: vi_delline + * + * Description: + * Delete N lines from the text buffer, beginning at the current line. + * + ****************************************************************************/ + +static void vi_delline(FAR struct vi_s *vi) +{ + off_t delsize; + off_t start; + off_t end; + + /* Get the offset in the text buffer corresponding to the range of lines to + * be deleted + */ + + vi_linerange(vi, &start, &end); + vivdbg("start=%ld end=%ld\n", (long)start, (long)end); + + /* Remove the text from the text buffer */ + + delsize = end - start + 1; + vi_shrinktext(vi, start, delsize); +} + +/**************************************************************************** + * Name: vi_yank + * + * Description: + * Remove N lines from the text buffer, beginning at the current line and + * copy the lines to an allocated yank buffer. + * + ****************************************************************************/ + +static void vi_yank(FAR struct vi_s *vi) +{ + off_t start; + off_t end; + + /* Get the offset in the text buffer corresponding to the range of lines to + * be yanked + */ + + vi_linerange(vi, &start, &end); + vivdbg("start=%ld end=%ld\n", (long)start, (long)end); /* Free any previously yanked lines */ @@ -2115,8 +2190,8 @@ static void vi_cmd_mode(FAR struct vi_s *vi) { if (vi->delarm) { - off_t curline = vi_linebegin(vi, vi->curpos); - vi_shrinktext(vi, curline, vi_nextline(vi, curline) - curline); + vi_delline(vi); + vi->delarm = false; } else { @@ -2130,6 +2205,7 @@ static void vi_cmd_mode(FAR struct vi_s *vi) if (vi->yankarm) { vi_yank(vi); + vi->yankarm = false; } else { @@ -2158,6 +2234,10 @@ static void vi_cmd_mode(FAR struct vi_s *vi) case KEY_CMDMODE_OPENBELOW: /* Enter insertion mode in new line below current */ { + /* Go forward to the end of the current line */ + + vi->curpos = vi_lineend(vi, vi->curpos); + /* Insert a newline to break the line. The cursor now points * beginning of the new line. */ @@ -2172,12 +2252,16 @@ static void vi_cmd_mode(FAR struct vi_s *vi) case KEY_CMDMODE_OPENABOVE: /* Enter insertion mode in new line above current */ { - /* Insert a newline to break the line. Backup the cursor so - * that it points to the end of the (previous) current line. + /* Back up to the beginning of the end of the previous line */ + + off_t pos = vi_prevline(vi, vi->curpos); + vi->curpos = vi_lineend(vi, pos); + + /* Insert a newline to open the line. The cursor will now point to the + * beginning of newly openly line before the current line. */ vi_insertch(vi, '\n'); - vi->curpos = vi_prevline(vi, vi->curpos); /* Then enter insert mode */ @@ -2187,7 +2271,7 @@ static void vi_cmd_mode(FAR struct vi_s *vi) case KEY_CMDMODE_APPEND: /* Enter insertion mode after the current cursor position */ { - vi->curpos = vi_cursorleft(vi, vi->curpos, 1); + vi->curpos = vi_cursorright(vi, vi->curpos, 1); vi_setmode(vi, MODE_INSERT, 0); } break; @@ -2242,10 +2326,14 @@ static void vi_cmd_mode(FAR struct vi_s *vi) } /* Any non-numeric input will reset the accumulated value (after it has - * been used) + * been used). For the double character sequences, we need to retain + * the value until the next character is entered. */ - vi->value = 0; + if (!vi->delarm && !vi->yankarm) + { + vi->value = 0; + } } } @@ -2836,7 +2924,7 @@ static void vi_replacech_submode(FAR struct vi_s *vi) off_t end; long nchars; bool found = false; - int ch; + int ch = 0; /* Get the number of characters to replace */ @@ -2850,13 +2938,12 @@ static void vi_replacech_submode(FAR struct vi_s *vi) if (vi->curpos + nchars > end) { vi_error(vi, g_fmtnotvalid); - vi_exitsubmode(vi, MODE_COMMAND); vi_setmode(vi, MODE_COMMAND, 0); } /* Loop until we get the replacement character */ - while (!found) + while (vi->mode == SUBMODE_REPLACECH && !found) { /* Get the next character from the input */ @@ -3023,7 +3110,7 @@ static void vi_insert_mode(FAR struct vi_s *vi) case ASCII_BS: { - if (vi->curpos) + if (vi->curpos > 0) { vi_shrinktext(vi, --vi->curpos, 1); } |