diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-10-06 09:31:50 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-10-26 10:52:01 -0300 |
commit | 0f0fae58b9576b970deab58acc606454d550ff05 (patch) | |
tree | 4f7de3fda1c24918f0c698de7d909ed757c4fd15 | |
parent | fa83b03feacb596088be54fabe6853872bdabba5 (diff) | |
download | rneovim-0f0fae58b9576b970deab58acc606454d550ff05.tar.gz rneovim-0f0fae58b9576b970deab58acc606454d550ff05.tar.bz2 rneovim-0f0fae58b9576b970deab58acc606454d550ff05.zip |
normal: Extract some functions from `normal_execute`
- `normal_handle_special_visual_command`
- `normal_need_aditional_char`
- `normal_get_additional_char`
- `normal_invert_horizontal`
-rw-r--r-- | src/nvim/normal.c | 506 |
1 files changed, 272 insertions, 234 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c96de8ea08..1cc5d3591c 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -70,6 +70,7 @@ typedef struct normal_state { VimState state; linenr_T conceal_old_cursor_line; linenr_T conceal_new_cursor_line; + bool need_flushbuf; bool conceal_update_lines; bool set_prevcount; bool previous_got_int; // `got_int` was true @@ -80,6 +81,8 @@ typedef struct normal_state { oparg_T oa; // operator arguments cmdarg_T ca; // command arguments int mapped_len; + int idx; + int c; } NormalState; /* @@ -508,17 +511,241 @@ static void normal_prepare(NormalState *s) } } -static int normal_execute(VimState *state, int c) +static bool normal_handle_special_visual_command(NormalState *s) +{ + // when 'keymodel' contains "stopsel" may stop Select/Visual mode + if (km_stopsel + && (nv_cmds[s->idx].cmd_flags & NV_STS) + && !(mod_mask & MOD_MASK_SHIFT)) { + end_visual_mode(); + redraw_curbuf_later(INVERTED); + } + + // Keys that work different when 'keymodel' contains "startsel" + if (km_startsel) { + if (nv_cmds[s->idx].cmd_flags & NV_SS) { + unshift_special(&s->ca); + s->idx = find_command(s->ca.cmdchar); + if (s->idx < 0) { + // Just in case + clearopbeep(&s->oa); + return true; + } + } else if ((nv_cmds[s->idx].cmd_flags & NV_SSS) + && (mod_mask & MOD_MASK_SHIFT)) { + mod_mask &= ~MOD_MASK_SHIFT; + } + } + return false; +} + +static bool normal_need_aditional_char(NormalState *s) +{ + int flags = nv_cmds[s->idx].cmd_flags; + bool pending_op = s->oa.op_type != OP_NOP; + int cmdchar = s->ca.cmdchar; + return + // without NV_NCH we never need to check for an additional char + flags & NV_NCH && ( + // NV_NCH_NOP is set and no operator is pending, get a second char + ((flags & NV_NCH_NOP) == NV_NCH_NOP && !pending_op) + // NV_NCH_ALW is set, always get a second char + || (flags & NV_NCH_ALW) == NV_NCH_ALW + // 'q' without a pending operator, recording or executing a register, + // needs to be followed by a second char, examples: + // - qc => record using register c + // - q: => open command-line window + || (cmdchar == 'q' && !pending_op && !Recording && !Exec_reg) + // 'a' or 'i' after an operator is a text object, examples: + // - ciw => change inside word + // - da( => delete parenthesis and everything inside. + // Also, don't do anything when these keys are received in visual mode + // so just get another char. + // + // TODO(tarruda): Visual state needs to be refactored into a + // separate state that "inherits" from normal state. + || ((cmdchar == 'a' || cmdchar == 'i') && (pending_op || VIsual_active))); +} + +// TODO(tarruda): Split into a "normal pending" state that can handle K_EVENT +static void normal_get_additional_char(NormalState *s) +{ + int *cp; + bool repl = false; // get character for replace mode + bool lit = false; // get extra character literally + bool langmap_active = false; // using :lmap mappings + int lang; // getting a text character + + ++no_mapping; + ++allow_keys; // no mapping for nchar, but allow key codes + // Don't generate a CursorHold event here, most commands can't handle + // it, e.g., nv_replace(), nv_csearch(). + did_cursorhold = true; + if (s->ca.cmdchar == 'g') { + // For 'g' get the next character now, so that we can check for + // "gr", "g'" and "g`". + s->ca.nchar = plain_vgetc(); + LANGMAP_ADJUST(s->ca.nchar, true); + s->need_flushbuf |= add_to_showcmd(s->ca.nchar); + if (s->ca.nchar == 'r' || s->ca.nchar == '\'' || s->ca.nchar == '`' + || s->ca.nchar == Ctrl_BSL) { + cp = &s->ca.extra_char; // need to get a third character + if (s->ca.nchar != 'r') { + lit = true; // get it literally + } else { + repl = true; // get it in replace mode + } + } else { + cp = NULL; // no third character needed + } + } else { + if (s->ca.cmdchar == 'r') { + // get it in replace mode + repl = true; + } + cp = &s->ca.nchar; + } + lang = (repl || (nv_cmds[s->idx].cmd_flags & NV_LANG)); + + // Get a second or third character. + if (cp != NULL) { + if (repl) { + State = REPLACE; // pretend Replace mode + ui_cursor_shape(); // show different cursor shape + } + if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) { + // Allow mappings defined with ":lmap". + --no_mapping; + --allow_keys; + if (repl) { + State = LREPLACE; + } else { + State = LANGMAP; + } + langmap_active = true; + } + + *cp = plain_vgetc(); + + if (langmap_active) { + // Undo the decrement done above + ++no_mapping; + ++allow_keys; + State = NORMAL_BUSY; + } + State = NORMAL_BUSY; + s->need_flushbuf |= add_to_showcmd(*cp); + + if (!lit) { + // Typing CTRL-K gets a digraph. + if (*cp == Ctrl_K && ((nv_cmds[s->idx].cmd_flags & NV_LANG) + || cp == &s->ca.extra_char) + && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) { + s->c = get_digraph(false); + if (s->c > 0) { + *cp = s->c; + // Guessing how to update showcmd here... + del_from_showcmd(3); + s->need_flushbuf |= add_to_showcmd(*cp); + } + } + + // adjust chars > 127, except after "tTfFr" commands + LANGMAP_ADJUST(*cp, !lang); + // adjust Hebrew mapped char + if (p_hkmap && lang && KeyTyped) { + *cp = hkmap(*cp); + } + // adjust Farsi mapped char + if (p_fkmap && lang && KeyTyped) { + *cp = fkmap(*cp); + } + } + + // When the next character is CTRL-\ a following CTRL-N means the + // command is aborted and we go to Normal mode. + if (cp == &s->ca.extra_char + && s->ca.nchar == Ctrl_BSL + && (s->ca.extra_char == Ctrl_N || s->ca.extra_char == Ctrl_G)) { + s->ca.cmdchar = Ctrl_BSL; + s->ca.nchar = s->ca.extra_char; + s->idx = find_command(s->ca.cmdchar); + } else if ((s->ca.nchar == 'n' || s->ca.nchar == 'N') + && s->ca.cmdchar == 'g') { + s->ca.oap->op_type = get_op_type(*cp, NUL); + } else if (*cp == Ctrl_BSL) { + long towait = (p_ttm >= 0 ? p_ttm : p_tm); + + // There is a busy wait here when typing "f<C-\>" and then + // something different from CTRL-N. Can't be avoided. + while ((s->c = vpeekc()) <= 0 && towait > 0L) { + do_sleep(towait > 50L ? 50L : towait); + towait -= 50L; + } + if (s->c > 0) { + s->c = plain_vgetc(); + if (s->c != Ctrl_N && s->c != Ctrl_G) { + vungetc(s->c); + } else { + s->ca.cmdchar = Ctrl_BSL; + s->ca.nchar = s->c; + s->idx = find_command(s->ca.cmdchar); + assert(s->idx >= 0); + } + } + } + + // When getting a text character and the next character is a + // multi-byte character, it could be a composing character. + // However, don't wait for it to arrive. Also, do enable mapping, + // because if it's put back with vungetc() it's too late to apply + // mapping. + no_mapping--; + while (enc_utf8 && lang && (s->c = vpeekc()) > 0 + && (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { + s->c = plain_vgetc(); + if (!utf_iscomposing(s->c)) { + vungetc(s->c); /* it wasn't, put it back */ + break; + } else if (s->ca.ncharC1 == 0) { + s->ca.ncharC1 = s->c; + } else { + s->ca.ncharC2 = s->c; + } + } + no_mapping++; + } + --no_mapping; + --allow_keys; +} + +static void normal_invert_horizontal(NormalState *s) +{ + switch (s->ca.cmdchar) { + case 'l': s->ca.cmdchar = 'h'; break; + case K_RIGHT: s->ca.cmdchar = K_LEFT; break; + case K_S_RIGHT: s->ca.cmdchar = K_S_LEFT; break; + case K_C_RIGHT: s->ca.cmdchar = K_C_LEFT; break; + case 'h': s->ca.cmdchar = 'l'; break; + case K_LEFT: s->ca.cmdchar = K_RIGHT; break; + case K_S_LEFT: s->ca.cmdchar = K_S_RIGHT; break; + case K_C_LEFT: s->ca.cmdchar = K_C_RIGHT; break; + case '>': s->ca.cmdchar = '<'; break; + case '<': s->ca.cmdchar = '>'; break; + } + s->idx = find_command(s->ca.cmdchar); +} + +static int normal_execute(VimState *state, int key) { NormalState *s = (NormalState *)state; bool ctrl_w = false; /* got CTRL-W command */ int old_col = curwin->w_curswant; - bool need_flushbuf; /* need to call ui_flush() */ pos_T old_pos; /* cursor position before command */ static int old_mapped_len = 0; - int idx; + s->c = key; - LANGMAP_ADJUST(c, true); + LANGMAP_ADJUST(s->c, true); // If a mapping was started in Visual or Select mode, remember the length // of the mapping. This is used below to not return to Insert mode for as @@ -530,42 +757,42 @@ static int normal_execute(VimState *state, int c) old_mapped_len = typebuf_maplen(); } - if (c == NUL) { - c = K_ZERO; + if (s->c == NUL) { + s->c = K_ZERO; } // In Select mode, typed text replaces the selection. - if (VIsual_active && VIsual_select - && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER)) { + if (VIsual_active && VIsual_select && (vim_isprintc(s->c) + || s->c == NL || s->c == CAR || s->c == K_KENTER)) { // Fake a "c"hange command. When "restart_edit" is set (e.g., because // 'insertmode' is set) fake a "d"elete command, Insert mode will // restart automatically. // Insert the typed character in the typeahead buffer, so that it can // be mapped in Insert mode. Required for ":lmap" to work. - ins_char_typebuf(c); + ins_char_typebuf(s->c); if (restart_edit != 0) { - c = 'd'; + s->c = 'd'; } else { - c = 'c'; + s->c = 'c'; } msg_nowait = true; // don't delay going to insert mode old_mapped_len = 0; // do go to Insert mode } - need_flushbuf = add_to_showcmd(c); + s->need_flushbuf = add_to_showcmd(s->c); getcount: if (!(VIsual_active && VIsual_select)) { // Handle a count before a command and compute ca.count0. // Note that '0' is a command and not the start of a count, but it's // part of a count after other digits. - while ((c >= '1' && c <= '9') || (s->ca.count0 != 0 - && (c == K_DEL || c == K_KDEL || c == '0'))) { - if (c == K_DEL || c == K_KDEL) { + while ((s->c >= '1' && s->c <= '9') || (s->ca.count0 != 0 + && (s->c == K_DEL || s->c == K_KDEL || s->c == '0'))) { + if (s->c == K_DEL || s->c == K_KDEL) { s->ca.count0 /= 10; del_from_showcmd(4); // delete the digit and ~@% } else { - s->ca.count0 = s->ca.count0 * 10 + (c - '0'); + s->ca.count0 = s->ca.count0 * 10 + (s->c - '0'); } if (s->ca.count0 < 0) { @@ -586,33 +813,33 @@ getcount: } ++no_zero_mapping; // don't map zero here - c = plain_vgetc(); - LANGMAP_ADJUST(c, true); + s->c = plain_vgetc(); + LANGMAP_ADJUST(s->c, true); --no_zero_mapping; if (ctrl_w) { --no_mapping; --allow_keys; } - need_flushbuf |= add_to_showcmd(c); + s->need_flushbuf |= add_to_showcmd(s->c); } // If we got CTRL-W there may be a/another count - if (c == Ctrl_W && !ctrl_w && s->oa.op_type == OP_NOP) { + if (s->c == Ctrl_W && !ctrl_w && s->oa.op_type == OP_NOP) { ctrl_w = true; s->ca.opcount = s->ca.count0; // remember first count s->ca.count0 = 0; ++no_mapping; ++allow_keys; // no mapping for nchar, but keys - c = plain_vgetc(); // get next character - LANGMAP_ADJUST(c, true); + s->c = plain_vgetc(); // get next character + LANGMAP_ADJUST(s->c, true); --no_mapping; --allow_keys; - need_flushbuf |= add_to_showcmd(c); + s->need_flushbuf |= add_to_showcmd(s->c); goto getcount; // jump back } } - if (c == K_EVENT) { + if (s->c == K_EVENT) { // Save the count values so that ca.opcount and ca.count0 are exactly // the same when coming back here after handling K_EVENT. s->oa.prev_opcount = s->ca.opcount; @@ -648,243 +875,54 @@ getcount: // Find the command character in the table of commands. // For CTRL-W we already got nchar when looking for a count. if (ctrl_w) { - s->ca.nchar = c; + s->ca.nchar = s->c; s->ca.cmdchar = Ctrl_W; } else { - s->ca.cmdchar = c; + s->ca.cmdchar = s->c; } - idx = find_command(s->ca.cmdchar); + s->idx = find_command(s->ca.cmdchar); - if (idx < 0) { + if (s->idx < 0) { // Not a known command: beep. clearopbeep(&s->oa); goto normal_end; } - if (text_locked() && (nv_cmds[idx].cmd_flags & NV_NCW)) { + if (text_locked() && (nv_cmds[s->idx].cmd_flags & NV_NCW)) { // This command is not allowed while editing a cmdline: beep. clearopbeep(&s->oa); text_locked_msg(); goto normal_end; } - if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked()) { + if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && curbuf_locked()) { goto normal_end; } // In Visual/Select mode, a few keys are handled in a special way. - if (VIsual_active) { - // when 'keymodel' contains "stopsel" may stop Select/Visual mode - if (km_stopsel - && (nv_cmds[idx].cmd_flags & NV_STS) - && !(mod_mask & MOD_MASK_SHIFT)) { - end_visual_mode(); - redraw_curbuf_later(INVERTED); - } - - // Keys that work different when 'keymodel' contains "startsel" - if (km_startsel) { - if (nv_cmds[idx].cmd_flags & NV_SS) { - unshift_special(&s->ca); - idx = find_command(s->ca.cmdchar); - if (idx < 0) { - // Just in case - clearopbeep(&s->oa); - goto normal_end; - } - } else if ((nv_cmds[idx].cmd_flags & NV_SSS) - && (mod_mask & MOD_MASK_SHIFT)) { - mod_mask &= ~MOD_MASK_SHIFT; - } - } + if (VIsual_active && normal_handle_special_visual_command(s)) { + goto normal_end; } if (curwin->w_p_rl && KeyTyped && !KeyStuffed - && (nv_cmds[idx].cmd_flags & NV_RL)) { + && (nv_cmds[s->idx].cmd_flags & NV_RL)) { // Invert horizontal movements and operations. Only when typed by the // user directly, not when the result of a mapping or "x" translated // to "dl". - switch (s->ca.cmdchar) { - case 'l': s->ca.cmdchar = 'h'; break; - case K_RIGHT: s->ca.cmdchar = K_LEFT; break; - case K_S_RIGHT: s->ca.cmdchar = K_S_LEFT; break; - case K_C_RIGHT: s->ca.cmdchar = K_C_LEFT; break; - case 'h': s->ca.cmdchar = 'l'; break; - case K_LEFT: s->ca.cmdchar = K_RIGHT; break; - case K_S_LEFT: s->ca.cmdchar = K_S_RIGHT; break; - case K_C_LEFT: s->ca.cmdchar = K_C_RIGHT; break; - case '>': s->ca.cmdchar = '<'; break; - case '<': s->ca.cmdchar = '>'; break; - } - idx = find_command(s->ca.cmdchar); + normal_invert_horizontal(s); } // Get an additional character if we need one. - if ((nv_cmds[idx].cmd_flags & NV_NCH) - && (((nv_cmds[idx].cmd_flags & NV_NCH_NOP) == NV_NCH_NOP - && s->oa.op_type == OP_NOP) - || (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW - || (s->ca.cmdchar == 'q' - && s->oa.op_type == OP_NOP - && !Recording - && !Exec_reg) - || ((s->ca.cmdchar == 'a' || s->ca.cmdchar == 'i') - && (s->oa.op_type != OP_NOP || VIsual_active)))) { - int *cp; - bool repl = false; // get character for replace mode - bool lit = false; // get extra character literally - bool langmap_active = false; // using :lmap mappings - int lang; // getting a text character - - ++no_mapping; - ++allow_keys; // no mapping for nchar, but allow key codes - // Don't generate a CursorHold event here, most commands can't handle - // it, e.g., nv_replace(), nv_csearch(). - did_cursorhold = true; - if (s->ca.cmdchar == 'g') { - // For 'g' get the next character now, so that we can check for - // "gr", "g'" and "g`". - s->ca.nchar = plain_vgetc(); - LANGMAP_ADJUST(s->ca.nchar, true); - need_flushbuf |= add_to_showcmd(s->ca.nchar); - if (s->ca.nchar == 'r' || s->ca.nchar == '\'' || s->ca.nchar == '`' - || s->ca.nchar == Ctrl_BSL) { - cp = &s->ca.extra_char; // need to get a third character - if (s->ca.nchar != 'r') { - lit = true; // get it literally - } else { - repl = true; // get it in replace mode - } - } else { - cp = NULL; // no third character needed - } - } else { - if (s->ca.cmdchar == 'r') { - // get it in replace mode - repl = true; - } - cp = &s->ca.nchar; - } - lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); - - // Get a second or third character. - if (cp != NULL) { - if (repl) { - State = REPLACE; // pretend Replace mode - ui_cursor_shape(); // show different cursor shape - } - if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) { - // Allow mappings defined with ":lmap". - --no_mapping; - --allow_keys; - if (repl) { - State = LREPLACE; - } else { - State = LANGMAP; - } - langmap_active = true; - } - - *cp = plain_vgetc(); - - if (langmap_active) { - // Undo the decrement done above - ++no_mapping; - ++allow_keys; - State = NORMAL_BUSY; - } - State = NORMAL_BUSY; - need_flushbuf |= add_to_showcmd(*cp); - - if (!lit) { - // Typing CTRL-K gets a digraph. - if (*cp == Ctrl_K && ((nv_cmds[idx].cmd_flags & NV_LANG) - || cp == &s->ca.extra_char) - && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) { - c = get_digraph(false); - if (c > 0) { - *cp = c; - // Guessing how to update showcmd here... - del_from_showcmd(3); - need_flushbuf |= add_to_showcmd(*cp); - } - } - - // adjust chars > 127, except after "tTfFr" commands - LANGMAP_ADJUST(*cp, !lang); - // adjust Hebrew mapped char - if (p_hkmap && lang && KeyTyped) { - *cp = hkmap(*cp); - } - // adjust Farsi mapped char - if (p_fkmap && lang && KeyTyped) { - *cp = fkmap(*cp); - } - } - - // When the next character is CTRL-\ a following CTRL-N means the - // command is aborted and we go to Normal mode. - if (cp == &s->ca.extra_char - && s->ca.nchar == Ctrl_BSL - && (s->ca.extra_char == Ctrl_N || s->ca.extra_char == Ctrl_G)) { - s->ca.cmdchar = Ctrl_BSL; - s->ca.nchar = s->ca.extra_char; - idx = find_command(s->ca.cmdchar); - } else if ((s->ca.nchar == 'n' || s->ca.nchar == 'N') - && s->ca.cmdchar == 'g') { - s->ca.oap->op_type = get_op_type(*cp, NUL); - } else if (*cp == Ctrl_BSL) { - long towait = (p_ttm >= 0 ? p_ttm : p_tm); - - // There is a busy wait here when typing "f<C-\>" and then - // something different from CTRL-N. Can't be avoided. - while ((c = vpeekc()) <= 0 && towait > 0L) { - do_sleep(towait > 50L ? 50L : towait); - towait -= 50L; - } - if (c > 0) { - c = plain_vgetc(); - if (c != Ctrl_N && c != Ctrl_G) { - vungetc(c); - } else { - s->ca.cmdchar = Ctrl_BSL; - s->ca.nchar = c; - idx = find_command(s->ca.cmdchar); - assert(idx >= 0); - } - } - } - - // When getting a text character and the next character is a - // multi-byte character, it could be a composing character. - // However, don't wait for it to arrive. Also, do enable mapping, - // because if it's put back with vungetc() it's too late to apply - // mapping. - no_mapping--; - while (enc_utf8 && lang && (c = vpeekc()) > 0 - && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { - c = plain_vgetc(); - if (!utf_iscomposing(c)) { - vungetc(c); /* it wasn't, put it back */ - break; - } else if (s->ca.ncharC1 == 0) { - s->ca.ncharC1 = c; - } else { - s->ca.ncharC2 = c; - } - } - no_mapping++; - } - --no_mapping; - --allow_keys; + if (normal_need_aditional_char(s)) { + normal_get_additional_char(s); } // Flush the showcmd characters onto the screen so we can see them while // the command is being executed. Only do this when the shown command was // actually displayed, otherwise this will slow down a lot when executing // mappings. - if (need_flushbuf) { + if (s->need_flushbuf) { ui_flush(); } if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) { @@ -911,11 +949,11 @@ getcount: // When 'keymodel' contains "startsel" some keys start Select/Visual // mode. if (!VIsual_active && km_startsel) { - if (nv_cmds[idx].cmd_flags & NV_SS) { + if (nv_cmds[s->idx].cmd_flags & NV_SS) { start_selection(); unshift_special(&s->ca); - idx = find_command(s->ca.cmdchar); - } else if ((nv_cmds[idx].cmd_flags & NV_SSS) + s->idx = find_command(s->ca.cmdchar); + } else if ((nv_cmds[s->idx].cmd_flags & NV_SSS) && (mod_mask & MOD_MASK_SHIFT)) { start_selection(); mod_mask &= ~MOD_MASK_SHIFT; @@ -924,14 +962,14 @@ getcount: // Execute the command! // Call the command function found in the commands table. - s->ca.arg = nv_cmds[idx].cmd_arg; - (nv_cmds[idx].cmd_func)(&s->ca); + s->ca.arg = nv_cmds[s->idx].cmd_arg; + (nv_cmds[s->idx].cmd_func)(&s->ca); // If we didn't start or finish an operator, reset oap->regname, unless we // need it later. if (!finish_op && !s->oa.op_type - && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) { + && (s->idx < 0 || !(nv_cmds[s->idx].cmd_flags & NV_KEEPREG))) { clearop(&s->oa); set_reg_var(get_default_register_name()); } @@ -1009,11 +1047,11 @@ normal_end: msg_nowait = false; // Reset finish_op, in case it was set - c = finish_op; + s->c = finish_op; finish_op = false; // Redraw the cursor with another shape, if we were in Operator-pending // mode or did a replace command. - if (c || s->ca.cmdchar == 'r') { + if (s->c || s->ca.cmdchar == 'r') { ui_cursor_shape(); // may show different cursor shape } |