// arglist.c: functions for dealing with the argument list
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "auto/config.h"
#include "nvim/arglist.h"
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/macros_defs.h"
#include "nvim/mark.h"
#include "nvim/memline_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/option_vars.h"
#include "nvim/os/input.h"
#include "nvim/path.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
#include "nvim/types_defs.h"
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/vim_defs.h"
#include "nvim/window.h"
/// State used by the :all command to open all the files in the argument list in
/// separate windows.
typedef struct {
alist_T *alist; ///< argument list to be used
int had_tab;
bool keep_tabs;
bool forceit;
bool use_firstwin; ///< use first window for arglist
uint8_t *opened; ///< Array of weight for which args are open:
///< 0: not opened
///< 1: opened in other tab
///< 2: opened in curtab
///< 3: opened in curtab and curwin
int opened_len; ///< length of opened[]
win_T *new_curwin;
tabpage_T *new_curtab;
} arg_all_state_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "arglist.c.generated.h"
#endif
static const char e_window_layout_changed_unexpectedly[]
= N_("E249: Window layout changed unexpectedly");
static const char e_cannot_change_arglist_recursively[]
= N_("E1156: Cannot change the argument list recursively");
enum {
AL_SET = 1,
AL_ADD = 2,
AL_DEL = 3,
};
/// This flag is set whenever the argument list is being changed and calling a
/// function that might trigger an autocommand.
static bool arglist_locked = false;
static int check_arglist_locked(void)
{
if (arglist_locked) {
emsg(_(e_cannot_change_arglist_recursively));
return FAIL;
}
return OK;
}
/// Clear an argument list: free all file names and reset it to zero entries.
void alist_clear(alist_T *al)
{
if (check_arglist_locked() == FAIL) {
return;
}
#define FREE_AENTRY_FNAME(arg) xfree((arg)->ae_fname)
GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME);
}
/// Init an argument list.
void alist_init(alist_T *al)
{
ga_init(&al->al_ga, (int)sizeof(aentry_T), 5);
}
/// Remove a reference from an argument list.
/// Ignored when the argument list is the global one.
/// If the argument list is no longer used by any window, free it.
void alist_unlink(alist_T *al)
{
if (al != &global_alist && --al->al_refcount <= 0) {
alist_clear(al);
xfree(al);
}
}
/// Create a new argument list and use it for the current window.
void alist_new(void)
{
curwin->w_alist = xmalloc(sizeof(*curwin->w_alist));
curwin->w_alist->al_refcount = 1;
curwin->w_alist->id = ++max_alist_id;
alist_init(curwin->w_alist);
}
#if !defined(UNIX)
/// Expand the file names in the global argument list.
/// If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer
/// numbers to be re-used.
void alist_expand(int *fnum_list, int fnum_len)
{
char *save_p_su = p_su;
char **old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT);
// Don't use 'suffixes' here. This should work like the shell did the
// expansion. Also, the vimrc file isn't read yet, thus the user
// can't set the options.
p_su = empty_string_option;
for (int i = 0; i < GARGCOUNT; i++) {
old_arg_files[i] = xstrdup(GARGLIST[i].ae_fname);
}
int old_arg_count = GARGCOUNT;
char **new_arg_files;
int new_arg_file_count;
if (expand_wildcards(old_arg_count, old_arg_files,
&new_arg_file_count, &new_arg_files,
EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK
&& new_arg_file_count > 0) {
alist_set(&global_alist, new_arg_file_count, new_arg_files,
true, fnum_list, fnum_len);
FreeWild(old_arg_count, old_arg_files);
}
p_su = save_p_su;
}
#endif
/// Set the argument list for the current window.
/// Takes over the allocated files[] and the allocated fnames in it.
void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_list, int fnum_len)
{
if (check_arglist_locked() == FAIL) {
return;
}
alist_clear(al);
ga_grow(&al->al_ga
|