Mercurial > vim
diff src/ex_cmds2.c @ 17744:4a3dca734d36 v8.1.1869
patch 8.1.1869: code for the argument list is spread out
commit https://github.com/vim/vim/commit/4ad62155a1015751a6645aaecd94b02c94c8934b
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Aug 17 14:38:55 2019 +0200
patch 8.1.1869: code for the argument list is spread out
Problem: Code for the argument list is spread out.
Solution: Put argument list code in arglist.c. (Yegappan Lakshmanan,
closes #4819)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 17 Aug 2019 14:45:04 +0200 |
parents | ff097edaae89 |
children | 04245f071792 |
line wrap: on
line diff
--- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -823,598 +823,6 @@ buf_write_all(buf_T *buf, int forceit) } /* - * Code to handle the argument list. - */ - -static int do_arglist(char_u *str, int what, int after, int will_edit); -static void alist_check_arg_idx(void); -static void alist_add_list(int count, char_u **files, int after, int will_edit); -#define AL_SET 1 -#define AL_ADD 2 -#define AL_DEL 3 - -/* - * Isolate one argument, taking backticks. - * Changes the argument in-place, puts a NUL after it. Backticks remain. - * Return a pointer to the start of the next argument. - */ - static char_u * -do_one_arg(char_u *str) -{ - char_u *p; - int inbacktick; - - inbacktick = FALSE; - for (p = str; *str; ++str) - { - /* When the backslash is used for escaping the special meaning of a - * character we need to keep it until wildcard expansion. */ - if (rem_backslash(str)) - { - *p++ = *str++; - *p++ = *str; - } - else - { - /* An item ends at a space not in backticks */ - if (!inbacktick && vim_isspace(*str)) - break; - if (*str == '`') - inbacktick ^= TRUE; - *p++ = *str; - } - } - str = skipwhite(str); - *p = NUL; - - return str; -} - -/* - * Separate the arguments in "str" and return a list of pointers in the - * growarray "gap". - */ - static int -get_arglist(garray_T *gap, char_u *str, int escaped) -{ - ga_init2(gap, (int)sizeof(char_u *), 20); - while (*str != NUL) - { - if (ga_grow(gap, 1) == FAIL) - { - ga_clear(gap); - return FAIL; - } - ((char_u **)gap->ga_data)[gap->ga_len++] = str; - - /* If str is escaped, don't handle backslashes or spaces */ - if (!escaped) - return OK; - - /* Isolate one argument, change it in-place, put a NUL after it. */ - str = do_one_arg(str); - } - return OK; -} - -#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO) -/* - * Parse a list of arguments (file names), expand them and return in - * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'. - * Return FAIL or OK. - */ - int -get_arglist_exp( - char_u *str, - int *fcountp, - char_u ***fnamesp, - int wig) -{ - garray_T ga; - int i; - - if (get_arglist(&ga, str, TRUE) == FAIL) - return FAIL; - if (wig == TRUE) - i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, - fcountp, fnamesp, EW_FILE|EW_NOTFOUND); - else - i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data, - fcountp, fnamesp, EW_FILE|EW_NOTFOUND); - - ga_clear(&ga); - return i; -} -#endif - -/* - * Redefine the argument list. - */ - void -set_arglist(char_u *str) -{ - do_arglist(str, AL_SET, 0, FALSE); -} - -/* - * "what" == AL_SET: Redefine the argument list to 'str'. - * "what" == AL_ADD: add files in 'str' to the argument list after "after". - * "what" == AL_DEL: remove files in 'str' from the argument list. - * - * Return FAIL for failure, OK otherwise. - */ - static int -do_arglist( - char_u *str, - int what, - int after UNUSED, // 0 means before first one - int will_edit) // will edit added argument -{ - garray_T new_ga; - int exp_count; - char_u **exp_files; - int i; - char_u *p; - int match; - int arg_escaped = TRUE; - - /* - * Set default argument for ":argadd" command. - */ - if (what == AL_ADD && *str == NUL) - { - if (curbuf->b_ffname == NULL) - return FAIL; - str = curbuf->b_fname; - arg_escaped = FALSE; - } - - /* - * Collect all file name arguments in "new_ga". - */ - if (get_arglist(&new_ga, str, arg_escaped) == FAIL) - return FAIL; - - if (what == AL_DEL) - { - regmatch_T regmatch; - int didone; - - /* - * Delete the items: use each item as a regexp and find a match in the - * argument list. - */ - regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */ - for (i = 0; i < new_ga.ga_len && !got_int; ++i) - { - p = ((char_u **)new_ga.ga_data)[i]; - p = file_pat_to_reg_pat(p, NULL, NULL, FALSE); - if (p == NULL) - break; - regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); - if (regmatch.regprog == NULL) - { - vim_free(p); - break; - } - - didone = FALSE; - for (match = 0; match < ARGCOUNT; ++match) - if (vim_regexec(®match, alist_name(&ARGLIST[match]), - (colnr_T)0)) - { - didone = TRUE; - vim_free(ARGLIST[match].ae_fname); - mch_memmove(ARGLIST + match, ARGLIST + match + 1, - (ARGCOUNT - match - 1) * sizeof(aentry_T)); - --ALIST(curwin)->al_ga.ga_len; - if (curwin->w_arg_idx > match) - --curwin->w_arg_idx; - --match; - } - - vim_regfree(regmatch.regprog); - vim_free(p); - if (!didone) - semsg(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]); - } - ga_clear(&new_ga); - } - else - { - i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, - &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); - ga_clear(&new_ga); - if (i == FAIL || exp_count == 0) - { - emsg(_(e_nomatch)); - return FAIL; - } - - if (what == AL_ADD) - { - alist_add_list(exp_count, exp_files, after, will_edit); - vim_free(exp_files); - } - else /* what == AL_SET */ - alist_set(ALIST(curwin), exp_count, exp_files, will_edit, NULL, 0); - } - - alist_check_arg_idx(); - - return OK; -} - -/* - * Check the validity of the arg_idx for each other window. - */ - static void -alist_check_arg_idx(void) -{ - win_T *win; - tabpage_T *tp; - - FOR_ALL_TAB_WINDOWS(tp, win) - if (win->w_alist == curwin->w_alist) - check_arg_idx(win); -} - -/* - * Return TRUE if window "win" is editing the file at the current argument - * index. - */ - static int -editing_arg_idx(win_T *win) -{ - return !(win->w_arg_idx >= WARGCOUNT(win) - || (win->w_buffer->b_fnum - != WARGLIST(win)[win->w_arg_idx].ae_fnum - && (win->w_buffer->b_ffname == NULL - || !(fullpathcmp( - alist_name(&WARGLIST(win)[win->w_arg_idx]), - win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME)))); -} - -/* - * Check if window "win" is editing the w_arg_idx file in its argument list. - */ - void -check_arg_idx(win_T *win) -{ - if (WARGCOUNT(win) > 1 && !editing_arg_idx(win)) - { - /* We are not editing the current entry in the argument list. - * Set "arg_had_last" if we are editing the last one. */ - win->w_arg_idx_invalid = TRUE; - if (win->w_arg_idx != WARGCOUNT(win) - 1 - && arg_had_last == FALSE - && ALIST(win) == &global_alist - && GARGCOUNT > 0 - && win->w_arg_idx < GARGCOUNT - && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum - || (win->w_buffer->b_ffname != NULL - && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]), - win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME)))) - arg_had_last = TRUE; - } - else - { - /* We are editing the current entry in the argument list. - * Set "arg_had_last" if it's also the last one */ - win->w_arg_idx_invalid = FALSE; - if (win->w_arg_idx == WARGCOUNT(win) - 1 - && win->w_alist == &global_alist) - arg_had_last = TRUE; - } -} - -/* - * ":args", ":argslocal" and ":argsglobal". - */ - void -ex_args(exarg_T *eap) -{ - int i; - - if (eap->cmdidx != CMD_args) - { - alist_unlink(ALIST(curwin)); - if (eap->cmdidx == CMD_argglobal) - ALIST(curwin) = &global_alist; - else /* eap->cmdidx == CMD_arglocal */ - alist_new(); - } - - if (*eap->arg != NUL) - { - /* - * ":args file ..": define new argument list, handle like ":next" - * Also for ":argslocal file .." and ":argsglobal file ..". - */ - ex_next(eap); - } - else if (eap->cmdidx == CMD_args) - { - /* - * ":args": list arguments. - */ - if (ARGCOUNT > 0) - { - char_u **items = ALLOC_MULT(char_u *, ARGCOUNT); - - if (items != NULL) - { - /* Overwrite the command, for a short list there is no - * scrolling required and no wait_return(). */ - gotocmdline(TRUE); - - for (i = 0; i < ARGCOUNT; ++i) - items[i] = alist_name(&ARGLIST[i]); - list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); - vim_free(items); - } - } - } - else if (eap->cmdidx == CMD_arglocal) - { - garray_T *gap = &curwin->w_alist->al_ga; - - /* - * ":argslocal": make a local copy of the global argument list. - */ - if (ga_grow(gap, GARGCOUNT) == OK) - for (i = 0; i < GARGCOUNT; ++i) - if (GARGLIST[i].ae_fname != NULL) - { - AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = - vim_strsave(GARGLIST[i].ae_fname); - AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = - GARGLIST[i].ae_fnum; - ++gap->ga_len; - } - } -} - -/* - * ":previous", ":sprevious", ":Next" and ":sNext". - */ - void -ex_previous(exarg_T *eap) -{ - /* If past the last one already, go to the last one. */ - if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) - do_argfile(eap, ARGCOUNT - 1); - else - do_argfile(eap, curwin->w_arg_idx - (int)eap->line2); -} - -/* - * ":rewind", ":first", ":sfirst" and ":srewind". - */ - void -ex_rewind(exarg_T *eap) -{ - do_argfile(eap, 0); -} - -/* - * ":last" and ":slast". - */ - void -ex_last(exarg_T *eap) -{ - do_argfile(eap, ARGCOUNT - 1); -} - -/* - * ":argument" and ":sargument". - */ - void -ex_argument(exarg_T *eap) -{ - int i; - - if (eap->addr_count > 0) - i = eap->line2 - 1; - else - i = curwin->w_arg_idx; - do_argfile(eap, i); -} - -/* - * Edit file "argn" of the argument lists. - */ - void -do_argfile(exarg_T *eap, int argn) -{ - int other; - char_u *p; - int old_arg_idx = curwin->w_arg_idx; - - if (ERROR_IF_POPUP_WINDOW) - return; - if (argn < 0 || argn >= ARGCOUNT) - { - if (ARGCOUNT <= 1) - emsg(_("E163: There is only one file to edit")); - else if (argn < 0) - emsg(_("E164: Cannot go before first file")); - else - emsg(_("E165: Cannot go beyond last file")); - } - else - { - setpcmark(); -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - - /* split window or create new tab page first */ - if (*eap->cmd == 's' || cmdmod.tab != 0) - { - if (win_split(0, 0) == FAIL) - return; - RESET_BINDING(curwin); - } - else - { - /* - * if 'hidden' set, only check for changed file when re-editing - * the same buffer - */ - other = TRUE; - if (buf_hide(curbuf)) - { - p = fix_fname(alist_name(&ARGLIST[argn])); - other = otherfile(p); - vim_free(p); - } - if ((!buf_hide(curbuf) || !other) - && check_changed(curbuf, CCGD_AW - | (other ? 0 : CCGD_MULTWIN) - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) - return; - } - - curwin->w_arg_idx = argn; - if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist) - arg_had_last = TRUE; - - /* Edit the file; always use the last known line number. - * When it fails (e.g. Abort for already edited file) restore the - * argument index. */ - if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, - eap, ECMD_LAST, - (buf_hide(curwin->w_buffer) ? ECMD_HIDE : 0) - + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) - curwin->w_arg_idx = old_arg_idx; - /* like Vi: set the mark where the cursor is in the file. */ - else if (eap->cmdidx != CMD_argdo) - setmark('\''); - } -} - -/* - * ":next", and commands that behave like it. - */ - void -ex_next(exarg_T *eap) -{ - int i; - - /* - * check for changed buffer now, if this fails the argument list is not - * redefined. - */ - if ( buf_hide(curbuf) - || eap->cmdidx == CMD_snext - || !check_changed(curbuf, CCGD_AW - | (eap->forceit ? CCGD_FORCEIT : 0) - | CCGD_EXCMD)) - { - if (*eap->arg != NUL) /* redefine file list */ - { - if (do_arglist(eap->arg, AL_SET, 0, TRUE) == FAIL) - return; - i = 0; - } - else - i = curwin->w_arg_idx + (int)eap->line2; - do_argfile(eap, i); - } -} - -/* - * ":argedit" - */ - void -ex_argedit(exarg_T *eap) -{ - int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1; - // Whether curbuf will be reused, curbuf->b_ffname will be set. - int curbuf_is_reusable = curbuf_reusable(); - - if (do_arglist(eap->arg, AL_ADD, i, TRUE) == FAIL) - return; -#ifdef FEAT_TITLE - maketitle(); -#endif - - if (curwin->w_arg_idx == 0 - && (curbuf->b_ml.ml_flags & ML_EMPTY) - && (curbuf->b_ffname == NULL || curbuf_is_reusable)) - i = 0; - /* Edit the argument. */ - if (i < ARGCOUNT) - do_argfile(eap, i); -} - -/* - * ":argadd" - */ - void -ex_argadd(exarg_T *eap) -{ - do_arglist(eap->arg, AL_ADD, - eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1, - FALSE); -#ifdef FEAT_TITLE - maketitle(); -#endif -} - -/* - * ":argdelete" - */ - void -ex_argdelete(exarg_T *eap) -{ - int i; - int n; - - if (eap->addr_count > 0) - { - /* ":1,4argdel": Delete all arguments in the range. */ - if (eap->line2 > ARGCOUNT) - eap->line2 = ARGCOUNT; - n = eap->line2 - eap->line1 + 1; - if (*eap->arg != NUL) - /* Can't have both a range and an argument. */ - emsg(_(e_invarg)); - else if (n <= 0) - { - /* Don't give an error for ":%argdel" if the list is empty. */ - if (eap->line1 != 1 || eap->line2 != 0) - emsg(_(e_invrange)); - } - else - { - for (i = eap->line1; i <= eap->line2; ++i) - vim_free(ARGLIST[i - 1].ae_fname); - mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, - (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T))); - ALIST(curwin)->al_ga.ga_len -= n; - if (curwin->w_arg_idx >= eap->line2) - curwin->w_arg_idx -= n; - else if (curwin->w_arg_idx > eap->line1) - curwin->w_arg_idx = eap->line1; - if (ARGCOUNT == 0) - curwin->w_arg_idx = 0; - else if (curwin->w_arg_idx >= ARGCOUNT) - curwin->w_arg_idx = ARGCOUNT - 1; - } - } - else if (*eap->arg == NUL) - emsg(_(e_argreq)); - else - do_arglist(eap->arg, AL_DEL, 0, FALSE); -#ifdef FEAT_TITLE - maketitle(); -#endif -} - -/* * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" */ void @@ -1681,63 +1089,6 @@ ex_listdo(exarg_T *eap) #endif } -/* - * Add files[count] to the arglist of the current window after arg "after". - * The file names in files[count] must have been allocated and are taken over. - * Files[] itself is not taken over. - */ - static void -alist_add_list( - int count, - char_u **files, - int after, // where to add: 0 = before first one - int will_edit) // will edit adding argument -{ - int i; - int old_argcount = ARGCOUNT; - - if (ga_grow(&ALIST(curwin)->al_ga, count) == OK) - { - if (after < 0) - after = 0; - if (after > ARGCOUNT) - after = ARGCOUNT; - if (after < ARGCOUNT) - mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), - (ARGCOUNT - after) * sizeof(aentry_T)); - for (i = 0; i < count; ++i) - { - int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); - - ARGLIST[after + i].ae_fname = files[i]; - ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); - } - ALIST(curwin)->al_ga.ga_len += count; - if (old_argcount > 0 && curwin->w_arg_idx >= after) - curwin->w_arg_idx += count; - return; - } - - for (i = 0; i < count; ++i) - vim_free(files[i]); -} - -#if defined(FEAT_CMDL_COMPL) || defined(PROTO) -/* - * Function given to ExpandGeneric() to obtain the possible arguments of the - * argedit and argdelete commands. - */ - char_u * -get_arglist_name(expand_T *xp UNUSED, int idx) -{ - if (idx >= ARGCOUNT) - return NULL; - - return alist_name(&ARGLIST[idx]); -} -#endif - - #ifdef FEAT_EVAL /* * ":compiler[!] {name}"