diff options
Diffstat (limited to 'src/nvim/ex_getln.c')
-rw-r--r-- | src/nvim/ex_getln.c | 270 |
1 files changed, 200 insertions, 70 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a4e5a4dcd7..dba7a73814 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -34,7 +34,6 @@ #include "nvim/menu.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" #include "nvim/memory.h" #include "nvim/cursor_shape.h" #include "nvim/keymap.h" @@ -96,19 +95,20 @@ typedef struct command_line_state { char_u *lookfor; // string to match int hiscnt; // current history line in use int histype; // history type to be used - pos_T old_cursor; - colnr_T old_curswant; - colnr_T old_leftcol; - linenr_T old_topline; - int old_topfill; - linenr_T old_botline; + pos_T old_cursor; + colnr_T old_curswant; + colnr_T old_leftcol; + linenr_T old_topline; + int old_topfill; + linenr_T old_botline; int did_incsearch; int incsearch_postponed; int did_wild_list; // did wild_list() recently int wim_index; // index in wim_flags[] int res; - int save_msg_scroll; - int save_State; // remember State when called + int save_msg_scroll; + int save_State; // remember State when called + char_u *save_p_icm; int some_key_typed; // one of the keys was typed // mouse drag and release events are ignored, unless they are // preceded with a mouse down event @@ -160,6 +160,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) s->indent = indent; s->save_msg_scroll = msg_scroll; s->save_State = State; + s->save_p_icm = vim_strsave(p_icm); s->ignore_drag_release = true; if (s->firstc == -1) { @@ -324,9 +325,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) need_wait_return = false; } + set_string_option_direct((char_u *)"icm", -1, s->save_p_icm, OPT_FREE, + SID_NONE); State = s->save_State; setmouse(); ui_cursor_shape(); // may show different cursor shape + xfree(s->save_p_icm); { char_u *p = ccline.cmdbuff; @@ -358,7 +362,8 @@ static int command_line_execute(VimState *state, int key) s->c = key; if (s->c == K_EVENT) { - queue_process_events(loop.events); + multiqueue_process_events(main_loop.events); + redrawcmdline(); return 1; } @@ -981,7 +986,6 @@ static int command_line_handle_key(CommandLineState *s) status_redraw_curbuf(); return command_line_not_changed(s); - // case '@': only in very old vi case Ctrl_U: // delete all characters left of the cursor s->j = ccline.cmdpos; @@ -996,7 +1000,6 @@ static int command_line_handle_key(CommandLineState *s) redrawcmd(); return command_line_changed(s); - case ESC: // get here if p_wc != ESC or when ESC typed twice case Ctrl_C: // In exmode it doesn't make sense to return. Except when @@ -1489,11 +1492,11 @@ static int command_line_handle_key(CommandLineState *s) static int command_line_not_changed(CommandLineState *s) { - // This part implements incremental searches for "/" and "?" Jump to - // cmdline_not_changed when a character has been read but the command line - // did not change. Then we only search and redraw if something changed in - // the past. Jump to cmdline_changed when the command line did change. - // (Sorry for the goto's, I know it is ugly). + // Incremental searches for "/" and "?": + // Enter command_line_not_changed() when a character has been read but the + // command line did not change. Then we only search and redraw if something + // changed in the past. + // Enter command_line_changed() when the command line did change. if (!s->incsearch_postponed) { return 1; } @@ -1591,6 +1594,36 @@ static int command_line_changed(CommandLineState *s) msg_starthere(); redrawcmdline(); s->did_incsearch = true; + } else if (s->firstc == ':' + && current_SID == 0 // only if interactive + && *p_icm != NUL // 'inccommand' is set + && curbuf->b_p_ma // buffer is modifiable + && cmdline_star == 0 // not typing a password + && cmd_can_preview(ccline.cmdbuff) + && !vpeekc_any()) { + // Show 'inccommand' preview. It works like this: + // 1. Do the command. + // 2. Command implementation detects CMDPREVIEW state, then: + // - Update the screen while the effects are in place. + // - Immediately undo the effects. + State |= CMDPREVIEW; + emsg_silent++; // Block error reporting as the command may be incomplete + do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_NOWAIT); + emsg_silent--; // Unblock error reporting + + // Restore the window "view". + curwin->w_cursor = s->old_cursor; + curwin->w_curswant = s->old_curswant; + curwin->w_leftcol = s->old_leftcol; + curwin->w_topline = s->old_topline; + curwin->w_topfill = s->old_topfill; + curwin->w_botline = s->old_botline; + update_topline(); + + redrawcmdline(); + } else if (State & CMDPREVIEW) { + State = (State & ~CMDPREVIEW); + update_screen(SOME_VALID); // Clear 'inccommand' preview. } if (cmdmsg_rl || (p_arshape && !p_tbidi && enc_utf8)) { @@ -1688,10 +1721,15 @@ int text_locked(void) { */ void text_locked_msg(void) { - if (cmdwin_type != 0) - EMSG(_(e_cmdwin)); - else - EMSG(_(e_secure)); + EMSG(_(get_text_locked_msg())); +} + +char_u * get_text_locked_msg(void) { + if (cmdwin_type != 0) { + return e_cmdwin; + } else { + return e_secure; + } } /* @@ -2548,10 +2586,9 @@ static void cmdline_del(int from) ccline.cmdpos = from; } -/* - * this function is called when the screen size changes and with incremental - * search - */ +// This function is called when the screen size changes and with incremental +// search and in other situations where the command line may have been +// overwritten. void redrawcmdline(void) { if (cmd_silent) @@ -3439,6 +3476,7 @@ addstar ( || context == EXPAND_COMPILER || context == EXPAND_OWNSYNTAX || context == EXPAND_FILETYPE + || context == EXPAND_PACKADD || (context == EXPAND_TAGS && fname[0] == '/')) retval = vim_strnsave(fname, len); else { @@ -3577,15 +3615,16 @@ static void set_expand_context(expand_T *xp) xp->xp_context = EXPAND_NOTHING; return; } - set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos); + set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos, true); } void set_cmd_context ( expand_T *xp, - char_u *str, /* start of command line */ - int len, /* length of command line (excl. NUL) */ - int col /* position of cursor */ + char_u *str, // start of command line + int len, // length of command line (excl. NUL) + int col, // position of cursor + int use_ccline // use ccline for info ) { int old_char = NUL; @@ -3600,10 +3639,10 @@ set_cmd_context ( str[col] = NUL; nextcomm = str; - if (ccline.cmdfirstc == '=') { - /* pass CMD_SIZE because there is no real command */ + if (use_ccline && ccline.cmdfirstc == '=') { + // pass CMD_SIZE because there is no real command set_context_for_expression(xp, str, CMD_SIZE); - } else if (ccline.input_fn) { + } else if (use_ccline && ccline.input_fn) { xp->xp_context = ccline.xp_context; xp->xp_pattern = ccline.cmdbuff; xp->xp_arg = ccline.xp_arg; @@ -3668,27 +3707,54 @@ expand_cmdline ( return EXPAND_OK; } -/* - * Cleanup matches for help tags: remove "@en" if "en" is the only language. - */ - +// Cleanup matches for help tags: +// Remove "@ab" if the top of 'helplang' is "ab" and the language of the first +// tag matches it. Otherwise remove "@en" if "en" is the only language. static void cleanup_help_tags(int num_file, char_u **file) { - int i, j; - int len; + char_u buf[4]; + char_u *p = buf; - for (i = 0; i < num_file; ++i) { - len = (int)STRLEN(file[i]) - 3; - if (len > 0 && STRCMP(file[i] + len, "@en") == 0) { - /* Sorting on priority means the same item in another language may - * be anywhere. Search all items for a match up to the "@en". */ - for (j = 0; j < num_file; ++j) + if (p_hlg[0] != NUL && (p_hlg[0] != 'e' || p_hlg[1] != 'n')) { + *p++ = '@'; + *p++ = p_hlg[0]; + *p++ = p_hlg[1]; + } + *p = NUL; + + for (int i = 0; i < num_file; i++) { + int len = (int)STRLEN(file[i]) - 3; + if (len <= 0) { + continue; + } + if (STRCMP(file[i] + len, "@en") == 0) { + // Sorting on priority means the same item in another language may + // be anywhere. Search all items for a match up to the "@en". + int j; + for (j = 0; j < num_file; j++) { if (j != i && (int)STRLEN(file[j]) == len + 3 - && STRNCMP(file[i], file[j], len + 1) == 0) + && STRNCMP(file[i], file[j], len + 1) == 0) { break; - if (j == num_file) + } + } + if (j == num_file) { + // item only exists with @en, remove it file[i][len] = NUL; + } + } + } + + if (*buf != NUL) { + for (int i = 0; i < num_file; i++) { + int len = (int)STRLEN(file[i]) - 3; + if (len <= 0) { + continue; + } + if (STRCMP(file[i] + len, buf) == 0) { + // remove the default language + file[i][len] = NUL; + } } } } @@ -3793,23 +3859,27 @@ ExpandFromContext ( || xp->xp_context == EXPAND_TAGS_LISTFILES) return expand_tags(xp->xp_context == EXPAND_TAGS, pat, num_file, file); if (xp->xp_context == EXPAND_COLORS) { - char *directories[] = {"colors", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "colors", NULL }; + return ExpandRTDir(pat, DIP_START + DIP_OPT, num_file, file, directories); } if (xp->xp_context == EXPAND_COMPILER) { - char *directories[] = {"compiler", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "compiler", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_OWNSYNTAX) { - char *directories[] = {"syntax", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "syntax", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } if (xp->xp_context == EXPAND_FILETYPE) { - char *directories[] = {"syntax", "indent", "ftplugin", NULL}; - return ExpandRTDir(pat, num_file, file, directories); + char *directories[] = { "syntax", "indent", "ftplugin", NULL }; + return ExpandRTDir(pat, 0, num_file, file, directories); } - if (xp->xp_context == EXPAND_USER_LIST) + if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, num_file, file); + } + if (xp->xp_context == EXPAND_PACKADD) { + return ExpandPackAddDir(pat, num_file, file); + } regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); if (regmatch.regprog == NULL) @@ -4189,12 +4259,16 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file) return OK; } -/* - * Expand color scheme, compiler or filetype names: - * 'runtimepath'/{dirnames}/{pat}.vim - * "dirnames" is an array with one or more directory names. - */ -static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirnames[]) +/// Expand color scheme, compiler or filetype names. +/// Search from 'runtimepath': +/// 'runtimepath'/{dirnames}/{pat}.vim +/// When "flags" has DIP_START: search also from 'start' of 'packpath': +/// 'packpath'/pack/ * /start/ * /{dirnames}/{pat}.vim +/// When "flags" has DIP_OPT: search also from 'opt' of 'packpath': +/// 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim +/// "dirnames" is an array with one or more directory names. +static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, + char *dirnames[]) { *num_file = 0; *file = NULL; @@ -4211,6 +4285,26 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname xfree(s); } + if (flags & DIP_START) { + for (int i = 0; dirnames[i] != NULL; i++) { + size_t size = STRLEN(dirnames[i]) + pat_len + 22; + char_u *s = xmalloc(size); + snprintf((char *)s, size, "pack/*/start/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + } + } + + if (flags & DIP_OPT) { + for (int i = 0; dirnames[i] != NULL; i++) { + size_t size = STRLEN(dirnames[i]) + pat_len + 20; + char_u *s = xmalloc(size); + snprintf((char *)s, size, "pack/*/opt/*/%s/%s*.vim", dirnames[i], pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + } + } + for (int i = 0; i < ga.ga_len; i++) { char_u *match = ((char_u **)ga.ga_data)[i]; char_u *s = match; @@ -4240,6 +4334,43 @@ static int ExpandRTDir(char_u *pat, int *num_file, char_u ***file, char *dirname return OK; } +/// Expand loadplugin names: +/// 'packpath'/pack/ * /opt/{pat} +static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file) +{ + garray_T ga; + + *num_file = 0; + *file = NULL; + size_t pat_len = STRLEN(pat); + ga_init(&ga, (int)sizeof(char *), 10); + + size_t buflen = pat_len + 26; + char_u *s = xmalloc(buflen); + snprintf((char *)s, buflen, "pack/*/opt/%s*", pat); // NOLINT + globpath(p_pp, s, &ga, 0); + xfree(s); + + for (int i = 0; i < ga.ga_len; i++) { + char_u *match = ((char_u **)ga.ga_data)[i]; + s = path_tail(match); + char_u *e = s + STRLEN(s); + memmove(match, s, e - s + 1); + } + + if (GA_EMPTY(&ga)) { + return FAIL; + } + + // Sort and remove duplicates which can happen when specifying multiple + // directories in dirnames. + ga_remove_duplicate_strings(&ga); + + *file = ga.ga_data; + *num_file = ga.ga_len; + return OK; +} + /// Expand `file` for all comma-separated directories in `path`. /// Adds matches to `ga`. @@ -4304,6 +4435,7 @@ static HistoryType hist_char2type(const int c) case '>': { return HIST_DEBUG; } + case NUL: case '/': case '?': { return HIST_SEARCH; @@ -5039,16 +5171,14 @@ static int ex_window(void) } cmdwin_type = get_cmdline_type(); - /* Create the command-line buffer empty. */ - (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL); - (void)setfname(curbuf, (char_u *)"[Command Line]", NULL, TRUE); - set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL); - set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); - curbuf->b_p_ma = TRUE; - curwin->w_p_fen = FALSE; + // Create empty command-line buffer. + buf_open_scratch(0, "[Command Line]"); + // Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer. + set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); curwin->w_p_rl = cmdmsg_rl; - cmdmsg_rl = FALSE; - RESET_BINDING(curwin); + cmdmsg_rl = false; + curbuf->b_p_ma = true; + curwin->w_p_fen = false; /* Do execute autocommands for setting the filetype (load syntax). */ unblock_autocmds(); |