aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-12-06 16:31:38 +0800
committerGitHub <noreply@github.com>2022-12-06 16:31:38 +0800
commitd82e56dd120af016ba7bb551ff98849d2fa369d0 (patch)
tree45093beee62baa1b37c12b28f1e90470c477f06b
parent6d7b94ea086e17d16e2490e56572f17031924af5 (diff)
downloadrneovim-d82e56dd120af016ba7bb551ff98849d2fa369d0.tar.gz
rneovim-d82e56dd120af016ba7bb551ff98849d2fa369d0.tar.bz2
rneovim-d82e56dd120af016ba7bb551ff98849d2fa369d0.zip
vim-patch:8.2.1622: loop to handle keys for the command line is too long (#21307)
Problem: Loop to handle keys for the command line is too long. Solution: Move code to functions. (Yegappan Lakshmanan, closes vim/vim#6880) https://github.com/vim/vim/commit/2f3cd2e4ec5617e3697ec4f4c6e1c9449061ad30 Use the command line state as only argument instead.
-rw-r--r--src/nvim/ex_getln.c532
1 files changed, 282 insertions, 250 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 1ba55a86d8..d763a59d08 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1410,6 +1410,198 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_
return FAIL;
}
+/// Handle backspace, delete and CTRL-W keys in the command-line mode.
+static int command_line_erase_chars(CommandLineState *s)
+{
+ if (s->c == K_KDEL) {
+ s->c = K_DEL;
+ }
+
+ // Delete current character is the same as backspace on next
+ // character, except at end of line
+ if (s->c == K_DEL && ccline.cmdpos != ccline.cmdlen) {
+ ccline.cmdpos++;
+ }
+
+ if (s->c == K_DEL) {
+ ccline.cmdpos += mb_off_next((char_u *)ccline.cmdbuff,
+ (char_u *)ccline.cmdbuff + ccline.cmdpos);
+ }
+
+ if (ccline.cmdpos > 0) {
+ char_u *p;
+
+ int j = ccline.cmdpos;
+ p = mb_prevptr((char_u *)ccline.cmdbuff, (char_u *)ccline.cmdbuff + j);
+
+ if (s->c == Ctrl_W) {
+ while (p > (char_u *)ccline.cmdbuff && ascii_isspace(*p)) {
+ p = mb_prevptr((char_u *)ccline.cmdbuff, p);
+ }
+
+ int i = mb_get_class(p);
+ while (p > (char_u *)ccline.cmdbuff && mb_get_class(p) == i) {
+ p = mb_prevptr((char_u *)ccline.cmdbuff, p);
+ }
+
+ if (mb_get_class(p) != i) {
+ p += utfc_ptr2len((char *)p);
+ }
+ }
+
+ ccline.cmdpos = (int)(p - (char_u *)ccline.cmdbuff);
+ ccline.cmdlen -= j - ccline.cmdpos;
+ int i = ccline.cmdpos;
+
+ while (i < ccline.cmdlen) {
+ ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
+ }
+
+ // Truncate at the end, required for multi-byte chars.
+ ccline.cmdbuff[ccline.cmdlen] = NUL;
+ if (ccline.cmdlen == 0) {
+ s->is_state.search_start = s->is_state.save_cursor;
+ // save view settings, so that the screen won't be restored at the
+ // wrong position
+ s->is_state.old_viewstate = s->is_state.init_viewstate;
+ }
+ redrawcmd();
+ } else if (ccline.cmdlen == 0 && s->c != Ctrl_W
+ && ccline.cmdprompt == NULL && s->indent == 0) {
+ // In ex and debug mode it doesn't make sense to return.
+ if (exmode_active || ccline.cmdfirstc == '>') {
+ return command_line_not_changed(s);
+ }
+
+ XFREE_CLEAR(ccline.cmdbuff); // no commandline to return
+ if (!cmd_silent && !ui_has(kUICmdline)) {
+ if (cmdmsg_rl) {
+ msg_col = Columns;
+ } else {
+ msg_col = 0;
+ }
+ msg_putchar(' '); // delete ':'
+ }
+ s->is_state.search_start = s->is_state.save_cursor;
+ redraw_cmdline = true;
+ return 0; // back to cmd mode
+ }
+ return command_line_changed(s);
+}
+
+/// Handle the CTRL-^ key in the command-line mode and toggle the use of the
+/// language :lmap mappings and/or Input Method.
+static void command_line_toggle_langmap(CommandLineState *s)
+{
+ if (map_to_exists_mode("", MODE_LANGMAP, false)) {
+ // ":lmap" mappings exists, toggle use of mappings.
+ State ^= MODE_LANGMAP;
+ if (s->b_im_ptr != NULL) {
+ if (State & MODE_LANGMAP) {
+ *s->b_im_ptr = B_IMODE_LMAP;
+ } else {
+ *s->b_im_ptr = B_IMODE_NONE;
+ }
+ }
+ }
+
+ if (s->b_im_ptr != NULL) {
+ if (s->b_im_ptr == &curbuf->b_p_iminsert) {
+ set_iminsert_global();
+ } else {
+ set_imsearch_global();
+ }
+ }
+ ui_cursor_shape(); // may show different cursor shape
+ // Show/unshow value of 'keymap' in status lines later.
+ status_redraw_curbuf();
+}
+
+/// Handle the CTRL-R key in the command-line mode and insert the contents of a
+/// numbered or named register.
+static int command_line_insert_reg(CommandLineState *s)
+{
+ const int save_new_cmdpos = new_cmdpos;
+
+ putcmdline('"', true);
+ no_mapping++;
+ allow_keys++;
+ int i = s->c = plain_vgetc(); // CTRL-R <char>
+ if (i == Ctrl_O) {
+ i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R
+ }
+
+ if (i == Ctrl_R) {
+ s->c = plain_vgetc(); // CTRL-R CTRL-R <char>
+ }
+ no_mapping--;
+ allow_keys--;
+ // Insert the result of an expression.
+ new_cmdpos = -1;
+ if (s->c == '=') {
+ if (ccline.cmdfirstc == '=' // can't do this recursively
+ || cmdline_star > 0) { // or when typing a password
+ beep_flush();
+ s->c = ESC;
+ } else {
+ s->c = get_expr_register();
+ }
+ }
+
+ if (s->c != ESC) { // use ESC to cancel inserting register
+ cmdline_paste(s->c, i == Ctrl_R, false);
+
+ // When there was a serious error abort getting the
+ // command line.
+ if (aborting()) {
+ s->gotesc = true; // will free ccline.cmdbuff after
+ // putting it in history
+ return 0; // back to cmd mode
+ }
+ KeyTyped = false; // Don't do p_wc completion.
+ if (new_cmdpos >= 0) {
+ // set_cmdline_pos() was used
+ if (new_cmdpos > ccline.cmdlen) {
+ ccline.cmdpos = ccline.cmdlen;
+ } else {
+ ccline.cmdpos = new_cmdpos;
+ }
+ }
+ }
+ new_cmdpos = save_new_cmdpos;
+
+ // remove the double quote
+ ccline.special_char = NUL;
+ redrawcmd();
+
+ return command_line_changed(s);
+}
+
+/// Handle the Left and Right mouse clicks in the command-line mode.
+static void command_line_left_right_mouse(CommandLineState *s)
+{
+ if (s->c == K_LEFTRELEASE || s->c == K_RIGHTRELEASE) {
+ s->ignore_drag_release = true;
+ } else {
+ s->ignore_drag_release = false;
+ }
+
+ ccline.cmdspos = cmd_startcol();
+ for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
+ ccline.cmdpos++) {
+ int cells = cmdline_charsize(ccline.cmdpos);
+ if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
+ && mouse_col < ccline.cmdspos % Columns + cells) {
+ break;
+ }
+
+ // Count ">" for double-wide char that doesn't fit.
+ correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos);
+ ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1;
+ ccline.cmdspos += cells;
+ }
+}
+
static void command_line_next_histidx(CommandLineState *s, bool next_match)
{
int j = (int)strlen(s->lookfor);
@@ -1462,89 +1654,104 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match)
}
}
-static int command_line_handle_key(CommandLineState *s)
+/// Handle the Up, Down, Page Up, Page down, CTRL-N and CTRL-P key in the
+/// command-line mode. The pressed key is in 'c'.
+static int command_line_browse_history(CommandLineState *s)
{
- // Big switch for a typed command line character.
- switch (s->c) {
- case K_BS:
- case Ctrl_H:
- case K_DEL:
- case K_KDEL:
- case Ctrl_W:
- if (s->c == K_KDEL) {
- s->c = K_DEL;
- }
-
- // delete current character is the same as backspace on next
- // character, except at end of line
- if (s->c == K_DEL && ccline.cmdpos != ccline.cmdlen) {
- ccline.cmdpos++;
- }
+ if (s->histype == HIST_INVALID || get_hislen() == 0 || s->firstc == NUL) {
+ // no history
+ return command_line_not_changed(s);
+ }
- if (s->c == K_DEL) {
- ccline.cmdpos += mb_off_next((char_u *)ccline.cmdbuff,
- (char_u *)ccline.cmdbuff + ccline.cmdpos);
- }
+ s->save_hiscnt = s->hiscnt;
- if (ccline.cmdpos > 0) {
- char_u *p;
+ // save current command string so it can be restored later
+ if (s->lookfor == NULL) {
+ s->lookfor = xstrdup(ccline.cmdbuff);
+ s->lookfor[ccline.cmdpos] = NUL;
+ }
- int j = ccline.cmdpos;
- p = mb_prevptr((char_u *)ccline.cmdbuff, (char_u *)ccline.cmdbuff + j);
+ bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N
+ || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
+ command_line_next_histidx(s, next_match);
- if (s->c == Ctrl_W) {
- while (p > (char_u *)ccline.cmdbuff && ascii_isspace(*p)) {
- p = mb_prevptr((char_u *)ccline.cmdbuff, p);
- }
+ if (s->hiscnt != s->save_hiscnt) {
+ // jumped to other entry
+ char *p;
+ int len = 0;
+ int old_firstc;
- int i = mb_get_class(p);
- while (p > (char_u *)ccline.cmdbuff && mb_get_class(p) == i) {
- p = mb_prevptr((char_u *)ccline.cmdbuff, p);
- }
+ XFREE_CLEAR(ccline.cmdbuff);
+ s->xpc.xp_context = EXPAND_NOTHING;
+ if (s->hiscnt == get_hislen()) {
+ p = s->lookfor; // back to the old one
+ } else {
+ p = get_histentry(s->histype)[s->hiscnt].hisstr;
+ }
+
+ if (s->histype == HIST_SEARCH
+ && p != s->lookfor
+ && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) {
+ // Correct for the separator character used when
+ // adding the history entry vs the one used now.
+ // First loop: count length.
+ // Second loop: copy the characters.
+ for (int i = 0; i <= 1; i++) {
+ len = 0;
+ for (int j = 0; p[j] != NUL; j++) {
+ // Replace old sep with new sep, unless it is
+ // escaped.
+ if (p[j] == old_firstc
+ && (j == 0 || p[j - 1] != '\\')) {
+ if (i > 0) {
+ ccline.cmdbuff[len] = (char)s->firstc;
+ }
+ } else {
+ // Escape new sep, unless it is already
+ // escaped.
+ if (p[j] == s->firstc
+ && (j == 0 || p[j - 1] != '\\')) {
+ if (i > 0) {
+ ccline.cmdbuff[len] = '\\';
+ }
+ len++;
+ }
- if (mb_get_class(p) != i) {
- p += utfc_ptr2len((char *)p);
+ if (i > 0) {
+ ccline.cmdbuff[len] = p[j];
+ }
+ }
+ len++;
}
- }
-
- ccline.cmdpos = (int)(p - (char_u *)ccline.cmdbuff);
- ccline.cmdlen -= j - ccline.cmdpos;
- int i = ccline.cmdpos;
-
- while (i < ccline.cmdlen) {
- ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
- }
- // Truncate at the end, required for multi-byte chars.
- ccline.cmdbuff[ccline.cmdlen] = NUL;
- if (ccline.cmdlen == 0) {
- s->is_state.search_start = s->is_state.save_cursor;
- // save view settings, so that the screen won't be restored at the
- // wrong position
- s->is_state.old_viewstate = s->is_state.init_viewstate;
- }
- redrawcmd();
- } else if (ccline.cmdlen == 0 && s->c != Ctrl_W
- && ccline.cmdprompt == NULL && s->indent == 0) {
- // In ex and debug mode it doesn't make sense to return.
- if (exmode_active || ccline.cmdfirstc == '>') {
- return command_line_not_changed(s);
- }
-
- XFREE_CLEAR(ccline.cmdbuff); // no commandline to return
- if (!cmd_silent && !ui_has(kUICmdline)) {
- if (cmdmsg_rl) {
- msg_col = Columns;
- } else {
- msg_col = 0;
+ if (i == 0) {
+ alloc_cmdbuff(len);
}
- msg_putchar(' '); // delete ':'
}
- s->is_state.search_start = s->is_state.save_cursor;
- redraw_cmdline = true;
- return 0; // back to cmd mode
+ ccline.cmdbuff[len] = NUL;
+ } else {
+ alloc_cmdbuff((int)strlen(p));
+ STRCPY(ccline.cmdbuff, p);
}
+
+ ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff);
+ redrawcmd();
return command_line_changed(s);
+ }
+ beep_flush();
+ return command_line_not_changed(s);
+}
+
+static int command_line_handle_key(CommandLineState *s)
+{
+ // Big switch for a typed command line character.
+ switch (s->c) {
+ case K_BS:
+ case Ctrl_H:
+ case K_DEL:
+ case K_KDEL:
+ case Ctrl_W:
+ return command_line_erase_chars(s);
case K_INS:
case K_KINS:
@@ -1554,28 +1761,7 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s);
case Ctrl_HAT:
- if (map_to_exists_mode("", MODE_LANGMAP, false)) {
- // ":lmap" mappings exists, toggle use of mappings.
- State ^= MODE_LANGMAP;
- if (s->b_im_ptr != NULL) {
- if (State & MODE_LANGMAP) {
- *s->b_im_ptr = B_IMODE_LMAP;
- } else {
- *s->b_im_ptr = B_IMODE_NONE;
- }
- }
- }
-
- if (s->b_im_ptr != NULL) {
- if (s->b_im_ptr == &curbuf->b_p_iminsert) {
- set_iminsert_global();
- } else {
- set_imsearch_global();
- }
- }
- ui_cursor_shape(); // may show different cursor shape
- // Show/unshow value of 'keymap' in status lines later.
- status_redraw_curbuf();
+ command_line_toggle_langmap(s);
return command_line_not_changed(s);
case Ctrl_U: {
@@ -1611,62 +1797,8 @@ static int command_line_handle_key(CommandLineState *s)
// putting it in history
return 0; // back to cmd mode
- case Ctrl_R: { // insert register
- const int save_new_cmdpos = new_cmdpos;
-
- putcmdline('"', true);
- no_mapping++;
- allow_keys++;
- int i = s->c = plain_vgetc(); // CTRL-R <char>
- if (i == Ctrl_O) {
- i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R
- }
-
- if (i == Ctrl_R) {
- s->c = plain_vgetc(); // CTRL-R CTRL-R <char>
- }
- no_mapping--;
- allow_keys--;
- // Insert the result of an expression.
- new_cmdpos = -1;
- if (s->c == '=') {
- if (ccline.cmdfirstc == '=' // can't do this recursively
- || cmdline_star > 0) { // or when typing a password
- beep_flush();
- s->c = ESC;
- } else {
- s->c = get_expr_register();
- }
- }
-
- if (s->c != ESC) { // use ESC to cancel inserting register
- cmdline_paste(s->c, i == Ctrl_R, false);
-
- // When there was a serious error abort getting the
- // command line.
- if (aborting()) {
- s->gotesc = true; // will free ccline.cmdbuff after
- // putting it in history
- return 0; // back to cmd mode
- }
- KeyTyped = false; // Don't do p_wc completion.
- if (new_cmdpos >= 0) {
- // set_cmdline_pos() was used
- if (new_cmdpos > ccline.cmdlen) {
- ccline.cmdpos = ccline.cmdlen;
- } else {
- ccline.cmdpos = new_cmdpos;
- }
- }
- }
- new_cmdpos = save_new_cmdpos;
-
- // remove the double quote
- ccline.special_char = NUL;
- redrawcmd();
-
- return command_line_changed(s);
- }
+ case Ctrl_R: // insert register
+ return command_line_insert_reg(s);
case Ctrl_D:
if (showmatches(&s->xpc, false) == EXPAND_NOTHING) {
@@ -1747,26 +1879,7 @@ static int command_line_handle_key(CommandLineState *s)
FALLTHROUGH;
case K_LEFTMOUSE:
case K_RIGHTMOUSE:
- if (s->c == K_LEFTRELEASE || s->c == K_RIGHTRELEASE) {
- s->ignore_drag_release = true;
- } else {
- s->ignore_drag_release = false;
- }
-
- ccline.cmdspos = cmd_startcol();
- for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
- ccline.cmdpos++) {
- int cells = cmdline_charsize(ccline.cmdpos);
- if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
- && mouse_col < ccline.cmdspos % Columns + cells) {
- break;
- }
-
- // Count ">" for double-wide char that doesn't fit.
- correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos);
- ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1;
- ccline.cmdspos += cells;
- }
+ command_line_left_right_mouse(s);
return command_line_not_changed(s);
// Mouse scroll wheel: ignored here
@@ -1849,88 +1962,7 @@ static int command_line_handle_key(CommandLineState *s)
case K_KPAGEUP:
case K_PAGEDOWN:
case K_KPAGEDOWN:
- if (s->histype == HIST_INVALID || get_hislen() == 0 || s->firstc == NUL) {
- // no history
- return command_line_not_changed(s);
- }
-
- s->save_hiscnt = s->hiscnt;
-
- // save current command string so it can be restored later
- if (s->lookfor == NULL) {
- s->lookfor = xstrdup(ccline.cmdbuff);
- s->lookfor[ccline.cmdpos] = NUL;
- }
-
- bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N
- || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
- command_line_next_histidx(s, next_match);
-
- if (s->hiscnt != s->save_hiscnt) {
- // jumped to other entry
- char *p;
- int len = 0;
- int old_firstc;
-
- XFREE_CLEAR(ccline.cmdbuff);
- s->xpc.xp_context = EXPAND_NOTHING;
- if (s->hiscnt == get_hislen()) {
- p = s->lookfor; // back to the old one
- } else {
- p = get_histentry(s->histype)[s->hiscnt].hisstr;
- }
-
- if (s->histype == HIST_SEARCH
- && p != s->lookfor
- && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) {
- // Correct for the separator character used when
- // adding the history entry vs the one used now.
- // First loop: count length.
- // Second loop: copy the characters.
- for (int i = 0; i <= 1; i++) {
- len = 0;
- for (int j = 0; p[j] != NUL; j++) {
- // Replace old sep with new sep, unless it is
- // escaped.
- if (p[j] == old_firstc
- && (j == 0 || p[j - 1] != '\\')) {
- if (i > 0) {
- ccline.cmdbuff[len] = (char)s->firstc;
- }
- } else {
- // Escape new sep, unless it is already
- // escaped.
- if (p[j] == s->firstc
- && (j == 0 || p[j - 1] != '\\')) {
- if (i > 0) {
- ccline.cmdbuff[len] = '\\';
- }
- len++;
- }
-
- if (i > 0) {
- ccline.cmdbuff[len] = p[j];
- }
- }
- len++;
- }
-
- if (i == 0) {
- alloc_cmdbuff(len);
- }
- }
- ccline.cmdbuff[len] = NUL;
- } else {
- alloc_cmdbuff((int)strlen(p));
- STRCPY(ccline.cmdbuff, p);
- }
-
- ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff);
- redrawcmd();
- return command_line_changed(s);
- }
- beep_flush();
- return command_line_not_changed(s);
+ return command_line_browse_history(s);
case Ctrl_G: // next match
case Ctrl_T: // previous match