diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-12-06 16:31:38 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-06 16:31:38 +0800 |
commit | d82e56dd120af016ba7bb551ff98849d2fa369d0 (patch) | |
tree | 45093beee62baa1b37c12b28f1e90470c477f06b | |
parent | 6d7b94ea086e17d16e2490e56572f17031924af5 (diff) | |
download | rneovim-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.c | 532 |
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 |