diff options
Diffstat (limited to 'src/ex_getln.c')
-rw-r--r-- | src/ex_getln.c | 2052 |
1 files changed, 25 insertions, 2027 deletions
diff --git a/src/ex_getln.c b/src/ex_getln.c index 7a00c6ba30..24cce5b738 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -17,39 +17,10 @@ # define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif -/* - * Variables shared between getcmdline(), redrawcmdline() and others. - * These need to be saved when using CTRL-R |, that's why they are in a - * structure. - */ -struct cmdline_info -{ - char_u *cmdbuff; /* pointer to command line buffer */ - int cmdbufflen; /* length of cmdbuff */ - int cmdlen; /* number of chars in command line */ - int cmdpos; /* current cursor position */ - int cmdspos; /* cursor column on screen */ - int cmdfirstc; /* ':', '/', '?', '=', '>' or NUL */ - int cmdindent; /* number of spaces before cmdline */ - char_u *cmdprompt; /* message in front of cmdline */ - int cmdattr; /* attributes for prompt */ - int overstrike; /* Typing mode on the command line. Shared by - getcmdline() and put_on_cmdline(). */ - expand_T *xpc; /* struct being used for expansion, xp_pattern - may point into cmdbuff */ - int xp_context; /* type of expansion */ -# ifdef FEAT_EVAL - char_u *xp_arg; /* user-defined expansion arg */ - int input_fn; /* when TRUE Invoked for input() function */ -# endif -}; - // The current cmdline_info. It is initialized in getcmdline() and after that // used by other functions. When invoking getcmdline() recursively it needs // to be saved with save_cmdline() and restored with restore_cmdline(). -static struct cmdline_info ccline; - -static int cmd_showtail; /* Only show path tail in lists ? */ +static cmdline_info_T ccline; #ifdef FEAT_EVAL static int new_cmdpos; /* position set by set_cmdline_pos() */ @@ -69,41 +40,20 @@ static void set_cmdspos(void); static void set_cmdspos_cursor(void); static void correct_cmdspos(int idx, int cells); static void alloc_cmdbuff(int len); -static int realloc_cmdbuff(int len); static void draw_cmdline(int start, int len); -static void save_cmdline(struct cmdline_info *ccp); -static void restore_cmdline(struct cmdline_info *ccp); +static void save_cmdline(cmdline_info_T *ccp); +static void restore_cmdline(cmdline_info_T *ccp); static int cmdline_paste(int regname, int literally, int remcr); #ifdef FEAT_WILDMENU static void cmdline_del(int from); #endif static void redrawcmdprompt(void); -static void cursorcmd(void); static int ccheck_abbr(int); -static int nextwild(expand_T *xp, int type, int options, int escape); -static void escape_fname(char_u **pp); -static int showmatches(expand_T *xp, int wildmenu); -static void set_expand_context(expand_T *xp); -static int ExpandFromContext(expand_T *xp, char_u *, int *, char_u ***, int); -static int expand_showtail(expand_T *xp); -#ifdef FEAT_CMDL_COMPL -static int expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg); -static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirname[]); -static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); -# if defined(FEAT_EVAL) -static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); -static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file); -# endif -#endif #ifdef FEAT_CMDWIN static int open_cmdwin(void); #endif -#if defined(FEAT_CMDL_COMPL) || defined(PROTO) -static int sort_func_compare(const void *s1, const void *s2); -#endif - static void trigger_cmd_autocmd(int typechar, int evt) @@ -789,7 +739,7 @@ cmdline_has_arabic(int start, int len) void cmdline_init(void) { - vim_memset(&ccline, 0, sizeof(struct cmdline_info)); + vim_memset(&ccline, 0, sizeof(cmdline_info_T)); } /* @@ -855,7 +805,7 @@ getcmdline_int( #endif expand_T xpc; long *b_im_ptr = NULL; - struct cmdline_info save_ccline; + cmdline_info_T save_ccline; int did_save_ccline = FALSE; int cmdline_type; @@ -867,7 +817,7 @@ getcmdline_int( did_save_ccline = TRUE; } if (init_ccline) - vim_memset(&ccline, 0, sizeof(struct cmdline_info)); + vim_memset(&ccline, 0, sizeof(cmdline_info_T)); #ifdef FEAT_EVAL if (firstc == -1) @@ -2474,7 +2424,7 @@ getcmdline_prompt( char_u *xp_arg) /* user-defined expansion argument */ { char_u *s; - struct cmdline_info save_ccline; + cmdline_info_T save_ccline; int did_save_ccline = FALSE; int msg_col_save = msg_col; int msg_silent_save = msg_silent; @@ -2486,7 +2436,7 @@ getcmdline_prompt( did_save_ccline = TRUE; } - vim_memset(&ccline, 0, sizeof(struct cmdline_info)); + vim_memset(&ccline, 0, sizeof(cmdline_info_T)); ccline.cmdprompt = prompt; ccline.cmdattr = attr; # ifdef FEAT_EVAL @@ -3099,7 +3049,7 @@ alloc_cmdbuff(int len) * Re-allocate the command line to length len + something extra. * return FAIL for failure, OK otherwise */ - static int + int realloc_cmdbuff(int len) { char_u *p; @@ -3460,8 +3410,8 @@ put_on_cmdline(char_u *str, int len, int redraw) return retval; } -static struct cmdline_info prev_ccline; -static int prev_ccline_used = FALSE; +static cmdline_info_T prev_ccline; +static int prev_ccline_used = FALSE; /* * Save ccline, because obtaining the "=" register may execute "normal :cmd" @@ -3469,11 +3419,11 @@ static int prev_ccline_used = FALSE; * available globally in prev_ccline. */ static void -save_cmdline(struct cmdline_info *ccp) +save_cmdline(cmdline_info_T *ccp) { if (!prev_ccline_used) { - vim_memset(&prev_ccline, 0, sizeof(struct cmdline_info)); + vim_memset(&prev_ccline, 0, sizeof(cmdline_info_T)); prev_ccline_used = TRUE; } *ccp = prev_ccline; @@ -3485,7 +3435,7 @@ save_cmdline(struct cmdline_info *ccp) * Restore ccline after it has been saved with save_cmdline(). */ static void -restore_cmdline(struct cmdline_info *ccp) +restore_cmdline(cmdline_info_T *ccp) { ccline = prev_ccline; prev_ccline = *ccp; @@ -3723,7 +3673,7 @@ compute_cmdrow(void) + lastwin->w_status_height; } - static void + void cursorcmd(void) { if (cmd_silent) @@ -3801,522 +3751,6 @@ ccheck_abbr(int c) return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos); } -#if defined(FEAT_CMDL_COMPL) || defined(PROTO) - static int -sort_func_compare(const void *s1, const void *s2) -{ - char_u *p1 = *(char_u **)s1; - char_u *p2 = *(char_u **)s2; - - if (*p1 != '<' && *p2 == '<') return -1; - if (*p1 == '<' && *p2 != '<') return 1; - return STRCMP(p1, p2); -} -#endif - -/* - * Return FAIL if this is not an appropriate context in which to do - * completion of anything, return OK if it is (even if there are no matches). - * For the caller, this means that the character is just passed through like a - * normal character (instead of being expanded). This allows :s/^I^D etc. - */ - static int -nextwild( - expand_T *xp, - int type, - int options, /* extra options for ExpandOne() */ - int escape) /* if TRUE, escape the returned matches */ -{ - int i, j; - char_u *p1; - char_u *p2; - int difflen; - int v; - - if (xp->xp_numfiles == -1) - { - set_expand_context(xp); - cmd_showtail = expand_showtail(xp); - } - - if (xp->xp_context == EXPAND_UNSUCCESSFUL) - { - beep_flush(); - return OK; /* Something illegal on command line */ - } - if (xp->xp_context == EXPAND_NOTHING) - { - /* Caller can use the character as a normal char instead */ - return FAIL; - } - - msg_puts("..."); /* show that we are busy */ - out_flush(); - - i = (int)(xp->xp_pattern - ccline.cmdbuff); - xp->xp_pattern_len = ccline.cmdpos - i; - - if (type == WILD_NEXT || type == WILD_PREV) - { - /* - * Get next/previous match for a previous expanded pattern. - */ - p2 = ExpandOne(xp, NULL, NULL, 0, type); - } - else - { - /* - * Translate string into pattern and expand it. - */ - if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, - xp->xp_context)) == NULL) - p2 = NULL; - else - { - int use_options = options | - WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; - if (escape) - use_options |= WILD_ESCAPE; - - if (p_wic) - use_options += WILD_ICASE; - p2 = ExpandOne(xp, p1, - vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len), - use_options, type); - vim_free(p1); - /* longest match: make sure it is not shorter, happens with :help */ - if (p2 != NULL && type == WILD_LONGEST) - { - for (j = 0; j < xp->xp_pattern_len; ++j) - if (ccline.cmdbuff[i + j] == '*' - || ccline.cmdbuff[i + j] == '?') - break; - if ((int)STRLEN(p2) < j) - VIM_CLEAR(p2); - } - } - } - - if (p2 != NULL && !got_int) - { - difflen = (int)STRLEN(p2) - xp->xp_pattern_len; - if (ccline.cmdlen + difflen + 4 > ccline.cmdbufflen) - { - v = realloc_cmdbuff(ccline.cmdlen + difflen + 4); - xp->xp_pattern = ccline.cmdbuff + i; - } - else - v = OK; - if (v == OK) - { - mch_memmove(&ccline.cmdbuff[ccline.cmdpos + difflen], - &ccline.cmdbuff[ccline.cmdpos], - (size_t)(ccline.cmdlen - ccline.cmdpos + 1)); - mch_memmove(&ccline.cmdbuff[i], p2, STRLEN(p2)); - ccline.cmdlen += difflen; - ccline.cmdpos += difflen; - } - } - vim_free(p2); - - redrawcmd(); - cursorcmd(); - - /* When expanding a ":map" command and no matches are found, assume that - * the key is supposed to be inserted literally */ - if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL) - return FAIL; - - if (xp->xp_numfiles <= 0 && p2 == NULL) - beep_flush(); - else if (xp->xp_numfiles == 1) - /* free expanded pattern */ - (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE); - - return OK; -} - -/* - * Do wildcard expansion on the string 'str'. - * Chars that should not be expanded must be preceded with a backslash. - * Return a pointer to allocated memory containing the new string. - * Return NULL for failure. - * - * "orig" is the originally expanded string, copied to allocated memory. It - * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or - * WILD_PREV "orig" should be NULL. - * - * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode" - * is WILD_EXPAND_FREE or WILD_ALL. - * - * mode = WILD_FREE: just free previously expanded matches - * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches - * mode = WILD_EXPAND_KEEP: normal expansion, keep matches - * mode = WILD_NEXT: use next match in multiple match, wrap to first - * mode = WILD_PREV: use previous match in multiple match, wrap to first - * mode = WILD_ALL: return all matches concatenated - * mode = WILD_LONGEST: return longest matched part - * mode = WILD_ALL_KEEP: get all matches, keep matches - * - * options = WILD_LIST_NOTFOUND: list entries without a match - * options = WILD_HOME_REPLACE: do home_replace() for buffer names - * options = WILD_USE_NL: Use '\n' for WILD_ALL - * options = WILD_NO_BEEP: Don't beep for multiple matches - * options = WILD_ADD_SLASH: add a slash after directory names - * options = WILD_KEEP_ALL: don't remove 'wildignore' entries - * options = WILD_SILENT: don't print warning messages - * options = WILD_ESCAPE: put backslash before special chars - * options = WILD_ICASE: ignore case for files - * - * The variables xp->xp_context and xp->xp_backslash must have been set! - */ - char_u * -ExpandOne( - expand_T *xp, - char_u *str, - char_u *orig, /* allocated copy of original of expanded string */ - int options, - int mode) -{ - char_u *ss = NULL; - static int findex; - static char_u *orig_save = NULL; /* kept value of orig */ - int orig_saved = FALSE; - int i; - long_u len; - int non_suf_match; /* number without matching suffix */ - - /* - * first handle the case of using an old match - */ - if (mode == WILD_NEXT || mode == WILD_PREV) - { - if (xp->xp_numfiles > 0) - { - if (mode == WILD_PREV) - { - if (findex == -1) - findex = xp->xp_numfiles; - --findex; - } - else /* mode == WILD_NEXT */ - ++findex; - - /* - * When wrapping around, return the original string, set findex to - * -1. - */ - if (findex < 0) - { - if (orig_save == NULL) - findex = xp->xp_numfiles - 1; - else - findex = -1; - } - if (findex >= xp->xp_numfiles) - { - if (orig_save == NULL) - findex = 0; - else - findex = -1; - } -#ifdef FEAT_WILDMENU - if (p_wmnu) - win_redr_status_matches(xp, xp->xp_numfiles, xp->xp_files, - findex, cmd_showtail); -#endif - if (findex == -1) - return vim_strsave(orig_save); - return vim_strsave(xp->xp_files[findex]); - } - else - return NULL; - } - - /* free old names */ - if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) - { - FreeWild(xp->xp_numfiles, xp->xp_files); - xp->xp_numfiles = -1; - VIM_CLEAR(orig_save); - } - findex = 0; - - if (mode == WILD_FREE) /* only release file name */ - return NULL; - - if (xp->xp_numfiles == -1) - { - vim_free(orig_save); - orig_save = orig; - orig_saved = TRUE; - - /* - * Do the expansion. - */ - if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files, - options) == FAIL) - { -#ifdef FNAME_ILLEGAL - /* Illegal file name has been silently skipped. But when there - * are wildcards, the real problem is that there was no match, - * causing the pattern to be added, which has illegal characters. - */ - if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) - semsg(_(e_nomatch2), str); -#endif - } - else if (xp->xp_numfiles == 0) - { - if (!(options & WILD_SILENT)) - semsg(_(e_nomatch2), str); - } - else - { - /* Escape the matches for use on the command line. */ - ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options); - - /* - * Check for matching suffixes in file names. - */ - if (mode != WILD_ALL && mode != WILD_ALL_KEEP - && mode != WILD_LONGEST) - { - if (xp->xp_numfiles) - non_suf_match = xp->xp_numfiles; - else - non_suf_match = 1; - if ((xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_DIRECTORIES) - && xp->xp_numfiles > 1) - { - /* - * More than one match; check suffix. - * The files will have been sorted on matching suffix in - * expand_wildcards, only need to check the first two. - */ - non_suf_match = 0; - for (i = 0; i < 2; ++i) - if (match_suffix(xp->xp_files[i])) - ++non_suf_match; - } - if (non_suf_match != 1) - { - /* Can we ever get here unless it's while expanding - * interactively? If not, we can get rid of this all - * together. Don't really want to wait for this message - * (and possibly have to hit return to continue!). - */ - if (!(options & WILD_SILENT)) - emsg(_(e_toomany)); - else if (!(options & WILD_NO_BEEP)) - beep_flush(); - } - if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) - ss = vim_strsave(xp->xp_files[0]); - } - } - } - - /* Find longest common part */ - if (mode == WILD_LONGEST && xp->xp_numfiles > 0) - { - int mb_len = 1; - int c0, ci; - - for (len = 0; xp->xp_files[0][len]; len += mb_len) - { - if (has_mbyte) - { - mb_len = (*mb_ptr2len)(&xp->xp_files[0][len]); - c0 =(* mb_ptr2char)(&xp->xp_files[0][len]); - } - else - c0 = xp->xp_files[0][len]; - for (i = 1; i < xp->xp_numfiles; ++i) - { - if (has_mbyte) - ci =(* mb_ptr2char)(&xp->xp_files[i][len]); - else - ci = xp->xp_files[i][len]; - if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES - || xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS)) - { - if (MB_TOLOWER(c0) != MB_TOLOWER(ci)) - break; - } - else if (c0 != ci) - break; - } - if (i < xp->xp_numfiles) - { - if (!(options & WILD_NO_BEEP)) - vim_beep(BO_WILD); - break; - } - } - - ss = alloc(len + 1); - if (ss) - vim_strncpy(ss, xp->xp_files[0], (size_t)len); - findex = -1; /* next p_wc gets first one */ - } - - /* Concatenate all matching names */ - if (mode == WILD_ALL && xp->xp_numfiles > 0) - { - len = 0; - for (i = 0; i < xp->xp_numfiles; ++i) - len += (long_u)STRLEN(xp->xp_files[i]) + 1; - ss = alloc(len); - if (ss != NULL) - { - *ss = NUL; - for (i = 0; i < xp->xp_numfiles; ++i) - { - STRCAT(ss, xp->xp_files[i]); - if (i != xp->xp_numfiles - 1) - STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " "); - } - } - } - - if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) - ExpandCleanup(xp); - - /* Free "orig" if it wasn't stored in "orig_save". */ - if (!orig_saved) - vim_free(orig); - - return ss; -} - -/* - * Prepare an expand structure for use. - */ - void -ExpandInit(expand_T *xp) -{ - xp->xp_pattern = NULL; - xp->xp_pattern_len = 0; - xp->xp_backslash = XP_BS_NONE; -#ifndef BACKSLASH_IN_FILENAME - xp->xp_shell = FALSE; -#endif - xp->xp_numfiles = -1; - xp->xp_files = NULL; -#if defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL) - xp->xp_arg = NULL; -#endif - xp->xp_line = NULL; -} - -/* - * Cleanup an expand structure after use. - */ - void -ExpandCleanup(expand_T *xp) -{ - if (xp->xp_numfiles >= 0) - { - FreeWild(xp->xp_numfiles, xp->xp_files); - xp->xp_numfiles = -1; - } -} - - void -ExpandEscape( - expand_T *xp, - char_u *str, - int numfiles, - char_u **files, - int options) -{ - int i; - char_u *p; - - /* - * May change home directory back to "~" - */ - if (options & WILD_HOME_REPLACE) - tilde_replace(str, numfiles, files); - - if (options & WILD_ESCAPE) - { - if (xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_FILES_IN_PATH - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS - || xp->xp_context == EXPAND_DIRECTORIES) - { - /* - * Insert a backslash into a file name before a space, \, %, # - * and wildmatch characters, except '~'. - */ - for (i = 0; i < numfiles; ++i) - { - /* for ":set path=" we need to escape spaces twice */ - if (xp->xp_backslash == XP_BS_THREE) - { - p = vim_strsave_escaped(files[i], (char_u *)" "); - if (p != NULL) - { - vim_free(files[i]); - files[i] = p; -#if defined(BACKSLASH_IN_FILENAME) - p = vim_strsave_escaped(files[i], (char_u *)" "); - if (p != NULL) - { - vim_free(files[i]); - files[i] = p; - } -#endif - } - } -#ifdef BACKSLASH_IN_FILENAME - p = vim_strsave_fnameescape(files[i], FALSE); -#else - p = vim_strsave_fnameescape(files[i], xp->xp_shell); -#endif - if (p != NULL) - { - vim_free(files[i]); - files[i] = p; - } - - /* If 'str' starts with "\~", replace "~" at start of - * files[i] with "\~". */ - if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') - escape_fname(&files[i]); - } - xp->xp_backslash = XP_BS_NONE; - - /* If the first file starts with a '+' escape it. Otherwise it - * could be seen as "+cmd". */ - if (*files[0] == '+') - escape_fname(&files[0]); - } - else if (xp->xp_context == EXPAND_TAGS) - { - /* - * Insert a backslash before characters in a tag name that - * would terminate the ":tag" command. - */ - for (i = 0; i < numfiles; ++i) - { - p = vim_strsave_escaped(files[i], (char_u *)"\\|\""); - if (p != NULL) - { - vim_free(files[i]); - files[i] = p; - } - } - } - } -} - /* * Escape special characters in "fname" for when used as a file name argument * after a Vim command, or, when "shell" is non-zero, a shell command. @@ -4361,7 +3795,7 @@ vim_strsave_fnameescape(char_u *fname, int shell) /* * Put a backslash before the file name in "pp", which is in allocated memory. */ - static void + void escape_fname(char_u **pp) { char_u *p; @@ -4404,1456 +3838,20 @@ tilde_replace( } /* - * Show all matches for completion on the command line. - * Returns EXPAND_NOTHING when the character that triggered expansion should - * be inserted like a normal character. - */ - static int -showmatches(expand_T *xp, int wildmenu UNUSED) -{ -#define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m]) - int num_files; - char_u **files_found; - int i, j, k; - int maxlen; - int lines; - int columns; - char_u *p; - int lastlen; - int attr; - int showtail; - - if (xp->xp_numfiles == -1) - { - set_expand_context(xp); - i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos, - &num_files, &files_found); - showtail = expand_showtail(xp); - if (i != EXPAND_OK) - return i; - - } - else - { - num_files = xp->xp_numfiles; - files_found = xp->xp_files; - showtail = cmd_showtail; - } - -#ifdef FEAT_WILDMENU - if (!wildmenu) - { -#endif - msg_didany = FALSE; /* lines_left will be set */ - msg_start(); /* prepare for paging */ - msg_putchar('\n'); - out_flush(); - cmdline_row = msg_row; - msg_didany = FALSE; /* lines_left will be set again */ - msg_start(); /* prepare for paging */ -#ifdef FEAT_WILDMENU - } -#endif - - if (got_int) - got_int = FALSE; /* only int. the completion, not the cmd line */ -#ifdef FEAT_WILDMENU - else if (wildmenu) - win_redr_status_matches(xp, num_files, files_found, -1, showtail); -#endif - else - { - /* find the length of the longest file name */ - maxlen = 0; - for (i = 0; i < num_files; ++i) - { - if (!showtail && (xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS)) - { - home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE); - j = vim_strsize(NameBuff); - } - else - j = vim_strsize(L_SHOWFILE(i)); - if (j > maxlen) - maxlen = j; - } - - if (xp->xp_context == EXPAND_TAGS_LISTFILES) - lines = num_files; - else - { - /* compute the number of columns and lines for the listing */ - maxlen += 2; /* two spaces between file names */ - columns = ((int)Columns + 2) / maxlen; - if (columns < 1) - columns = 1; - lines = (num_files + columns - 1) / columns; - } - - attr = HL_ATTR(HLF_D); /* find out highlighting for directories */ - - if (xp->xp_context == EXPAND_TAGS_LISTFILES) - { - msg_puts_attr(_("tagname"), HL_ATTR(HLF_T)); - msg_clr_eos(); - msg_advance(maxlen - 3); - msg_puts_attr(_(" kind file\n"), HL_ATTR(HLF_T)); - } - - /* list the files line by line */ - for (i = 0; i < lines; ++i) - { - lastlen = 999; - for (k = i; k < num_files; k += lines) - { - if (xp->xp_context == EXPAND_TAGS_LISTFILES) - { - msg_outtrans_attr(files_found[k], HL_ATTR(HLF_D)); - p = files_found[k] + STRLEN(files_found[k]) + 1; - msg_advance(maxlen + 1); - msg_puts((char *)p); - msg_advance(maxlen + 3); - msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D)); - break; - } - for (j = maxlen - lastlen; --j >= 0; ) - msg_putchar(' '); - if (xp->xp_context == EXPAND_FILES - || xp->xp_context == EXPAND_SHELLCMD - || xp->xp_context == EXPAND_BUFFERS) - { - /* highlight directories */ - if (xp->xp_numfiles != -1) - { - char_u *halved_slash; - char_u *exp_path; - - /* Expansion was done before and special characters - * were escaped, need to halve backslashes. Also - * $HOME has been replaced with ~/. */ - exp_path = expand_env_save_opt(files_found[k], TRUE); - halved_slash = backslash_halve_save( - exp_path != NULL ? exp_path : files_found[k]); - j = mch_isdir(halved_slash != NULL ? halved_slash - : files_found[k]); - vim_free(exp_path); - vim_free(halved_slash); - } - else - /* Expansion was done here, file names are literal. */ - j = mch_isdir(files_found[k]); - if (showtail) - p = L_SHOWFILE(k); - else - { - home_replace(NULL, files_found[k], NameBuff, MAXPATHL, - TRUE); - p = NameBuff; - } - } - else - { - j = FALSE; - p = L_SHOWFILE(k); - } - lastlen = msg_outtrans_attr(p, j ? attr : 0); - } - if (msg_col > 0) /* when not wrapped around */ - { - msg_clr_eos(); - msg_putchar('\n'); - } - out_flush(); /* show one line at a time */ - if (got_int) - { - got_int = FALSE; - break; - } - } - - /* - * we redraw the command below the lines that we have just listed - * This is a bit tricky, but it saves a lot of screen updating. - */ - cmdline_row = msg_row; /* will put it back later */ - } - - if (xp->xp_numfiles == -1) - FreeWild(num_files, files_found); - - return EXPAND_OK; -} - -/* - * Private gettail for showmatches() (and win_redr_status_matches()): - * Find tail of file name path, but ignore trailing "/". + * Get a pointer to the current command line info. */ - char_u * -sm_gettail(char_u *s) + cmdline_info_T * +get_cmdline_info(void) { - char_u *p; - char_u *t = s; - int had_sep = FALSE; - - for (p = s; *p != NUL; ) - { - if (vim_ispathsep(*p) -#ifdef BACKSLASH_IN_FILENAME - && !rem_backslash(p) -#endif - ) - had_sep = TRUE; - else if (had_sep) - { - t = p; - had_sep = FALSE; - } - MB_PTR_ADV(p); - } - return t; + return &ccline; } -/* - * Return TRUE if we only need to show the tail of completion matches. - * When not completing file names or there is a wildcard in the path FALSE is - * returned. - */ - static int -expand_showtail(expand_T *xp) -{ - char_u *s; - char_u *end; - - /* When not completing file names a "/" may mean something different. */ - if (xp->xp_context != EXPAND_FILES - && xp->xp_context != EXPAND_SHELLCMD - && xp->xp_context != EXPAND_DIRECTORIES) - return FALSE; - - end = gettail(xp->xp_pattern); - if (end == xp->xp_pattern) /* there is no path separator */ - return FALSE; - - for (s = xp->xp_pattern; s < end; s++) - { - /* Skip escaped wildcards. Only when the backslash is not a path - * separator, on DOS the '*' "path\*\file" must not be skipped. */ - if (rem_backslash(s)) - ++s; - else if (vim_strchr((char_u *)"*?[", *s) != NULL) - return FALSE; - } - return TRUE; -} - -/* - * Prepare a string for expansion. - * When expanding file names: The string will be used with expand_wildcards(). - * Copy "fname[len]" into allocated memory and add a '*' at the end. - * When expanding other names: The string will be used with regcomp(). Copy - * the name into allocated memory and prepend "^". - */ - char_u * -addstar( - char_u *fname, - int len, - int context) /* EXPAND_FILES etc. */ -{ - char_u *retval; - int i, j; - int new_len; - char_u *tail; - int ends_in_star; - - if (context != EXPAND_FILES - && context != EXPAND_FILES_IN_PATH - && context != EXPAND_SHELLCMD - && context != EXPAND_DIRECTORIES) - { - /* - * Matching will be done internally (on something other than files). - * So we convert the file-matching-type wildcards into our kind for - * use with vim_regcomp(). First work out how long it will be: - */ - - /* For help tags the translation is done in find_help_tags(). - * For a tag pattern starting with "/" no translation is needed. */ - if (context == EXPAND_HELP - || context == EXPAND_COLORS - || context == EXPAND_COMPILER - || context == EXPAND_OWNSYNTAX - || context == EXPAND_FILETYPE - || context == EXPAND_PACKADD - || ((context == EXPAND_TAGS_LISTFILES - || context == EXPAND_TAGS) - && fname[0] == '/')) - retval = vim_strnsave(fname, len); - else - { - new_len = len + 2; /* +2 for '^' at start, NUL at end */ - for (i = 0; i < len; i++) - { - if (fname[i] == '*' || fname[i] == '~') - new_len++; /* '*' needs to be replaced by ".*" - '~' needs to be replaced by "\~" */ - - /* Buffer names are like file names. "." should be literal */ - if (context == EXPAND_BUFFERS && fname[i] == '.') - new_len++; /* "." becomes "\." */ - - /* Custom expansion takes care of special things, match - * backslashes literally (perhaps also for other types?) */ - if ((context == EXPAND_USER_DEFINED - || context == EXPAND_USER_LIST) && fname[i] == '\\') - new_len++; /* '\' becomes "\\" */ - } - retval = alloc(new_len); - if (retval != NULL) - { - retval[0] = '^'; - j = 1; - for (i = 0; i < len; i++, j++) - { - /* Skip backslash. But why? At least keep it for custom - * expansion. */ - if (context != EXPAND_USER_DEFINED - && context != EXPAND_USER_LIST - && fname[i] == '\\' - && ++i == len) - break; - - switch (fname[i]) - { - case '*': retval[j++] = '.'; - break; - case '~': retval[j++] = '\\'; - break; - case '?': retval[j] = '.'; - continue; - case '.': if (context == EXPAND_BUFFERS) - retval[j++] = '\\'; - break; - case '\\': if (context == EXPAND_USER_DEFINED - || context == EXPAND_USER_LIST) - retval[j++] = '\\'; - break; - } - retval[j] = fname[i]; - } - retval[j] = NUL; - } - } - } - else - { - retval = alloc(len + 4); - if (retval != NULL) - { - vim_strncpy(retval, fname, len); - - /* - * Don't add a star to *, ~, ~user, $var or `cmd`. - * * would become **, which walks the whole tree. - * ~ would be at the start of the file name, but not the tail. - * $ could be anywhere in the tail. - * ` could be anywhere in the file name. - * When the name ends in '$' don't add a star, remove the '$'. - */ - tail = gettail(retval); - ends_in_star = (len > 0 && retval[len - 1] == '*'); -#ifndef BACKSLASH_IN_FILENAME - for (i = len - 2; i >= 0; --i) - { - if (retval[i] != '\\') - break; - ends_in_star = !ends_in_star; - } -#endif - if ((*retval != '~' || tail != retval) - && !ends_in_star - && vim_strchr(tail, '$') == NULL - && vim_strchr(retval, '`') == NULL) - retval[len++] = '*'; - else if (len > 0 && retval[len - 1] == '$') - --len; - retval[len] = NUL; - } - } - return retval; -} - -/* - * Must parse the command line so far to work out what context we are in. - * Completion can then be done based on that context. - * This routine sets the variables: - * xp->xp_pattern The start of the pattern to be expanded within - * the command line (ends at the cursor). - * xp->xp_context The type of thing to expand. Will be one of: - * - * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on - * the command line, like an unknown command. Caller - * should beep. - * EXPAND_NOTHING Unrecognised context for completion, use char like - * a normal char, rather than for completion. eg - * :s/^I/ - * EXPAND_COMMANDS Cursor is still touching the command, so complete - * it. - * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. - * EXPAND_FILES After command with EX_XFILE set, or after setting - * with P_EXPAND set. eg :e ^I, :w>>^I - * EXPAND_DIRECTORIES In some cases this is used instead of the latter - * when we know only directories are of interest. eg - * :set dir=^I - * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd". - * EXPAND_SETTINGS Complete variable names. eg :set d^I - * EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I - * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I - * EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect - * EXPAND_HELP Complete tags from the file 'helpfile'/tags - * EXPAND_EVENTS Complete event names - * EXPAND_SYNTAX Complete :syntax command arguments - * EXPAND_HIGHLIGHT Complete highlight (syntax) group names - * EXPAND_AUGROUP Complete autocommand group names - * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I - * EXPAND_MAPPINGS Complete mapping and abbreviation names, - * eg :unmap a^I , :cunab x^I - * EXPAND_FUNCTIONS Complete internal or user defined function names, - * eg :call sub^I - * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I - * EXPAND_EXPRESSION Complete internal or user defined function/variable - * names in expressions, eg :while s^I - * EXPAND_ENV_VARS Complete environment variable names - * EXPAND_USER Complete user names - */ - static void -set_expand_context(expand_T *xp) -{ - /* only expansion for ':', '>' and '=' command-lines */ - if (ccline.cmdfirstc != ':' -#ifdef FEAT_EVAL - && ccline.cmdfirstc != '>' && ccline.cmdfirstc != '=' - && !ccline.input_fn -#endif - ) - { - xp->xp_context = EXPAND_NOTHING; - return; - } - 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 */ - int use_ccline UNUSED) /* use ccline for info |