in system/vi/vi.c [3401:4132]
static void vi_cmd_mode(FAR struct vi_s *vi)
{
viinfo("Enter command mode\n");
/* Loop while we are in command mode */
while (vi->mode == MODE_COMMAND)
{
bool preserve;
int ch;
/* Make sure that the display reflects the current state */
vi_showtext(vi);
vi_showlinecol(vi);
vi_setcursor(vi, vi->cursor.row, vi->cursor.column);
/* Get the next character from the input */
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
/* Test for end of command repeat */
if (vi->cmdrepeat && vi->cmdindex == vi->cmdcount)
{
/* Terminate the command repeat */
vi->cmdrepeat = false;
}
/* Test for active cmdrepeat */
if (vi->cmdrepeat)
{
/* Read next command from command buffer */
ch = vi->cmdbuf[vi->cmdindex++];
}
else
#endif
{
ch = vi_getch(vi);
}
/* Handle numeric input. Zero (0) with no preceding value is a
* special case: It means to go to the beginning o the line.
*/
if (isdigit(ch) && (vi->value > 0 || ch != '0'))
{
uint32_t tmp = 10 * vi->value + (ch - '0');
if (tmp > UINT16_MAX)
{
tmp = UINT16_MAX;
}
/* Update the command repetition count */
vi->value = tmp;
viinfo("Value=%ld\n", vi->value);
continue;
}
/* Allow the following during yank / delete modes */
if (ch != 'f' && ch != 't' && ch != 'w')
{
/* Anything other than 'd' disarms line deletion */
if (ch != 'd')
{
vi->delarm = false;
}
/* Anything other than 'y' disarms line yanking */
if (ch != 'y')
{
vi->yankarm = false;
}
/* Anything other than 'c' disarms line yanking */
if (ch != 'c')
{
vi->chgarm = false;
}
}
/* Anything other than'g' disarms goto top */
if (ch != 'g')
{
vi->toparm = false;
}
/* Anything other than'Z' disarms :wq */
if (ch != 'Z')
{
vi->wqarm = false;
}
/* Test for empty file */
if (vi->textsize == 0)
{
/* We need some text before we can do anything. Only accept
* text insertion commands.
*/
if (ch != KEY_CMDMODE_APPEND && ch != KEY_CMDMODE_INSERT &&
ch != KEY_CMDMODE_OPENBELOW && ch != KEY_CMDMODE_APPENDEND &&
ch != KEY_CMDMODE_INSBEGIN && ch != KEY_CMDMODE_OPENABOVE &&
ch != KEY_CMDMODE_COLONMODE)
{
continue;
}
}
/* Any key press clears the error message */
vi->error = false;
/* Then handle the non-numeric character. Normally the accumulated
* value will be reset after processing the command. There are a few
* exceptions; 'preserve' will be set to 'true' in those exceptional
* cases.
*/
preserve = false;
vi->updatereqcol = true;
switch (ch)
{
case KEY_CMDMODE_UP: /* Move the cursor up one line */
case KEY_UP: /* Move the cursor up one line */
{
vi->updatereqcol = false;
vi_cusorup(vi, vi->value);
}
break;
case KEY_CMDMODE_DOWN: /* Move the cursor down one line */
case KEY_DOWN: /* Move the cursor down one line */
{
vi->updatereqcol = false;
vi_cursordown(vi, vi->value);
}
break;
case KEY_CMDMODE_LEFT: /* Move the cursor left N characters */
case KEY_LEFT: /* Move the cursor left N characters */
{
vi->curpos = vi_cursorleft(vi, vi->curpos, vi->value);
}
break;
case KEY_CMDMODE_RIGHT: /* Move the cursor right one character */
case KEY_RIGHT: /* Move the cursor right one character */
{
if (vi->text[vi->curpos] != '\n' &&
vi->text[vi->curpos + 1] != '\n')
{
vi->curpos = vi_cursorright(vi, vi->curpos, vi->value);
if (vi->curpos >= vi->textsize)
{
vi->curpos = vi->textsize - 1;
}
}
}
break;
case KEY_CMDMODE_BEGINLINE: /* Move cursor to start of current line */
case KEY_HOME:
{
vi->curpos = vi_linebegin(vi, vi->curpos);
}
break;
case KEY_CMDMODE_ENDLINE: /* Move cursor to end of current line */
case KEY_END:
{
vi->curpos = vi_lineend(vi, vi->curpos);
vi->reqcolumn = 65535;
vi->updatereqcol = false;
}
break;
case KEY_CMDMODE_PAGEUP: /* Move up (backward) one screen */
case KEY_PPAGE:
{
vi->updatereqcol = false;
vi_cusorup(vi, vi->display.row);
}
break;
case KEY_CMDMODE_PAGEDOWN: /* Move down (forward) one screen */
case KEY_NPAGE:
{
vi->updatereqcol = false;
vi_cursordown(vi, vi->display.row);
}
break;
case KEY_CMDMODE_HALFUP: /* Move up (backward) one screen */
{
vi->updatereqcol = false;
vi_cusorup(vi, vi->display.row >> 1);
}
break;
case KEY_CMDMODE_HALFDOWN: /* Move down (forward) one half screen */
{
vi->updatereqcol = false;
vi_cursordown(vi, vi->display.row >> 1);
}
break;
case KEY_CMDMODE_TOP: /* Move to top of screen */
{
vi->curpos = vi->winpos;
}
break;
case KEY_CMDMODE_BOTTOM: /* Move to bottom of screen */
{
vi_gotoscreenbottom(vi, 0);
}
break;
case KEY_CMDMODE_MIDDLE: /* Move to middle of screen */
{
/* Find bottom row number, then move to half that */
off_t pos = vi_gotoscreenbottom(vi, 0);
vi_gotoscreenbottom(vi, pos);
}
break;
case KEY_CMDMODE_FIRSTCHAR:
{
vi_gotofirstnonwhite(vi);
}
break;
case KEY_CMDMODE_GOTOTOP: /* Go to top of document */
{
if (vi->toparm)
{
vi->curpos = 0;
vi->redrawline = true;
vi->toparm = false;
}
else
{
vi->toparm = true;
}
}
break;
case KEY_CMDMODE_FINDNEXT:
{
if (vi->revfind)
{
vi_findprev(vi);
}
else
{
vi_findnext(vi);
}
break;
}
case KEY_CMDMODE_FINDPREV:
{
if (vi->revfind)
{
vi_findnext(vi);
}
else
{
vi_findprev(vi);
}
break;
}
break;
case ASCII_BS: /* Delete N characters before the cursor */
{
/* Move the cursor to the left */
if (vi->curpos > 0)
{
vi->curpos--;
/* If we moved to \n on the previous line, skip it */
if (vi->curpos > 0 && vi->text[vi->curpos] == '\n')
{
vi->curpos--;
}
}
}
break;
case KEY_CMDMODE_DEL_LINE: /* Delete the current line */
{
if (vi->delarm)
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
vi_appendrepeat(vi, ch);
#endif
vi_delline(vi);
vi->delarm = false;
}
else
{
vi->delarm = true;
preserve = true;
}
}
break;
case KEY_CMDMODE_CHANGE:
{
if (vi->chgarm)
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
vi_appendrepeat(vi, ch);
#endif
vi_gotofirstnonwhite(vi);
vi_deltoeol(vi);
vi_setmode(vi, MODE_INSERT, 0);
if (vi->curpos == vi->textsize)
{
vi->curpos = vi_cursorright(vi, vi->curpos, 1) + 1;
}
else
{
vi->curpos = vi_cursorright(vi, vi->curpos, 1);
}
vi->chgarm = false;
}
else
{
vi->chgarm = true;
preserve = true;
}
}
break;
case KEY_CMDMODE_DELTOEOL: /* Delete to end of current line */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_deltoeol(vi);
}
break;
case KEY_CMDMODE_DELBACKWARD: /* Delete from cursor forward */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_delbackward(vi);
}
break;
case KEY_CMDMODE_YANK: /* Yank the current line(s) into the buffer */
{
if (vi->yankarm)
{
vi_yank(vi, false);
vi->yankarm = false;
}
else
{
vi->yankarm = true;
preserve = true;
}
}
break;
case KEY_CMDMODE_PASTE: /* Paste line(s) from into text after current line */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_paste(vi, false);
}
break;
case KEY_CMDMODE_PASTEBEFORE: /* Paste text before cursor position */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_paste(vi, true);
}
break;
case KEY_CMDMODE_REPLACECH: /* Replace character(s) under cursor */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, SUBMODE_REPLACECH, vi->value);
preserve = true;
}
break;
case KEY_CMDMODE_REPLACE: /* Replace character(s) under cursor until ESC */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, MODE_REPLACE, 0);
}
break; /* Not implemented */
case KEY_CMDMODE_FINDINLINE: /* Find character(s) in current line */
case KEY_CMDMODE_TFINDINLINE: /* Find character(s) in current line */
{
vi->tfind = ch == KEY_CMDMODE_TFINDINLINE;
vi->mode = MODE_FINDINLINE;
preserve = true;
}
break;
case KEY_CMDMODE_OPENBELOW: /* Enter insertion mode in new line below current */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, MODE_INSERT, 0);
/* Go forward to the end of the current line */
vi->curpos = vi_lineend(vi, vi->curpos);
if (vi->curpos != vi->textsize)
{
/* Include the '\n' */
vi->curpos++;
}
/* Insert a newline to break the line. The cursor now points
* beginning of the new line.
*/
vi_insertch(vi, '\n');
/* Then enter insert mode */
vi->drawtoeos = true;
}
break;
case KEY_CMDMODE_OPENABOVE: /* Enter insertion mode in new line above current */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
/* Back up to the beginning of the end of the previous line */
off_t pos = vi_linebegin(vi, vi->curpos);
if (pos == 0)
{
/* Insert newline at beginning of file, then move to previous
* line.
*/
vi->curpos = 0;
vi_insertch(vi, '\n');
vi->curpos = vi_prevline(vi, vi->curpos);
}
else
{
/* Insert a newline to open the line. The cursor will now
* point to thebeginning of newly openly line before the
* current line.
*/
pos = vi_prevline(vi, pos);
vi->curpos = vi_lineend(vi, pos)+1;
vi_insertch(vi, '\n');
}
/* Then enter insert mode */
vi_setmode(vi, MODE_INSERT, 0);
vi->drawtoeos = true;
}
break;
case KEY_CMDMODE_CHANGETOEOL: /* Delete to end of current line */
{
/* First delete to end of line */
vi_deltoeol(vi);
}
/* Now enter insert mode by falling through the case */
case KEY_CMDMODE_APPEND: /* Enter insertion mode after the current
* cursor position */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, MODE_INSERT, 0);
if (vi->curpos == vi->textsize)
{
vi->curpos = vi_cursorright(vi, vi->curpos, 1) + 1;
}
else
{
vi->curpos = vi_cursorright(vi, vi->curpos, 1);
}
}
break;
case KEY_CMDMODE_APPENDEND: /* Enter insertion mode at the end of the current line */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, MODE_INSERT, 0);
vi->curpos = vi_lineend(vi, vi->curpos) + 1;
}
break;
case KEY_CMDMODE_SUBSTITUTE:
case KEY_CMDMODE_DEL: /* Delete N characters at the cursor */
case KEY_DC:
case ASCII_DEL:
{
off_t pos = vi->curpos;
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
/* If we are at the end of the line, then delete backward */
if (vi->text[pos] == '\n')
{
/* Nothing to do */
break;
}
else if (pos + 1 != vi->textsize && vi->text[pos + 1] == '\n')
{
if (pos > 0)
{
vi_delforward(vi);
vi->curpos = vi_cursorleft(vi, vi->curpos, 1);
}
}
else
{
vi_delforward(vi);
vi->redrawline = true;
}
}
/* For 's'ubstitute key, we go into insert mode */
if (ch == KEY_CMDMODE_SUBSTITUTE)
{
vi_setmode(vi, MODE_INSERT, 0);
}
break;
case KEY_CMDMODE_INSBEGIN: /* Enter insertion mode at the beginning of the current line */
{
vi->curpos = vi_linebegin(vi, vi->curpos);
}
/* Fall through */
case KEY_CMDMODE_INSERT: /* Enter insertion mode before the current cursor position */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_setmode(vi, MODE_INSERT, 0);
}
break;
case KEY_CMDMODE_JOIN: /* Join line below with current line */
{
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
vi_saverepeat(vi, ch);
#endif
vi_join(vi);
}
break;
case KEY_CMDMODE_COLONMODE: /* Enter : command sub-mode */
{
vi->updatereqcol = false;
vi_setsubmode(vi, SUBMODE_COLON, ':', 0);
}
break;
case KEY_CMDMODE_SAVEQUIT: /* Two of these is the same as :wq */
{
if (vi->wqarm)
{
/* Emulate :wq */
strlcpy(vi->scratch, "wq", sizeof(vi->scratch));
vi->cmdlen = 2;
vi_parsecolon(vi);
/* If save quit succeeds, we won't return */
}
else
{
vi->wqarm = true;
}
}
break;
case KEY_CMDMODE_FINDMODE: /* Enter / find sub-mode */
{
vi->updatereqcol = false;
vi_setsubmode(vi, SUBMODE_FIND, '/', 0);
}
break;
case KEY_CMDMODE_REVFINDMODE: /* Enter / find sub-mode */
{
vi->updatereqcol = false;
vi_setsubmode(vi, SUBMODE_REVFIND, '?', 0);
}
break;
#ifdef CONFIG_SYSTEM_VI_INCLUDE_COMMAND_REPEAT
case KEY_CMDMODE_REPEAT: /* Repeat the last command */
{
if (vi->cmdcount < CMD_BUFSIZE)
{
vi->cmdindex = 0;
vi->cmdrepeat = true;
vi->value = vi->value > 0 ? vi->value : vi->repeatvalue > 0 ?
vi->repeatvalue : 1;
preserve = true;
}
else
{
VI_BEL(vi);
}
}
break;
#endif
case KEY_CMDMODE_GOTO: /* Go to line specified by the accumulated value */
{
vi_gotoline(vi);
}
break;
case KEY_CMDMODE_WORDFWD: /* Go to line specified by the accumulated value */
{
vi_gotonextword(vi);
}
break;
case KEY_CMDMODE_WORDBACK: /* Go to line specified by the accumulated value */
{
vi_gotoprevword(vi);
}
break;
case KEY_CMDMODE_NEXTLINE:
case '\n': /* LF terminates line */
{
vi->curpos = vi_nextline(vi, vi->curpos);
vi_gotofirstnonwhite(vi);
}
break;
case KEY_CMDMODE_PREVLINE:
{
vi->curpos = vi_prevline(vi, vi->curpos);
vi_gotofirstnonwhite(vi);
}
break;
/* Unimplemented and invalid commands */
case KEY_CMDMODE_REDRAW: /* Redraws the screen */
case KEY_CMDMODE_REDRAW2: /* Redraws the screen, removing deleted lines */
case KEY_CMDMODE_MARK: /* Place a mark beginning at the current cursor position */
default:
{
if (ch == -1)
{
continue;
}
else
{
VI_BEL(vi);
}
}
break;
}
/* Any non-numeric input will reset the accumulated value (after it has
* been used). There are a few exceptions:
*
* - For the double character sequences, we need to retain the value
* until the next character is entered.
* - If we are changing modes, then we may need to preserve the 'value'
* as well; in some cases settings are passed to the new mode in
* 'value' (vi_setmode() will have set or cleared 'value'
* appropriately).
*/
if (!preserve)
{
vi->value = 0;
}
}
}