Mercurial > vim
comparison src/getchar.c @ 17590:8d20183f2a8c v8.1.1792
patch 8.1.1792: the vgetorpeek() function is too long
commit https://github.com/vim/vim/commit/dd00035cb52aa295d3ed3a93338ac04f2c8b35d0
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Aug 2 21:35:33 2019 +0200
patch 8.1.1792: the vgetorpeek() function is too long
Problem: The vgetorpeek() function is too long.
Solution: Split off the part that handles mappings.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 02 Aug 2019 21:45:04 +0200 |
parents | 97a750e8707f |
children | 3b18d5341c03 |
comparison
equal
deleted
inserted
replaced
17589:5c29f5419166 | 17590:8d20183f2a8c |
---|---|
1898 retval = vpeekc(); | 1898 retval = vpeekc(); |
1899 --no_mapping; | 1899 --no_mapping; |
1900 return (retval != NUL); | 1900 return (retval != NUL); |
1901 } | 1901 } |
1902 | 1902 |
1903 typedef enum { | |
1904 map_result_fail, // failed, break loop | |
1905 map_result_get, // get a character from typeahead | |
1906 map_result_retry, // try to map again | |
1907 map_result_nomatch // no matching mapping, get char | |
1908 } map_result_T; | |
1909 | |
1910 /* | |
1911 * Handle mappings in the typeahead buffer. | |
1912 * - When something was mapped, return map_result_retry for recursive mappings. | |
1913 * - When nothing mapped and typeahead has a character return map_result_get. | |
1914 * - When there is no match yet, return map_result_nomatch, need to get more | |
1915 * typeahead. | |
1916 */ | |
1917 static int | |
1918 handle_mapping( | |
1919 int *keylenp, | |
1920 int *timedout, | |
1921 int *mapdepth) | |
1922 { | |
1923 mapblock_T *mp = NULL; | |
1924 mapblock_T *mp2; | |
1925 mapblock_T *mp_match; | |
1926 int mp_match_len = 0; | |
1927 int max_mlen = 0; | |
1928 int tb_c1; | |
1929 int mlen; | |
1930 #ifdef FEAT_LANGMAP | |
1931 int nolmaplen; | |
1932 #endif | |
1933 int keylen; | |
1934 int i; | |
1935 int local_State = get_real_state(); | |
1936 | |
1937 /* | |
1938 * Check for a mappable key sequence. | |
1939 * Walk through one maphash[] list until we find an | |
1940 * entry that matches. | |
1941 * | |
1942 * Don't look for mappings if: | |
1943 * - no_mapping set: mapping disabled (e.g. for CTRL-V) | |
1944 * - maphash_valid not set: no mappings present. | |
1945 * - typebuf.tb_buf[typebuf.tb_off] should not be remapped | |
1946 * - in insert or cmdline mode and 'paste' option set | |
1947 * - waiting for "hit return to continue" and CR or SPACE | |
1948 * typed | |
1949 * - waiting for a char with --more-- | |
1950 * - in Ctrl-X mode, and we get a valid char for that mode | |
1951 */ | |
1952 tb_c1 = typebuf.tb_buf[typebuf.tb_off]; | |
1953 if (no_mapping == 0 && is_maphash_valid() | |
1954 && (no_zero_mapping == 0 || tb_c1 != '0') | |
1955 && (typebuf.tb_maplen == 0 | |
1956 || (p_remap | |
1957 && (typebuf.tb_noremap[typebuf.tb_off] | |
1958 & (RM_NONE|RM_ABBR)) == 0)) | |
1959 && !(p_paste && (State & (INSERT + CMDLINE))) | |
1960 && !(State == HITRETURN && (tb_c1 == CAR || tb_c1 == ' ')) | |
1961 && State != ASKMORE | |
1962 && State != CONFIRM | |
1963 #ifdef FEAT_INS_EXPAND | |
1964 && !((ctrl_x_mode_not_default() | |
1965 && vim_is_ctrl_x_key(tb_c1)) | |
1966 || ((compl_cont_status & CONT_LOCAL) | |
1967 && (tb_c1 == Ctrl_N || tb_c1 == Ctrl_P))) | |
1968 #endif | |
1969 ) | |
1970 { | |
1971 #ifdef FEAT_LANGMAP | |
1972 if (tb_c1 == K_SPECIAL) | |
1973 nolmaplen = 2; | |
1974 else | |
1975 { | |
1976 LANGMAP_ADJUST(tb_c1, | |
1977 (State & (CMDLINE | INSERT)) == 0 | |
1978 && get_real_state() != SELECTMODE); | |
1979 nolmaplen = 0; | |
1980 } | |
1981 #endif | |
1982 // First try buffer-local mappings. | |
1983 mp = get_buf_maphash_list(local_State, tb_c1); | |
1984 mp2 = get_maphash_list(local_State, tb_c1); | |
1985 if (mp == NULL) | |
1986 { | |
1987 // There are no buffer-local mappings. | |
1988 mp = mp2; | |
1989 mp2 = NULL; | |
1990 } | |
1991 /* | |
1992 * Loop until a partly matching mapping is found or | |
1993 * all (local) mappings have been checked. | |
1994 * The longest full match is remembered in "mp_match". | |
1995 * A full match is only accepted if there is no partly | |
1996 * match, so "aa" and "aaa" can both be mapped. | |
1997 */ | |
1998 mp_match = NULL; | |
1999 mp_match_len = 0; | |
2000 for ( ; mp != NULL; | |
2001 mp->m_next == NULL ? (mp = mp2, mp2 = NULL) | |
2002 : (mp = mp->m_next)) | |
2003 { | |
2004 // Only consider an entry if the first character | |
2005 // matches and it is for the current state. | |
2006 // Skip ":lmap" mappings if keys were mapped. | |
2007 if (mp->m_keys[0] == tb_c1 | |
2008 && (mp->m_mode & local_State) | |
2009 && ((mp->m_mode & LANGMAP) == 0 | |
2010 || typebuf.tb_maplen == 0)) | |
2011 { | |
2012 #ifdef FEAT_LANGMAP | |
2013 int nomap = nolmaplen; | |
2014 int c2; | |
2015 #endif | |
2016 // find the match length of this mapping | |
2017 for (mlen = 1; mlen < typebuf.tb_len; ++mlen) | |
2018 { | |
2019 #ifdef FEAT_LANGMAP | |
2020 c2 = typebuf.tb_buf[typebuf.tb_off + mlen]; | |
2021 if (nomap > 0) | |
2022 --nomap; | |
2023 else if (c2 == K_SPECIAL) | |
2024 nomap = 2; | |
2025 else | |
2026 LANGMAP_ADJUST(c2, TRUE); | |
2027 if (mp->m_keys[mlen] != c2) | |
2028 #else | |
2029 if (mp->m_keys[mlen] != | |
2030 typebuf.tb_buf[typebuf.tb_off + mlen]) | |
2031 #endif | |
2032 break; | |
2033 } | |
2034 | |
2035 // Don't allow mapping the first byte(s) of a | |
2036 // multi-byte char. Happens when mapping | |
2037 // <M-a> and then changing 'encoding'. Beware | |
2038 // that 0x80 is escaped. | |
2039 { | |
2040 char_u *p1 = mp->m_keys; | |
2041 char_u *p2 = mb_unescape(&p1); | |
2042 | |
2043 if (has_mbyte && p2 != NULL | |
2044 && MB_BYTE2LEN(tb_c1) > MB_PTR2LEN(p2)) | |
2045 mlen = 0; | |
2046 } | |
2047 | |
2048 // Check an entry whether it matches. | |
2049 // - Full match: mlen == keylen | |
2050 // - Partly match: mlen == typebuf.tb_len | |
2051 keylen = mp->m_keylen; | |
2052 if (mlen == keylen | |
2053 || (mlen == typebuf.tb_len | |
2054 && typebuf.tb_len < keylen)) | |
2055 { | |
2056 char_u *s; | |
2057 int n; | |
2058 | |
2059 // If only script-local mappings are | |
2060 // allowed, check if the mapping starts | |
2061 // with K_SNR. | |
2062 s = typebuf.tb_noremap + typebuf.tb_off; | |
2063 if (*s == RM_SCRIPT | |
2064 && (mp->m_keys[0] != K_SPECIAL | |
2065 || mp->m_keys[1] != KS_EXTRA | |
2066 || mp->m_keys[2] | |
2067 != (int)KE_SNR)) | |
2068 continue; | |
2069 | |
2070 // If one of the typed keys cannot be | |
2071 // remapped, skip the entry. | |
2072 for (n = mlen; --n >= 0; ) | |
2073 if (*s++ & (RM_NONE|RM_ABBR)) | |
2074 break; | |
2075 if (n >= 0) | |
2076 continue; | |
2077 | |
2078 if (keylen > typebuf.tb_len) | |
2079 { | |
2080 if (!*timedout && !(mp_match != NULL | |
2081 && mp_match->m_nowait)) | |
2082 { | |
2083 // break at a partly match | |
2084 keylen = KEYLEN_PART_MAP; | |
2085 break; | |
2086 } | |
2087 } | |
2088 else if (keylen > mp_match_len) | |
2089 { | |
2090 // found a longer match | |
2091 mp_match = mp; | |
2092 mp_match_len = keylen; | |
2093 } | |
2094 } | |
2095 else | |
2096 // No match; may have to check for | |
2097 // termcode at next character. | |
2098 if (max_mlen < mlen) | |
2099 max_mlen = mlen; | |
2100 } | |
2101 } | |
2102 | |
2103 // If no partly match found, use the longest full | |
2104 // match. | |
2105 if (keylen != KEYLEN_PART_MAP) | |
2106 { | |
2107 mp = mp_match; | |
2108 keylen = mp_match_len; | |
2109 } | |
2110 } | |
2111 | |
2112 /* | |
2113 * Check for match with 'pastetoggle' | |
2114 */ | |
2115 if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) | |
2116 { | |
2117 for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen]; | |
2118 ++mlen) | |
2119 if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off | |
2120 + mlen]) | |
2121 break; | |
2122 if (p_pt[mlen] == NUL) // match | |
2123 { | |
2124 // write chars to script file(s) | |
2125 if (mlen > typebuf.tb_maplen) | |
2126 gotchars(typebuf.tb_buf + typebuf.tb_off | |
2127 + typebuf.tb_maplen, | |
2128 mlen - typebuf.tb_maplen); | |
2129 | |
2130 del_typebuf(mlen, 0); // remove the chars | |
2131 set_option_value((char_u *)"paste", | |
2132 (long)!p_paste, NULL, 0); | |
2133 if (!(State & INSERT)) | |
2134 { | |
2135 msg_col = 0; | |
2136 msg_row = Rows - 1; | |
2137 msg_clr_eos(); // clear ruler | |
2138 } | |
2139 status_redraw_all(); | |
2140 redraw_statuslines(); | |
2141 showmode(); | |
2142 setcursor(); | |
2143 *keylenp = keylen; | |
2144 return map_result_retry; | |
2145 } | |
2146 // Need more chars for partly match. | |
2147 if (mlen == typebuf.tb_len) | |
2148 keylen = KEYLEN_PART_KEY; | |
2149 else if (max_mlen < mlen) | |
2150 // no match, may have to check for termcode at | |
2151 // next character | |
2152 max_mlen = mlen + 1; | |
2153 } | |
2154 | |
2155 if ((mp == NULL || max_mlen >= mp_match_len) | |
2156 && keylen != KEYLEN_PART_MAP) | |
2157 { | |
2158 int save_keylen = keylen; | |
2159 | |
2160 /* | |
2161 * When no matching mapping found or found a | |
2162 * non-matching mapping that matches at least what the | |
2163 * matching mapping matched: | |
2164 * Check if we have a terminal code, when: | |
2165 * mapping is allowed, | |
2166 * keys have not been mapped, | |
2167 * and not an ESC sequence, not in insert mode or | |
2168 * p_ek is on, | |
2169 * and when not timed out, | |
2170 */ | |
2171 if ((no_mapping == 0 || allow_keys != 0) | |
2172 && (typebuf.tb_maplen == 0 | |
2173 || (p_remap && typebuf.tb_noremap[ | |
2174 typebuf.tb_off] == RM_YES)) | |
2175 && !*timedout) | |
2176 { | |
2177 keylen = check_termcode(max_mlen + 1, | |
2178 NULL, 0, NULL); | |
2179 | |
2180 // If no termcode matched but 'pastetoggle' | |
2181 // matched partially it's like an incomplete key | |
2182 // sequence. | |
2183 if (keylen == 0 && save_keylen == KEYLEN_PART_KEY) | |
2184 keylen = KEYLEN_PART_KEY; | |
2185 | |
2186 // When getting a partial match, but the last | |
2187 // characters were not typed, don't wait for a | |
2188 // typed character to complete the termcode. | |
2189 // This helps a lot when a ":normal" command ends | |
2190 // in an ESC. | |
2191 if (keylen < 0 | |
2192 && typebuf.tb_len == typebuf.tb_maplen) | |
2193 keylen = 0; | |
2194 } | |
2195 else | |
2196 keylen = 0; | |
2197 if (keylen == 0) // no matching terminal code | |
2198 { | |
2199 #ifdef AMIGA // check for window bounds report | |
2200 if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[ | |
2201 typebuf.tb_off] & 0xff) == CSI) | |
2202 { | |
2203 char_u *s; | |
2204 | |
2205 for (s = typebuf.tb_buf + typebuf.tb_off + 1; | |
2206 s < typebuf.tb_buf + typebuf.tb_off | |
2207 + typebuf.tb_len | |
2208 && (VIM_ISDIGIT(*s) || *s == ';' | |
2209 || *s == ' '); | |
2210 ++s) | |
2211 ; | |
2212 if (*s == 'r' || *s == '|') // found one | |
2213 { | |
2214 del_typebuf((int)(s + 1 - | |
2215 (typebuf.tb_buf + typebuf.tb_off)), 0); | |
2216 // get size and redraw screen | |
2217 shell_resized(); | |
2218 *keylenp = keylen; | |
2219 return map_result_retry; | |
2220 } | |
2221 if (*s == NUL) // need more characters | |
2222 keylen = KEYLEN_PART_KEY; | |
2223 } | |
2224 if (keylen >= 0) | |
2225 #endif | |
2226 // When there was a matching mapping and no | |
2227 // termcode could be replaced after another one, | |
2228 // use that mapping (loop around). If there was | |
2229 // no mapping at all use the character from the | |
2230 // typeahead buffer right here. | |
2231 if (mp == NULL) | |
2232 { | |
2233 *keylenp = keylen; | |
2234 return map_result_get; // got character, break for loop | |
2235 } | |
2236 } | |
2237 | |
2238 if (keylen > 0) // full matching terminal code | |
2239 { | |
2240 #if defined(FEAT_GUI) && defined(FEAT_MENU) | |
2241 if (typebuf.tb_len >= 2 | |
2242 && typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL | |
2243 && typebuf.tb_buf[typebuf.tb_off + 1] | |
2244 == KS_MENU) | |
2245 { | |
2246 int idx; | |
2247 | |
2248 // Using a menu may cause a break in undo! | |
2249 // It's like using gotchars(), but without | |
2250 // recording or writing to a script file. | |
2251 may_sync_undo(); | |
2252 del_typebuf(3, 0); | |
2253 idx = get_menu_index(current_menu, local_State); | |
2254 if (idx != MENU_INDEX_INVALID) | |
2255 { | |
2256 // In Select mode and a Visual mode menu | |
2257 // is used: Switch to Visual mode | |
2258 // temporarily. Append K_SELECT to switch | |
2259 // back to Select mode. | |
2260 if (VIsual_active && VIsual_select | |
2261 && (current_menu->modes & VISUAL)) | |
2262 { | |
2263 VIsual_select = FALSE; | |
2264 (void)ins_typebuf(K_SELECT_STRING, | |
2265 REMAP_NONE, 0, TRUE, FALSE); | |
2266 } | |
2267 ins_typebuf(current_menu->strings[idx], | |
2268 current_menu->noremap[idx], | |
2269 0, TRUE, | |
2270 current_menu->silent[idx]); | |
2271 } | |
2272 } | |
2273 #endif // FEAT_GUI && FEAT_MENU | |
2274 *keylenp = keylen; | |
2275 return map_result_retry; // try mapping again | |
2276 } | |
2277 | |
2278 // Partial match: get some more characters. When a | |
2279 // matching mapping was found use that one. | |
2280 if (mp == NULL || keylen < 0) | |
2281 keylen = KEYLEN_PART_KEY; | |
2282 else | |
2283 keylen = mp_match_len; | |
2284 } | |
2285 | |
2286 /* | |
2287 * complete match | |
2288 */ | |
2289 if (keylen >= 0 && keylen <= typebuf.tb_len) | |
2290 { | |
2291 char_u *map_str; | |
2292 | |
2293 #ifdef FEAT_EVAL | |
2294 int save_m_expr; | |
2295 int save_m_noremap; | |
2296 int save_m_silent; | |
2297 char_u *save_m_keys; | |
2298 char_u *save_m_str; | |
2299 #else | |
2300 # define save_m_noremap mp->m_noremap | |
2301 # define save_m_silent mp->m_silent | |
2302 #endif | |
2303 | |
2304 // write chars to script file(s) | |
2305 if (keylen > typebuf.tb_maplen) | |
2306 gotchars(typebuf.tb_buf + typebuf.tb_off | |
2307 + typebuf.tb_maplen, | |
2308 keylen - typebuf.tb_maplen); | |
2309 | |
2310 cmd_silent = (typebuf.tb_silent > 0); | |
2311 del_typebuf(keylen, 0); // remove the mapped keys | |
2312 | |
2313 /* | |
2314 * Put the replacement string in front of mapstr. | |
2315 * The depth check catches ":map x y" and ":map y x". | |
2316 */ | |
2317 if (++*mapdepth >= p_mmd) | |
2318 { | |
2319 emsg(_("E223: recursive mapping")); | |
2320 if (State & CMDLINE) | |
2321 redrawcmdline(); | |
2322 else | |
2323 setcursor(); | |
2324 flush_buffers(FLUSH_MINIMAL); | |
2325 *mapdepth = 0; /* for next one */ | |
2326 *keylenp = keylen; | |
2327 return map_result_fail; | |
2328 } | |
2329 | |
2330 /* | |
2331 * In Select mode and a Visual mode mapping is used: | |
2332 * Switch to Visual mode temporarily. Append K_SELECT | |
2333 * to switch back to Select mode. | |
2334 */ | |
2335 if (VIsual_active && VIsual_select | |
2336 && (mp->m_mode & VISUAL)) | |
2337 { | |
2338 VIsual_select = FALSE; | |
2339 (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, | |
2340 0, TRUE, FALSE); | |
2341 } | |
2342 | |
2343 #ifdef FEAT_EVAL | |
2344 // Copy the values from *mp that are used, because | |
2345 // evaluating the expression may invoke a function | |
2346 // that redefines the mapping, thereby making *mp | |
2347 // invalid. | |
2348 save_m_expr = mp->m_expr; | |
2349 save_m_noremap = mp->m_noremap; | |
2350 save_m_silent = mp->m_silent; | |
2351 save_m_keys = NULL; // only saved when needed | |
2352 save_m_str = NULL; // only saved when needed | |
2353 | |
2354 /* | |
2355 * Handle ":map <expr>": evaluate the {rhs} as an | |
2356 * expression. Also save and restore the command line | |
2357 * for "normal :". | |
2358 */ | |
2359 if (mp->m_expr) | |
2360 { | |
2361 int save_vgetc_busy = vgetc_busy; | |
2362 int save_may_garbage_collect = may_garbage_collect; | |
2363 | |
2364 vgetc_busy = 0; | |
2365 may_garbage_collect = FALSE; | |
2366 | |
2367 save_m_keys = vim_strsave(mp->m_keys); | |
2368 save_m_str = vim_strsave(mp->m_str); | |
2369 map_str = eval_map_expr(save_m_str, NUL); | |
2370 | |
2371 vgetc_busy = save_vgetc_busy; | |
2372 may_garbage_collect = save_may_garbage_collect; | |
2373 } | |
2374 else | |
2375 #endif | |
2376 map_str = mp->m_str; | |
2377 | |
2378 /* | |
2379 * Insert the 'to' part in the typebuf.tb_buf. | |
2380 * If 'from' field is the same as the start of the | |
2381 * 'to' field, don't remap the first character (but do | |
2382 * allow abbreviations). | |
2383 * If m_noremap is set, don't remap the whole 'to' | |
2384 * part. | |
2385 */ | |
2386 if (map_str == NULL) | |
2387 i = FAIL; | |
2388 else | |
2389 { | |
2390 int noremap; | |
2391 | |
2392 if (save_m_noremap != REMAP_YES) | |
2393 noremap = save_m_noremap; | |
2394 else if ( | |
2395 #ifdef FEAT_EVAL | |
2396 STRNCMP(map_str, save_m_keys != NULL | |
2397 ? save_m_keys : mp->m_keys, | |
2398 (size_t)keylen) | |
2399 #else | |
2400 STRNCMP(map_str, mp->m_keys, (size_t)keylen) | |
2401 #endif | |
2402 != 0) | |
2403 noremap = REMAP_YES; | |
2404 else | |
2405 noremap = REMAP_SKIP; | |
2406 i = ins_typebuf(map_str, noremap, | |
2407 0, TRUE, cmd_silent || save_m_silent); | |
2408 #ifdef FEAT_EVAL | |
2409 if (save_m_expr) | |
2410 vim_free(map_str); | |
2411 #endif | |
2412 } | |
2413 #ifdef FEAT_EVAL | |
2414 vim_free(save_m_keys); | |
2415 vim_free(save_m_str); | |
2416 #endif | |
2417 *keylenp = keylen; | |
2418 if (i == FAIL) | |
2419 return map_result_fail; | |
2420 return map_result_retry; | |
2421 } | |
2422 | |
2423 *keylenp = keylen; | |
2424 return map_result_nomatch; | |
2425 } | |
2426 | |
1903 /* | 2427 /* |
1904 * unget one character (can only be done once!) | 2428 * unget one character (can only be done once!) |
1905 */ | 2429 */ |
1906 void | 2430 void |
1907 vungetc(int c) | 2431 vungetc(int c) |
1940 */ | 2464 */ |
1941 static int | 2465 static int |
1942 vgetorpeek(int advance) | 2466 vgetorpeek(int advance) |
1943 { | 2467 { |
1944 int c, c1; | 2468 int c, c1; |
1945 int keylen; | |
1946 char_u *s; | |
1947 mapblock_T *mp; | |
1948 mapblock_T *mp2; | |
1949 mapblock_T *mp_match; | |
1950 int mp_match_len = 0; | |
1951 int timedout = FALSE; /* waited for more than 1 second | 2469 int timedout = FALSE; /* waited for more than 1 second |
1952 for mapping to complete */ | 2470 for mapping to complete */ |
1953 int mapdepth = 0; /* check for recursive mapping */ | 2471 int mapdepth = 0; /* check for recursive mapping */ |
1954 int mode_deleted = FALSE; /* set when mode has been deleted */ | 2472 int mode_deleted = FALSE; /* set when mode has been deleted */ |
1955 int local_State; | |
1956 int mlen; | |
1957 int max_mlen; | |
1958 int i; | 2473 int i; |
1959 #ifdef FEAT_CMDL_INFO | 2474 #ifdef FEAT_CMDL_INFO |
1960 int new_wcol, new_wrow; | 2475 int new_wcol, new_wrow; |
1961 #endif | 2476 #endif |
1962 #ifdef FEAT_GUI | 2477 #ifdef FEAT_GUI |
1963 # ifdef FEAT_MENU | |
1964 int idx; | |
1965 # endif | |
1966 int shape_changed = FALSE; /* adjusted cursor shape */ | 2478 int shape_changed = FALSE; /* adjusted cursor shape */ |
1967 #endif | 2479 #endif |
1968 int n; | 2480 int n; |
1969 #ifdef FEAT_LANGMAP | |
1970 int nolmaplen; | |
1971 #endif | |
1972 int old_wcol, old_wrow; | 2481 int old_wcol, old_wrow; |
1973 int wait_tb_len; | 2482 int wait_tb_len; |
1974 | 2483 |
1975 /* | 2484 /* |
1976 * This function doesn't work very well when called recursively. This may | 2485 * This function doesn't work very well when called recursively. This may |
1984 * thus it should be OK. But don't get a key from the user then. | 2493 * thus it should be OK. But don't get a key from the user then. |
1985 */ | 2494 */ |
1986 if (vgetc_busy > 0 && ex_normal_busy == 0) | 2495 if (vgetc_busy > 0 && ex_normal_busy == 0) |
1987 return NUL; | 2496 return NUL; |
1988 | 2497 |
1989 local_State = get_real_state(); | |
1990 | |
1991 ++vgetc_busy; | 2498 ++vgetc_busy; |
1992 | 2499 |
1993 if (advance) | 2500 if (advance) |
1994 KeyStuffed = FALSE; | 2501 KeyStuffed = FALSE; |
1995 | 2502 |
2030 * If a mapped key sequence is found we go back to the start to | 2537 * If a mapped key sequence is found we go back to the start to |
2031 * try re-mapping. | 2538 * try re-mapping. |
2032 */ | 2539 */ |
2033 for (;;) | 2540 for (;;) |
2034 { | 2541 { |
2035 long wait_time; | 2542 long wait_time; |
2543 int keylen = 0; | |
2036 | 2544 |
2037 /* | 2545 /* |
2038 * ui_breakcheck() is slow, don't use it too often when | 2546 * ui_breakcheck() is slow, don't use it too often when |
2039 * inside a mapping. But call it each time for typed | 2547 * inside a mapping. But call it each time for typed |
2040 * characters. | 2548 * characters. |
2041 */ | 2549 */ |
2042 if (typebuf.tb_maplen) | 2550 if (typebuf.tb_maplen) |
2043 line_breakcheck(); | 2551 line_breakcheck(); |
2044 else | 2552 else |
2045 ui_breakcheck(); /* check for CTRL-C */ | 2553 ui_breakcheck(); /* check for CTRL-C */ |
2046 keylen = 0; | |
2047 if (got_int) | 2554 if (got_int) |
2048 { | 2555 { |
2049 /* flush all input */ | 2556 /* flush all input */ |
2050 c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L); | 2557 c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L); |
2558 | |
2051 /* | 2559 /* |
2052 * If inchar() returns TRUE (script file was active) or we | 2560 * If inchar() returns TRUE (script file was active) or we |
2053 * are inside a mapping, get out of Insert mode. | 2561 * are inside a mapping, get out of Insert mode. |
2054 * Otherwise we behave like having gotten a CTRL-C. | 2562 * Otherwise we behave like having gotten a CTRL-C. |
2055 * As a result typing CTRL-C in insert mode will | 2563 * As a result typing CTRL-C in insert mode will |
2074 break; | 2582 break; |
2075 } | 2583 } |
2076 else if (typebuf.tb_len > 0) | 2584 else if (typebuf.tb_len > 0) |
2077 { | 2585 { |
2078 /* | 2586 /* |
2079 * Check for a mappable key sequence. | 2587 * Check for a mapping in "typebuf". |
2080 * Walk through one maphash[] list until we find an | |
2081 * entry that matches. | |
2082 * | |
2083 * Don't look for mappings if: | |
2084 * - no_mapping set: mapping disabled (e.g. for CTRL-V) | |
2085 * - maphash_valid not set: no mappings present. | |
2086 * - typebuf.tb_buf[typebuf.tb_off] should not be remapped | |
2087 * - in insert or cmdline mode and 'paste' option set | |
2088 * - waiting for "hit return to continue" and CR or SPACE | |
2089 * typed | |
2090 * - waiting for a char with --more-- | |
2091 * - in Ctrl-X mode, and we get a valid char for that mode | |
2092 */ | 2588 */ |
2093 mp = NULL; | 2589 map_result_T result = handle_mapping( |
2094 max_mlen = 0; | 2590 &keylen, &timedout, &mapdepth); |
2095 c1 = typebuf.tb_buf[typebuf.tb_off]; | 2591 |
2096 if (no_mapping == 0 && is_maphash_valid() | 2592 if (result == map_result_retry) |
2097 && (no_zero_mapping == 0 || c1 != '0') | 2593 // try mapping again |
2098 && (typebuf.tb_maplen == 0 | 2594 continue; |
2099 || (p_remap | 2595 if (result == map_result_fail) |
2100 && (typebuf.tb_noremap[typebuf.tb_off] | |
2101 & (RM_NONE|RM_ABBR)) == 0)) | |
2102 && !(p_paste && (State & (INSERT + CMDLINE))) | |
2103 && !(State == HITRETURN && (c1 == CAR || c1 == ' ')) | |
2104 && State != ASKMORE | |
2105 && State != CONFIRM | |
2106 #ifdef FEAT_INS_EXPAND | |
2107 && !((ctrl_x_mode_not_default() | |
2108 && vim_is_ctrl_x_key(c1)) | |
2109 || ((compl_cont_status & CONT_LOCAL) | |
2110 && (c1 == Ctrl_N || c1 == Ctrl_P))) | |
2111 #endif | |
2112 ) | |
2113 { | 2596 { |
2114 #ifdef FEAT_LANGMAP | 2597 // failed, use the outer loop |
2115 if (c1 == K_SPECIAL) | 2598 c = -1; |
2116 nolmaplen = 2; | 2599 break; |
2117 else | 2600 } |
2601 if (result == map_result_get) | |
2602 { | |
2603 /* | |
2604 * get a character: 2. from the typeahead buffer | |
2605 */ | |
2606 c = typebuf.tb_buf[typebuf.tb_off] & 255; | |
2607 if (advance) /* remove chars from tb_buf */ | |
2118 { | 2608 { |
2119 LANGMAP_ADJUST(c1, | 2609 cmd_silent = (typebuf.tb_silent > 0); |
2120 (State & (CMDLINE | INSERT)) == 0 | 2610 if (typebuf.tb_maplen > 0) |
2121 && get_real_state() != SELECTMODE); | 2611 KeyTyped = FALSE; |
2122 nolmaplen = 0; | 2612 else |
2613 { | |
2614 KeyTyped = TRUE; | |
2615 /* write char to script file(s) */ | |
2616 gotchars(typebuf.tb_buf | |
2617 + typebuf.tb_off, 1); | |
2618 } | |
2619 KeyNoremap = typebuf.tb_noremap[ | |
2620 typebuf.tb_off]; | |
2621 del_typebuf(1, 0); | |
2123 } | 2622 } |
2124 #endif | 2623 break; |
2125 // First try buffer-local mappings. | |
2126 mp = get_buf_maphash_list(local_State, c1); | |
2127 mp2 = get_maphash_list(local_State, c1); | |
2128 if (mp == NULL) | |
2129 { | |
2130 // There are no buffer-local mappings. | |
2131 mp = mp2; | |
2132 mp2 = NULL; | |
2133 } | |
2134 /* | |
2135 * Loop until a partly matching mapping is found or | |
2136 * all (local) mappings have been checked. | |
2137 * The longest full match is remembered in "mp_match". | |
2138 * A full match is only accepted if there is no partly | |
2139 * match, so "aa" and "aaa" can both be mapped. | |
2140 */ | |
2141 mp_match = NULL; | |
2142 mp_match_len = 0; | |
2143 for ( ; mp != NULL; | |
2144 mp->m_next == NULL ? (mp = mp2, mp2 = NULL) | |
2145 : (mp = mp->m_next)) | |
2146 { | |
2147 /* | |
2148 * Only consider an entry if the first character | |
2149 * matches and it is for the current state. | |
2150 * Skip ":lmap" mappings if keys were mapped. | |
2151 */ | |
2152 if (mp->m_keys[0] == c1 | |
2153 && (mp->m_mode & local_State) | |
2154 && ((mp->m_mode & LANGMAP) == 0 | |
2155 || typebuf.tb_maplen == 0)) | |
2156 { | |
2157 #ifdef FEAT_LANGMAP | |
2158 int nomap = nolmaplen; | |
2159 int c2; | |
2160 #endif | |
2161 /* find the match length of this mapping */ | |
2162 for (mlen = 1; mlen < typebuf.tb_len; ++mlen) | |
2163 { | |
2164 #ifdef FEAT_LANGMAP | |
2165 c2 = typebuf.tb_buf[typebuf.tb_off + mlen]; | |
2166 if (nomap > 0) | |
2167 --nomap; | |
2168 else if (c2 == K_SPECIAL) | |
2169 nomap = 2; | |
2170 else | |
2171 LANGMAP_ADJUST(c2, TRUE); | |
2172 if (mp->m_keys[mlen] != c2) | |
2173 #else | |
2174 if (mp->m_keys[mlen] != | |
2175 typebuf.tb_buf[typebuf.tb_off + mlen]) | |
2176 #endif | |
2177 break; | |
2178 } | |
2179 | |
2180 /* Don't allow mapping the first byte(s) of a | |
2181 * multi-byte char. Happens when mapping | |
2182 * <M-a> and then changing 'encoding'. Beware | |
2183 * that 0x80 is escaped. */ | |
2184 { | |
2185 char_u *p1 = mp->m_keys; | |
2186 char_u *p2 = mb_unescape(&p1); | |
2187 | |
2188 if (has_mbyte && p2 != NULL | |
2189 && MB_BYTE2LEN(c1) > MB_PTR2LEN(p2)) | |
2190 mlen = 0; | |
2191 } | |
2192 /* | |
2193 * Check an entry whether it matches. | |
2194 * - Full match: mlen == keylen | |
2195 * - Partly match: mlen == typebuf.tb_len | |
2196 */ | |
2197 keylen = mp->m_keylen; | |
2198 if (mlen == keylen | |
2199 || (mlen == typebuf.tb_len | |
2200 && typebuf.tb_len < keylen)) | |
2201 { | |
2202 /* | |
2203 * If only script-local mappings are | |
2204 * allowed, check if the mapping starts | |
2205 * with K_SNR. | |
2206 */ | |
2207 s = typebuf.tb_noremap + typebuf.tb_off; | |
2208 if (*s == RM_SCRIPT | |
2209 && (mp->m_keys[0] != K_SPECIAL | |
2210 || mp->m_keys[1] != KS_EXTRA | |
2211 || mp->m_keys[2] | |
2212 != (int)KE_SNR)) | |
2213 continue; | |
2214 /* | |
2215 * If one of the typed keys cannot be | |
2216 * remapped, skip the entry. | |
2217 */ | |
2218 for (n = mlen; --n >= 0; ) | |
2219 if (*s++ & (RM_NONE|RM_ABBR)) | |
2220 break; | |
2221 if (n >= 0) | |
2222 continue; | |
2223 | |
2224 if (keylen > typebuf.tb_len) | |
2225 { | |
2226 if (!timedout && !(mp_match != NULL | |
2227 && mp_match->m_nowait)) | |
2228 { | |
2229 /* break at a partly match */ | |
2230 keylen = KEYLEN_PART_MAP; | |
2231 break; | |
2232 } | |
2233 } | |
2234 else if (keylen > mp_match_len) | |
2235 { | |
2236 /* found a longer match */ | |
2237 mp_match = mp; | |
2238 mp_match_len = keylen; | |
2239 } | |
2240 } | |
2241 else | |
2242 /* No match; may have to check for | |
2243 * termcode at next character. */ | |
2244 if (max_mlen < mlen) | |
2245 max_mlen = mlen; | |
2246 } | |
2247 } | |
2248 | |
2249 /* If no partly match found, use the longest full | |
2250 * match. */ | |
2251 if (keylen != KEYLEN_PART_MAP) | |
2252 { | |
2253 mp = mp_match; | |
2254 keylen = mp_match_len; | |
2255 } | |
2256 } | 2624 } |
2257 | 2625 |
2258 /* Check for match with 'pastetoggle' */ | 2626 // not enough characters, get more |
2259 if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) | |
2260 { | |
2261 for (mlen = 0; mlen < typebuf.tb_len && p_pt[mlen]; | |
2262 ++mlen) | |
2263 if (p_pt[mlen] != typebuf.tb_buf[typebuf.tb_off | |
2264 + mlen]) | |
2265 break; | |
2266 if (p_pt[mlen] == NUL) /* match */ | |
2267 { | |
2268 /* write chars to script file(s) */ | |
2269 if (mlen > typebuf.tb_maplen) | |
2270 gotchars(typebuf.tb_buf + typebuf.tb_off | |
2271 + typebuf.tb_maplen, | |
2272 mlen - typebuf.tb_maplen); | |
2273 | |
2274 del_typebuf(mlen, 0); /* remove the chars */ | |
2275 set_option_value((char_u *)"paste", | |
2276 (long)!p_paste, NULL, 0); | |
2277 if (!(State & INSERT)) | |
2278 { | |
2279 msg_col = 0; | |
2280 msg_row = Rows - 1; | |
2281 msg_clr_eos(); /* clear ruler */ | |
2282 } | |
2283 status_redraw_all(); | |
2284 redraw_statuslines(); | |
2285 showmode(); | |
2286 setcursor(); | |
2287 continue; | |
2288 } | |
2289 /* Need more chars for partly match. */ | |
2290 if (mlen == typebuf.tb_len) | |
2291 keylen = KEYLEN_PART_KEY; | |
2292 else if (max_mlen < mlen) | |
2293 /* no match, may have to check for termcode at | |
2294 * next character */ | |
2295 max_mlen = mlen + 1; | |
2296 } | |
2297 | |
2298 if ((mp == NULL || max_mlen >= mp_match_len) | |
2299 && keylen != KEYLEN_PART_MAP) | |
2300 { | |
2301 int save_keylen = keylen; | |
2302 | |
2303 /* | |
2304 * When no matching mapping found or found a | |
2305 * non-matching mapping that matches at least what the | |
2306 * matching mapping matched: | |
2307 * Check if we have a terminal code, when: | |
2308 * mapping is allowed, | |
2309 * keys have not been mapped, | |
2310 * and not an ESC sequence, not in insert mode or | |
2311 * p_ek is on, | |
2312 * and when not timed out, | |
2313 */ | |
2314 if ((no_mapping == 0 || allow_keys != 0) | |
2315 && (typebuf.tb_maplen == 0 | |
2316 || (p_remap && typebuf.tb_noremap[ | |
2317 typebuf.tb_off] == RM_YES)) | |
2318 && !timedout) | |
2319 { | |
2320 keylen = check_termcode(max_mlen + 1, | |
2321 NULL, 0, NULL); | |
2322 | |
2323 /* If no termcode matched but 'pastetoggle' | |
2324 * matched partially it's like an incomplete key | |
2325 * sequence. */ | |
2326 if (keylen == 0 && save_keylen == KEYLEN_PART_KEY) | |
2327 keylen = KEYLEN_PART_KEY; | |
2328 | |
2329 /* | |
2330 * When getting a partial match, but the last | |
2331 * characters were not typed, don't wait for a | |
2332 * typed character to complete the termcode. | |
2333 * This helps a lot when a ":normal" command ends | |
2334 * in an ESC. | |
2335 */ | |
2336 if (keylen < 0 | |
2337 && typebuf.tb_len == typebuf.tb_maplen) | |
2338 keylen = 0; | |
2339 } | |
2340 else | |
2341 keylen = 0; | |
2342 if (keylen == 0) /* no matching terminal code */ | |
2343 { | |
2344 #ifdef AMIGA /* check for window bounds report */ | |
2345 if (typebuf.tb_maplen == 0 && (typebuf.tb_buf[ | |
2346 typebuf.tb_off] & 0xff) == CSI) | |
2347 { | |
2348 for (s = typebuf.tb_buf + typebuf.tb_off + 1; | |
2349 s < typebuf.tb_buf + typebuf.tb_off | |
2350 + typebuf.tb_len | |
2351 && (VIM_ISDIGIT(*s) || *s == ';' | |
2352 || *s == ' '); | |
2353 ++s) | |
2354 ; | |
2355 if (*s == 'r' || *s == '|') /* found one */ | |
2356 { | |
2357 del_typebuf((int)(s + 1 - | |
2358 (typebuf.tb_buf + typebuf.tb_off)), 0); | |
2359 /* get size and redraw screen */ | |
2360 shell_resized(); | |
2361 continue; | |
2362 } | |
2363 if (*s == NUL) /* need more characters */ | |
2364 keylen = KEYLEN_PART_KEY; | |
2365 } | |
2366 if (keylen >= 0) | |
2367 #endif | |
2368 /* When there was a matching mapping and no | |
2369 * termcode could be replaced after another one, | |
2370 * use that mapping (loop around). If there was | |
2371 * no mapping use the character from the | |
2372 * typeahead buffer right here. */ | |
2373 if (mp == NULL) | |
2374 { | |
2375 /* | |
2376 * get a character: 2. from the typeahead buffer | |
2377 */ | |
2378 c = typebuf.tb_buf[typebuf.tb_off] & 255; | |
2379 if (advance) /* remove chars from tb_buf */ | |
2380 { | |
2381 cmd_silent = (typebuf.tb_silent > 0); | |
2382 if (typebuf.tb_maplen > 0) | |
2383 KeyTyped = FALSE; | |
2384 else | |
2385 { | |
2386 KeyTyped = TRUE; | |
2387 /* write char to script file(s) */ | |
2388 gotchars(typebuf.tb_buf | |
2389 + typebuf.tb_off, 1); | |
2390 } | |
2391 KeyNoremap = typebuf.tb_noremap[ | |
2392 typebuf.tb_off]; | |
2393 del_typebuf(1, 0); | |
2394 } | |
2395 break; /* got character, break for loop */ | |
2396 } | |
2397 } | |
2398 if (keylen > 0) /* full matching terminal code */ | |
2399 { | |
2400 #if defined(FEAT_GUI) && defined(FEAT_MENU) | |
2401 if (typebuf.tb_len >= 2 | |
2402 && typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL | |
2403 && typebuf.tb_buf[typebuf.tb_off + 1] | |
2404 == KS_MENU) | |
2405 { | |
2406 /* | |
2407 * Using a menu may cause a break in undo! | |
2408 * It's like using gotchars(), but without | |
2409 * recording or writing to a script file. | |
2410 */ | |
2411 may_sync_undo(); | |
2412 del_typebuf(3, 0); | |
2413 idx = get_menu_index(current_menu, local_State); | |
2414 if (idx != MENU_INDEX_INVALID) | |
2415 { | |
2416 /* | |
2417 * In Select mode and a Visual mode menu | |
2418 * is used: Switch to Visual mode | |
2419 * temporarily. Append K_SELECT to switch | |
2420 * back to Select mode. | |
2421 */ | |
2422 if (VIsual_active && VIsual_select | |
2423 && (current_menu->modes & VISUAL)) | |
2424 { | |
2425 VIsual_select = FALSE; | |
2426 (void)ins_typebuf(K_SELECT_STRING, | |
2427 REMAP_NONE, 0, TRUE, FALSE); | |
2428 } | |
2429 ins_typebuf(current_menu->strings[idx], | |
2430 current_menu->noremap[idx], | |
2431 0, TRUE, | |
2432 current_menu->silent[idx]); | |
2433 } | |
2434 } | |
2435 #endif /* FEAT_GUI && FEAT_MENU */ | |
2436 continue; /* try mapping again */ | |
2437 } | |
2438 | |
2439 /* Partial match: get some more characters. When a | |
2440 * matching mapping was found use that one. */ | |
2441 if (mp == NULL || keylen < 0) | |
2442 keylen = KEYLEN_PART_KEY; | |
2443 else | |
2444 keylen = mp_match_len; | |
2445 } | |
2446 | |
2447 /* complete match */ | |
2448 if (keylen >= 0 && keylen <= typebuf.tb_len) | |
2449 { | |
2450 #ifdef FEAT_EVAL | |
2451 int save_m_expr; | |
2452 int save_m_noremap; | |
2453 int save_m_silent; | |
2454 char_u *save_m_keys; | |
2455 char_u *save_m_str; | |
2456 #else | |
2457 # define save_m_noremap mp->m_noremap | |
2458 # define save_m_silent mp->m_silent | |
2459 #endif | |
2460 | |
2461 /* write chars to script file(s) */ | |
2462 if (keylen > typebuf.tb_maplen) | |
2463 gotchars(typebuf.tb_buf + typebuf.tb_off | |
2464 + typebuf.tb_maplen, | |
2465 keylen - typebuf.tb_maplen); | |
2466 | |
2467 cmd_silent = (typebuf.tb_silent > 0); | |
2468 del_typebuf(keylen, 0); /* remove the mapped keys */ | |
2469 | |
2470 /* | |
2471 * Put the replacement string in front of mapstr. | |
2472 * The depth check catches ":map x y" and ":map y x". | |
2473 */ | |
2474 if (++mapdepth >= p_mmd) | |
2475 { | |
2476 emsg(_("E223: recursive mapping")); | |
2477 if (State & CMDLINE) | |
2478 redrawcmdline(); | |
2479 else | |
2480 setcursor(); | |
2481 flush_buffers(FLUSH_MINIMAL); | |
2482 mapdepth = 0; /* for next one */ | |
2483 c = -1; | |
2484 break; | |
2485 } | |
2486 | |
2487 /* | |
2488 * In Select mode and a Visual mode mapping is used: | |
2489 * Switch to Visual mode temporarily. Append K_SELECT | |
2490 * to switch back to Select mode. | |
2491 */ | |
2492 if (VIsual_active && VIsual_select | |
2493 && (mp->m_mode & VISUAL)) | |
2494 { | |
2495 VIsual_select = FALSE; | |
2496 (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, | |
2497 0, TRUE, FALSE); | |
2498 } | |
2499 | |
2500 #ifdef FEAT_EVAL | |
2501 /* Copy the values from *mp that are used, because | |
2502 * evaluating the expression may invoke a function | |
2503 * that redefines the mapping, thereby making *mp | |
2504 * invalid. */ | |
2505 save_m_expr = mp->m_expr; | |
2506 save_m_noremap = mp->m_noremap; | |
2507 save_m_silent = mp->m_silent; | |
2508 save_m_keys = NULL; /* only saved when needed */ | |
2509 save_m_str = NULL; /* only saved when needed */ | |
2510 | |
2511 /* | |
2512 * Handle ":map <expr>": evaluate the {rhs} as an | |
2513 * expression. Also save and restore the command line | |
2514 * for "normal :". | |
2515 */ | |
2516 if (mp->m_expr) | |
2517 { | |
2518 int save_vgetc_busy = vgetc_busy; | |
2519 int save_may_garbage_collect = may_garbage_collect; | |
2520 | |
2521 vgetc_busy = 0; | |
2522 may_garbage_collect = FALSE; | |
2523 | |
2524 save_m_keys = vim_strsave(mp->m_keys); | |
2525 save_m_str = vim_strsave(mp->m_str); | |
2526 s = eval_map_expr(save_m_str, NUL); | |
2527 | |
2528 vgetc_busy = save_vgetc_busy; | |
2529 may_garbage_collect = save_may_garbage_collect; | |
2530 } | |
2531 else | |
2532 #endif | |
2533 s = mp->m_str; | |
2534 | |
2535 /* | |
2536 * Insert the 'to' part in the typebuf.tb_buf. | |
2537 * If 'from' field is the same as the start of the | |
2538 * 'to' field, don't remap the first character (but do | |
2539 * allow abbreviations). | |
2540 * If m_noremap is set, don't remap the whole 'to' | |
2541 * part. | |
2542 */ | |
2543 if (s == NULL) | |
2544 i = FAIL; | |
2545 else | |
2546 { | |
2547 int noremap; | |
2548 | |
2549 if (save_m_noremap != REMAP_YES) | |
2550 noremap = save_m_noremap; | |
2551 else if ( | |
2552 #ifdef FEAT_EVAL | |
2553 STRNCMP(s, save_m_keys != NULL | |
2554 ? save_m_keys : mp->m_keys, | |
2555 (size_t)keylen) | |
2556 #else | |
2557 STRNCMP(s, mp->m_keys, (size_t)keylen) | |
2558 #endif | |
2559 != 0) | |
2560 noremap = REMAP_YES; | |
2561 else | |
2562 noremap = REMAP_SKIP; | |
2563 i = ins_typebuf(s, noremap, | |
2564 0, TRUE, cmd_silent || save_m_silent); | |
2565 #ifdef FEAT_EVAL | |
2566 if (save_m_expr) | |
2567 vim_free(s); | |
2568 #endif | |
2569 } | |
2570 #ifdef FEAT_EVAL | |
2571 vim_free(save_m_keys); | |
2572 vim_free(save_m_str); | |
2573 #endif | |
2574 if (i == FAIL) | |
2575 { | |
2576 c = -1; | |
2577 break; | |
2578 } | |
2579 continue; | |
2580 } | |
2581 } | 2627 } |
2582 | 2628 |
2583 /* | 2629 /* |
2584 * get a character: 3. from the user - handle <Esc> in Insert mode | 2630 * get a character: 3. from the user - handle <Esc> in Insert mode |
2585 */ | 2631 */ |