mirror of
https://github.com/vim/vim.git
synced 2025-08-30 20:43:35 -04:00
patch 8.2.0988: getting directory contents is always case sorted
Problem: Getting directory contents is always case sorted. Solution: Add sort options and v:collate. (Christian Brabandt, closes #6229)
This commit is contained in:
parent
9af78769ee
commit
84cf6bd81b
@ -1745,6 +1745,14 @@ v:cmdbang Set like v:cmdarg for a file read/write command. When a "!"
|
||||
was used the value is 1, otherwise it is 0. Note that this
|
||||
can only be used in autocommands. For user commands |<bang>|
|
||||
can be used.
|
||||
*v:collate* *collate-variable*
|
||||
v:collate The current locale setting for collation order of the runtime
|
||||
environment. This allows Vim scripts to be aware of the
|
||||
current locale encoding. Technical: it's the value of
|
||||
LC_COLLATE. When not using a locale the value is "C".
|
||||
This variable can not be set directly, use the |:language|
|
||||
command.
|
||||
See |multi-lang|.
|
||||
|
||||
*v:completed_item* *completed_item-variable*
|
||||
v:completed_item
|
||||
@ -2683,8 +2691,10 @@ pyxeval({expr}) any evaluate |python_x| expression
|
||||
rand([{expr}]) Number get pseudo-random number
|
||||
range({expr} [, {max} [, {stride}]])
|
||||
List items from {expr} to {max}
|
||||
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
|
||||
readdirex({dir} [, {expr}]) List file info in {dir} selected by {expr}
|
||||
readdir({dir} [, {expr} [, {dict}]])
|
||||
List file names in {dir} selected by {expr}
|
||||
readdirex({dir} [, {expr} [, {dict}]])
|
||||
List file info in {dir} selected by {expr}
|
||||
readfile({fname} [, {type} [, {max}]])
|
||||
List get list of lines from file {fname}
|
||||
reduce({object}, {func} [, {initial}])
|
||||
@ -7904,11 +7914,12 @@ rand([{expr}]) *rand()* *random*
|
||||
:echo rand(seed)
|
||||
:echo rand(seed) % 16 " random number 0 - 15
|
||||
<
|
||||
readdir({directory} [, {expr}]) *readdir()*
|
||||
readdir({directory} [, {expr} [, {dict}]]) *readdir()*
|
||||
Return a list with file and directory names in {directory}.
|
||||
You can also use |glob()| if you don't need to do complicated
|
||||
things, such as limiting the number of matches.
|
||||
The list will be sorted (case sensitive).
|
||||
The list will be sorted (case sensitive), see the {dict}
|
||||
argument below for changing the sort order.
|
||||
|
||||
When {expr} is omitted all entries are included.
|
||||
When {expr} is given, it is evaluated to check what to do:
|
||||
@ -7926,18 +7937,38 @@ readdir({directory} [, {expr}]) *readdir()*
|
||||
< To skip hidden and backup files: >
|
||||
readdir(dirname, {n -> n !~ '^\.\|\~$'})
|
||||
|
||||
< The optional {dict} argument allows for further custom
|
||||
values. Currently this is used to specify if and how sorting
|
||||
should be performed. The dict can have the following members:
|
||||
|
||||
sort How to sort the result returned from the system.
|
||||
Valid values are:
|
||||
"none" do not sort (fastest method)
|
||||
"case" sort case sensitive (byte value of
|
||||
each character, technically, using
|
||||
strcmp()) (default)
|
||||
"icase" sort case insensitive (technically
|
||||
using strcasecmp())
|
||||
"collate" sort using the collation order
|
||||
of the "POSIX" or "C" |locale|
|
||||
(technically using strcoll())
|
||||
Other values are silently ignored.
|
||||
|
||||
For example, to get a list of all files in the current
|
||||
directory without sorting the individual entries: >
|
||||
readdir('.', '1', #{sort: 'none'})
|
||||
< If you want to get a directory tree: >
|
||||
function! s:tree(dir)
|
||||
return {a:dir : map(readdir(a:dir),
|
||||
function! s:tree(dir)
|
||||
return {a:dir : map(readdir(a:dir),
|
||||
\ {_, x -> isdirectory(x) ?
|
||||
\ {x : s:tree(a:dir . '/' . x)} : x})}
|
||||
endfunction
|
||||
echo s:tree(".")
|
||||
\ {x : s:tree(a:dir . '/' . x)} : x})}
|
||||
endfunction
|
||||
echo s:tree(".")
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
GetDirName()->readdir()
|
||||
<
|
||||
readdirex({directory} [, {expr}]) *readdirex()*
|
||||
readdirex({directory} [, {expr} [, {dict}]]) *readdirex()*
|
||||
Extended version of |readdir()|.
|
||||
Return a list of Dictionaries with file and directory
|
||||
information in {directory}.
|
||||
@ -7946,7 +7977,9 @@ readdirex({directory} [, {expr}]) *readdirex()*
|
||||
This is much faster than calling |readdir()| then calling
|
||||
|getfperm()|, |getfsize()|, |getftime()| and |getftype()| for
|
||||
each file and directory especially on MS-Windows.
|
||||
The list will be sorted by name (case sensitive).
|
||||
The list will by default be sorted by name (case sensitive),
|
||||
the sorting can be changed by using the optional {dict}
|
||||
argument, see |readdir()|.
|
||||
|
||||
The Dictionary for file and directory information has the
|
||||
following items:
|
||||
@ -7986,6 +8019,11 @@ readdirex({directory} [, {expr}]) *readdirex()*
|
||||
When {expr} is a function the entry is passed as the argument.
|
||||
For example, to get a list of files ending in ".txt": >
|
||||
readdirex(dirname, {e -> e.name =~ '.txt$'})
|
||||
<
|
||||
For example, to get a list of all files in the current
|
||||
directory without sorting the individual entries: >
|
||||
readdirex(dirname, '1', #{sort: 'none'})
|
||||
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
GetDirName()->readdirex()
|
||||
|
@ -37,6 +37,7 @@ use of "-" and "_".
|
||||
:lan[guage] mes[sages]
|
||||
:lan[guage] cty[pe]
|
||||
:lan[guage] tim[e]
|
||||
:lan[guage] col[late]
|
||||
Print the current language (aka locale).
|
||||
With the "messages" argument the language used for
|
||||
messages is printed. Technical: LC_MESSAGES.
|
||||
@ -44,15 +45,19 @@ use of "-" and "_".
|
||||
character encoding is printed. Technical: LC_CTYPE.
|
||||
With the "time" argument the language used for
|
||||
strftime() is printed. Technical: LC_TIME.
|
||||
With the "collate" argument the language used for
|
||||
collation order is printed. Technical: LC_COLLATE.
|
||||
Without argument all parts of the locale are printed
|
||||
(this is system dependent).
|
||||
The current language can also be obtained with the
|
||||
|v:lang|, |v:ctype| and |v:lc_time| variables.
|
||||
|v:lang|, |v:ctype|, |v:collate| and |v:lc_time|
|
||||
variables.
|
||||
|
||||
:lan[guage] {name}
|
||||
:lan[guage] mes[sages] {name}
|
||||
:lan[guage] cty[pe] {name}
|
||||
:lan[guage] tim[e] {name}
|
||||
:lan[guage] col[late] {name}
|
||||
Set the current language (aka locale) to {name}.
|
||||
The locale {name} must be a valid locale on your
|
||||
system. Some systems accept aliases like "en" or
|
||||
@ -72,7 +77,10 @@ use of "-" and "_".
|
||||
With the "time" argument the language used for time
|
||||
and date messages is set. This affects strftime().
|
||||
This sets $LC_TIME.
|
||||
Without an argument both are set, and additionally
|
||||
With the "collate" argument the language used for the
|
||||
collation order is set. This affects sorting of
|
||||
characters. This sets $LC_COLLATE.
|
||||
Without an argument all are set, and additionally
|
||||
$LANG is set.
|
||||
When compiled with the |+float| feature the LC_NUMERIC
|
||||
value will always be set to "C", so that floating
|
||||
|
2
src/auto/configure
vendored
2
src/auto/configure
vendored
@ -12618,7 +12618,7 @@ for ac_func in fchdir fchown fchmod fsync getcwd getpseudotty \
|
||||
getpwent getpwnam getpwuid getrlimit gettimeofday localtime_r lstat \
|
||||
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
|
||||
getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
|
||||
sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
|
||||
sigprocmask sigvec strcasecmp strcoll strerror strftime stricmp strncasecmp \
|
||||
strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \
|
||||
tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt
|
||||
do :
|
||||
|
@ -1728,7 +1728,8 @@ set_one_cmd_context(
|
||||
{
|
||||
if ( STRNCMP(arg, "messages", p - arg) == 0
|
||||
|| STRNCMP(arg, "ctype", p - arg) == 0
|
||||
|| STRNCMP(arg, "time", p - arg) == 0)
|
||||
|| STRNCMP(arg, "time", p - arg) == 0
|
||||
|| STRNCMP(arg, "collate", p - arg) == 0)
|
||||
{
|
||||
xp->xp_context = EXPAND_LOCALES;
|
||||
xp->xp_pattern = skipwhite(p);
|
||||
|
@ -198,6 +198,7 @@
|
||||
#undef HAVE_SIGVEC
|
||||
#undef HAVE_SMACK
|
||||
#undef HAVE_STRCASECMP
|
||||
#undef HAVE_STRCOLL
|
||||
#undef HAVE_STRERROR
|
||||
#undef HAVE_STRFTIME
|
||||
#undef HAVE_STRICMP
|
||||
|
@ -3739,7 +3739,7 @@ AC_CHECK_FUNCS(fchdir fchown fchmod fsync getcwd getpseudotty \
|
||||
getpwent getpwnam getpwuid getrlimit gettimeofday localtime_r lstat \
|
||||
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
|
||||
getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
|
||||
sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
|
||||
sigprocmask sigvec strcasecmp strcoll strerror strftime stricmp strncasecmp \
|
||||
strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \
|
||||
tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt)
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
|
@ -769,8 +769,8 @@ static funcentry_T global_functions[] =
|
||||
},
|
||||
{"rand", 0, 1, FEARG_1, ret_number, f_rand},
|
||||
{"range", 1, 3, FEARG_1, ret_list_number, f_range},
|
||||
{"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
|
||||
{"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
|
||||
{"readdir", 1, 3, FEARG_1, ret_list_string, f_readdir},
|
||||
{"readdirex", 1, 3, FEARG_1, ret_list_dict_any, f_readdirex},
|
||||
{"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
|
||||
{"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
|
||||
{"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
|
||||
|
@ -145,6 +145,7 @@ static struct vimvar
|
||||
{VV_NAME("versionlong", VAR_NUMBER), VV_RO},
|
||||
{VV_NAME("echospace", VAR_NUMBER), VV_RO},
|
||||
{VV_NAME("argv", VAR_LIST), VV_RO},
|
||||
{VV_NAME("collate", VAR_STRING), VV_RO},
|
||||
};
|
||||
|
||||
// shorthand
|
||||
|
@ -1185,6 +1185,14 @@ set_lang_var(void)
|
||||
loc = get_locale_val(LC_TIME);
|
||||
# endif
|
||||
set_vim_var_string(VV_LC_TIME, loc, -1);
|
||||
|
||||
# ifdef HAVE_GET_LOCALE_VAL
|
||||
loc = get_locale_val(LC_COLLATE);
|
||||
# else
|
||||
// setlocale() not supported: use the default value
|
||||
loc = (char_u *)"C";
|
||||
# endif
|
||||
set_vim_var_string(VV_COLLATE, loc, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1232,6 +1240,12 @@ ex_language(exarg_T *eap)
|
||||
name = skipwhite(p);
|
||||
whatstr = "time ";
|
||||
}
|
||||
else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
|
||||
{
|
||||
what = LC_COLLATE;
|
||||
name = skipwhite(p);
|
||||
whatstr = "collate ";
|
||||
}
|
||||
}
|
||||
|
||||
if (*name == NUL)
|
||||
@ -1274,7 +1288,7 @@ ex_language(exarg_T *eap)
|
||||
// Reset $LC_ALL, otherwise it would overrule everything.
|
||||
vim_setenv((char_u *)"LC_ALL", (char_u *)"");
|
||||
|
||||
if (what != LC_TIME)
|
||||
if (what != LC_TIME && what != LC_COLLATE)
|
||||
{
|
||||
// Tell gettext() what to translate to. It apparently doesn't
|
||||
// use the currently effective locale. Also do this when
|
||||
@ -1309,7 +1323,7 @@ ex_language(exarg_T *eap)
|
||||
}
|
||||
|
||||
# ifdef FEAT_EVAL
|
||||
// Set v:lang, v:lc_time and v:ctype to the final result.
|
||||
// Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
|
||||
set_lang_var();
|
||||
# endif
|
||||
# ifdef FEAT_TITLE
|
||||
@ -1462,11 +1476,13 @@ get_lang_arg(expand_T *xp UNUSED, int idx)
|
||||
return (char_u *)"ctype";
|
||||
if (idx == 2)
|
||||
return (char_u *)"time";
|
||||
if (idx == 3)
|
||||
return (char_u *)"collate";
|
||||
|
||||
init_locales();
|
||||
if (locales == NULL)
|
||||
return NULL;
|
||||
return locales[idx - 3];
|
||||
return locales[idx - 4];
|
||||
}
|
||||
|
||||
/*
|
||||
|
37
src/fileio.c
37
src/fileio.c
@ -35,6 +35,10 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp);
|
||||
static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags);
|
||||
static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
static int readdirex_sort;
|
||||
#endif
|
||||
|
||||
void
|
||||
filemess(
|
||||
buf_T *buf,
|
||||
@ -4645,7 +4649,23 @@ compare_readdirex_item(const void *p1, const void *p2)
|
||||
|
||||
name1 = dict_get_string(*(dict_T**)p1, (char_u*)"name", FALSE);
|
||||
name2 = dict_get_string(*(dict_T**)p2, (char_u*)"name", FALSE);
|
||||
return STRCMP(name1, name2);
|
||||
if (readdirex_sort == READDIR_SORT_BYTE)
|
||||
return STRCMP(name1, name2);
|
||||
else if (readdirex_sort == READDIR_SORT_IC)
|
||||
return STRICMP(name1, name2);
|
||||
else
|
||||
return STRCOLL(name1, name2);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_readdir_item(const void *s1, const void *s2)
|
||||
{
|
||||
if (readdirex_sort == READDIR_SORT_BYTE)
|
||||
return STRCMP(*(char **)s1, *(char **)s2);
|
||||
else if (readdirex_sort == READDIR_SORT_IC)
|
||||
return STRICMP(*(char **)s1, *(char **)s2);
|
||||
else
|
||||
return STRCOLL(*(char **)s1, *(char **)s2);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -4663,7 +4683,8 @@ readdir_core(
|
||||
char_u *path,
|
||||
int withattr UNUSED,
|
||||
void *context,
|
||||
int (*checkitem)(void *context, void *item))
|
||||
int (*checkitem)(void *context, void *item),
|
||||
int sort)
|
||||
{
|
||||
int failed = FALSE;
|
||||
char_u *p;
|
||||
@ -4687,6 +4708,8 @@ readdir_core(
|
||||
else \
|
||||
vim_free(item); \
|
||||
} while (0)
|
||||
|
||||
readdirex_sort = READDIR_SORT_BYTE;
|
||||
# else
|
||||
# define FREE_ITEM(item) vim_free(item)
|
||||
# endif
|
||||
@ -4844,15 +4867,19 @@ readdir_core(
|
||||
|
||||
# undef FREE_ITEM
|
||||
|
||||
if (!failed && gap->ga_len > 0)
|
||||
if (!failed && gap->ga_len > 0 && sort > READDIR_SORT_NONE)
|
||||
{
|
||||
# ifdef FEAT_EVAL
|
||||
readdirex_sort = sort;
|
||||
if (withattr)
|
||||
qsort((void*)gap->ga_data, (size_t)gap->ga_len, sizeof(dict_T*),
|
||||
compare_readdirex_item);
|
||||
else
|
||||
# endif
|
||||
qsort((void*)gap->ga_data, (size_t)gap->ga_len, sizeof(char_u *),
|
||||
compare_readdir_item);
|
||||
# else
|
||||
sort_strings((char_u **)gap->ga_data, gap->ga_len);
|
||||
# endif
|
||||
}
|
||||
|
||||
return failed ? FAIL : OK;
|
||||
@ -4883,7 +4910,7 @@ delete_recursive(char_u *name)
|
||||
exp = vim_strsave(name);
|
||||
if (exp == NULL)
|
||||
return -1;
|
||||
if (readdir_core(&ga, exp, FALSE, NULL, NULL) == OK)
|
||||
if (readdir_core(&ga, exp, FALSE, NULL, NULL, READDIR_SORT_NONE) == OK)
|
||||
{
|
||||
for (i = 0; i < ga.ga_len; ++i)
|
||||
{
|
||||
|
@ -1405,6 +1405,36 @@ theend:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
readdirex_dict_arg(typval_T *tv, int *cmp)
|
||||
{
|
||||
char_u *compare;
|
||||
|
||||
if (tv->v_type != VAR_DICT)
|
||||
{
|
||||
emsg(_(e_dictreq));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (dict_find(tv->vval.v_dict, (char_u *)"sort", -1) != NULL)
|
||||
compare = dict_get_string(tv->vval.v_dict, (char_u *)"sort", FALSE);
|
||||
else
|
||||
{
|
||||
semsg(_(e_no_dict_key), "sort");
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (STRCMP(compare, (char_u *) "none") == 0)
|
||||
*cmp = READDIR_SORT_NONE;
|
||||
else if (STRCMP(compare, (char_u *) "case") == 0)
|
||||
*cmp = READDIR_SORT_BYTE;
|
||||
else if (STRCMP(compare, (char_u *) "icase") == 0)
|
||||
*cmp = READDIR_SORT_IC;
|
||||
else if (STRCMP(compare, (char_u *) "collate") == 0)
|
||||
*cmp = READDIR_SORT_COLLATE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* "readdir()" function
|
||||
*/
|
||||
@ -1417,14 +1447,19 @@ f_readdir(typval_T *argvars, typval_T *rettv)
|
||||
char_u *p;
|
||||
garray_T ga;
|
||||
int i;
|
||||
int sort = READDIR_SORT_BYTE;
|
||||
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
path = tv_get_string(&argvars[0]);
|
||||
expr = &argvars[1];
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN &&
|
||||
readdirex_dict_arg(&argvars[2], &sort) == FAIL)
|
||||
return;
|
||||
|
||||
ret = readdir_core(&ga, path, FALSE, (void *)expr,
|
||||
(expr->v_type == VAR_UNKNOWN) ? NULL : readdir_checkitem);
|
||||
(expr->v_type == VAR_UNKNOWN) ? NULL : readdir_checkitem, sort);
|
||||
if (ret == OK)
|
||||
{
|
||||
for (i = 0; i < ga.ga_len; i++)
|
||||
@ -1480,14 +1515,19 @@ f_readdirex(typval_T *argvars, typval_T *rettv)
|
||||
char_u *path;
|
||||
garray_T ga;
|
||||
int i;
|
||||
int sort = READDIR_SORT_BYTE;
|
||||
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
path = tv_get_string(&argvars[0]);
|
||||
expr = &argvars[1];
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN &&
|
||||
readdirex_dict_arg(&argvars[2], &sort) == FAIL)
|
||||
return;
|
||||
|
||||
ret = readdir_core(&ga, path, TRUE, (void *)expr,
|
||||
(expr->v_type == VAR_UNKNOWN) ? NULL : readdirex_checkitem);
|
||||
(expr->v_type == VAR_UNKNOWN) ? NULL : readdirex_checkitem, sort);
|
||||
if (ret == OK)
|
||||
{
|
||||
for (i = 0; i < ga.ga_len; i++)
|
||||
|
@ -1699,6 +1699,8 @@ EXTERN char e_const_option[] INIT(= N_("E996: Cannot lock an option"));
|
||||
EXTERN char e_unknown_option[] INIT(= N_("E113: Unknown option: %s"));
|
||||
EXTERN char e_letunexp[] INIT(= N_("E18: Unexpected characters in :let"));
|
||||
EXTERN char e_reduceempty[] INIT(= N_("E998: Reduce of an empty %s with no initial value"));
|
||||
// TODO: Change Error Number
|
||||
EXTERN char e_no_dict_key[] INIT(= N_("E999: Dictionary with key \"%s\" required"));
|
||||
#endif
|
||||
#ifdef FEAT_QUICKFIX
|
||||
EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
|
||||
|
@ -31,7 +31,7 @@ int buf_check_timestamp(buf_T *buf, int focus);
|
||||
void buf_reload(buf_T *buf, int orig_mode);
|
||||
void buf_store_time(buf_T *buf, stat_T *st, char_u *fname);
|
||||
void write_lnum_adjust(linenr_T offset);
|
||||
int readdir_core(garray_T *gap, char_u *path, int withattr, void *context, int (*checkitem)(void *context, void *item));
|
||||
int readdir_core(garray_T *gap, char_u *path, int withattr, void *context, int (*checkitem)(void *context, void *item), int sort);
|
||||
int delete_recursive(char_u *name);
|
||||
void vim_deltempdir(void);
|
||||
char_u *vim_tempname(int extra_char, int keep);
|
||||
|
@ -604,10 +604,20 @@ func Test_cmdline_complete_bang()
|
||||
endfunc
|
||||
|
||||
func Test_cmdline_complete_languages()
|
||||
let lang = substitute(execute('language time'), '.*"\(.*\)"$', '\1', '')
|
||||
call assert_equal(lang, v:lc_time)
|
||||
|
||||
let lang = substitute(execute('language ctype'), '.*"\(.*\)"$', '\1', '')
|
||||
call assert_equal(lang, v:ctype)
|
||||
|
||||
let lang = substitute(execute('language collate'), '.*"\(.*\)"$', '\1', '')
|
||||
call assert_equal(lang, v:collate)
|
||||
|
||||
let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '')
|
||||
call assert_equal(lang, v:lang)
|
||||
|
||||
call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx')
|
||||
call assert_match('^"language .*\<ctype\>.*\<messages\>.*\<time\>', @:)
|
||||
call assert_match('^"language .*\<collate\>.*\<ctype\>.*\<messages\>.*\<time\>', @:)
|
||||
|
||||
call assert_match('^"language .*\<' . lang . '\>', @:)
|
||||
|
||||
@ -619,6 +629,9 @@ func Test_cmdline_complete_languages()
|
||||
|
||||
call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx')
|
||||
call assert_match('^"language .*\<' . lang . '\>', @:)
|
||||
|
||||
call feedkeys(":language collate \<c-a>\<c-b>\"\<cr>", 'tx')
|
||||
call assert_match('^"language .*\<' . lang . '\>', @:)
|
||||
endfunc
|
||||
|
||||
func Test_cmdline_complete_env_variable()
|
||||
|
@ -1937,6 +1937,85 @@ func Test_readdirex()
|
||||
eval 'Xdir'->delete('rf')
|
||||
endfunc
|
||||
|
||||
func Test_readdirex_sort()
|
||||
CheckUnix
|
||||
" Skip tests on Mac OS X and Cygwin (does not allow several files with different casing)
|
||||
if has("osxdarwin") || has("osx") || has("macunix") || has("win32unix")
|
||||
throw 'Skipped: Test_readdirex_sort on systems that do not allow this using the default filesystem'
|
||||
endif
|
||||
let _collate = v:collate
|
||||
call mkdir('Xdir2')
|
||||
call writefile(['1'], 'Xdir2/README.txt')
|
||||
call writefile(['2'], 'Xdir2/Readme.txt')
|
||||
call writefile(['3'], 'Xdir2/readme.txt')
|
||||
|
||||
" 1) default
|
||||
let files = readdirex('Xdir2')->map({-> v:val.name})
|
||||
let default = copy(files)
|
||||
call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], files, 'sort using default')
|
||||
|
||||
" 2) no sorting
|
||||
let files = readdirex('Xdir2', 1, #{sort: 'none'})->map({-> v:val.name})
|
||||
let unsorted = copy(files)
|
||||
call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], sort(files), 'unsorted')
|
||||
|
||||
" 3) sort by case (same as default)
|
||||
let files = readdirex('Xdir2', 1, #{sort: 'case'})->map({-> v:val.name})
|
||||
call assert_equal(default, files, 'sort by case')
|
||||
|
||||
" 4) sort by ignoring case
|
||||
let files = readdirex('Xdir2', 1, #{sort: 'icase'})->map({-> v:val.name})
|
||||
call assert_equal(unsorted->sort('i'), files, 'sort by icase')
|
||||
|
||||
" 5) Default Collation
|
||||
let collate = v:collate
|
||||
lang collate C
|
||||
let files = readdirex('Xdir2', 1, #{sort: 'collate'})->map({-> v:val.name})
|
||||
call assert_equal(['README.txt', 'Readme.txt', 'readme.txt'], files, 'sort by C collation')
|
||||
|
||||
" 6) Collation de_DE
|
||||
" Switch locale, this may not work on the CI system, if the locale isn't
|
||||
" available
|
||||
try
|
||||
lang collate de_DE
|
||||
let files = readdirex('Xdir2', 1, #{sort: 'collate'})->map({-> v:val.name})
|
||||
call assert_equal(['readme.txt', 'Readme.txt', 'README.txt'], files, 'sort by de_DE collation')
|
||||
catch
|
||||
throw 'Skipped: de_DE collation is not available'
|
||||
|
||||
finally
|
||||
exe 'lang collate' collate
|
||||
eval 'Xdir2'->delete('rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func Test_readdir_sort()
|
||||
" some more cases for testing sorting for readdirex
|
||||
let dir = 'Xdir3'
|
||||
call mkdir(dir)
|
||||
call writefile(['1'], dir .. '/README.txt')
|
||||
call writefile(['2'], dir .. '/Readm.txt')
|
||||
call writefile(['3'], dir .. '/read.txt')
|
||||
call writefile(['4'], dir .. '/Z.txt')
|
||||
call writefile(['5'], dir .. '/a.txt')
|
||||
call writefile(['6'], dir .. '/b.txt')
|
||||
|
||||
" 1) default
|
||||
let files = readdir(dir)
|
||||
let default = copy(files)
|
||||
call assert_equal(default->sort(), files, 'sort using default')
|
||||
|
||||
" 2) sort by case (same as default)
|
||||
let files = readdir(dir, '1', #{sort: 'case'})
|
||||
call assert_equal(default, files, 'sort using default')
|
||||
|
||||
" 3) sort by ignoring case
|
||||
let files = readdir(dir, '1', #{sort: 'icase'})
|
||||
call assert_equal(default->sort('i'), files, 'sort by ignoring case')
|
||||
|
||||
eval dir->delete('rf')
|
||||
endfunc
|
||||
|
||||
func Test_delete_rf()
|
||||
call mkdir('Xdir')
|
||||
call writefile([], 'Xdir/foo.txt')
|
||||
|
@ -754,6 +754,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
988,
|
||||
/**/
|
||||
987,
|
||||
/**/
|
||||
|
16
src/vim.h
16
src/vim.h
@ -1599,6 +1599,11 @@ void *vim_memset(void *, int, size_t);
|
||||
# define STRICMP(d, s) vim_stricmp((char *)(d), (char *)(s))
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STRCOLL
|
||||
# define STRCOLL(d, s) strcoll((char *)(d), (char *)(s))
|
||||
#else
|
||||
# define STRCOLL(d, s) strcmp((char *)(d), (char *)(s))
|
||||
#endif
|
||||
|
||||
// Like strcpy() but allows overlapped source and destination.
|
||||
#define STRMOVE(d, s) mch_memmove((d), (s), STRLEN(s) + 1)
|
||||
@ -1896,7 +1901,7 @@ typedef int sock_T;
|
||||
#define VALID_PATH 1
|
||||
#define VALID_HEAD 2
|
||||
|
||||
// Defines for Vim variables. These must match vimvars[] in eval.c!
|
||||
// Defines for Vim variables. These must match vimvars[] in evalvars.c!
|
||||
#define VV_COUNT 0
|
||||
#define VV_COUNT1 1
|
||||
#define VV_PREVCOUNT 2
|
||||
@ -1992,7 +1997,8 @@ typedef int sock_T;
|
||||
#define VV_VERSIONLONG 92
|
||||
#define VV_ECHOSPACE 93
|
||||
#define VV_ARGV 94
|
||||
#define VV_LEN 95 // number of v: vars
|
||||
#define VV_COLLATE 95
|
||||
#define VV_LEN 96 // number of v: vars
|
||||
|
||||
// used for v_number in VAR_BOOL and VAR_SPECIAL
|
||||
#define VVAL_FALSE 0L // VAR_BOOL
|
||||
@ -2669,4 +2675,10 @@ long elapsed(DWORD start_tick);
|
||||
#define FSK_IN_STRING 0x04 // TRUE in string, double quote is escaped
|
||||
#define FSK_SIMPLIFY 0x08 // simplify <C-H> and <A-x>
|
||||
|
||||
// Flags for the readdirex function, how to sort the result
|
||||
#define READDIR_SORT_NONE 0 // do not sort
|
||||
#define READDIR_SORT_BYTE 1 // sort by byte order (strcmp), default
|
||||
#define READDIR_SORT_IC 2 // sort ignoring case (strcasecmp)
|
||||
#define READDIR_SORT_COLLATE 3 // sort according to collation (strcoll)
|
||||
|
||||
#endif // VIM__H
|
||||
|
Loading…
x
Reference in New Issue
Block a user