vim-patch:8.1.1120: cannot easily get directory entry matches #12222

Problem:    Cannot easily get directory entry matches.
Solution:   Add the readdir() function. (Yasuhiro Matsumoto, closes vim/vim#2439)
543c9b1921

closes #12212
This commit is contained in:
Hennadii Chernyshchyk
2020-05-05 18:15:45 +03:00
committed by GitHub
parent 48c2198297
commit d2766b06c8
5 changed files with 153 additions and 13 deletions

View File

@@ -915,7 +915,7 @@ varnumber_T eval_to_number(char_u *expr)
* Save the current typeval in "save_tv".
* When not used yet add the variable to the v: hashtable.
*/
static void prepare_vimvar(int idx, typval_T *save_tv)
void prepare_vimvar(int idx, typval_T *save_tv)
{
*save_tv = vimvars[idx].vv_tv;
if (vimvars[idx].vv_type == VAR_UNKNOWN)
@@ -926,7 +926,7 @@ static void prepare_vimvar(int idx, typval_T *save_tv)
* Restore v: variable "idx" to typeval "save_tv".
* When no longer defined, remove the variable from the v: hashtable.
*/
static void restore_vimvar(int idx, typval_T *save_tv)
void restore_vimvar(int idx, typval_T *save_tv)
{
hashitem_T *hi;

View File

@@ -255,6 +255,7 @@ return {
pyeval={args=1},
pyxeval={args=1},
range={args={1, 3}},
readdir={args={1, 2}},
readfile={args={1, 3}},
reg_executing={},
reg_recording={},

View File

@@ -6316,6 +6316,99 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
// Evaluate "expr" for readdir().
static varnumber_T readdir_checkitem(typval_T *expr, const char *name)
{
typval_T save_val;
typval_T rettv;
typval_T argv[2];
varnumber_T retval = 0;
bool error = false;
prepare_vimvar(VV_VAL, &save_val);
set_vim_var_string(VV_VAL, name, -1);
argv[0].v_type = VAR_STRING;
argv[0].vval.v_string = (char_u *)name;
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL) {
goto theend;
}
retval = tv_get_number_chk(&rettv, &error);
if (error) {
retval = -1;
}
tv_clear(&rettv);
theend:
set_vim_var_string(VV_VAL, NULL, 0);
restore_vimvar(VV_VAL, &save_val);
return retval;
}
// "readdir()" function
static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
typval_T *expr;
const char *path;
garray_T ga;
Directory dir;
tv_list_alloc_ret(rettv, kListLenUnknown);
path = tv_get_string(&argvars[0]);
expr = &argvars[1];
ga_init(&ga, (int)sizeof(char *), 20);
if (!os_scandir(&dir, path)) {
smsg(_(e_notopen), path);
} else {
for (;;) {
bool ignore;
path = os_scandir_next(&dir);
if (path == NULL) {
break;
}
ignore = (path[0] == '.'
&& (path[1] == NUL || (path[1] == '.' && path[2] == NUL)));
if (!ignore && expr->v_type != VAR_UNKNOWN) {
varnumber_T r = readdir_checkitem(expr, path);
if (r < 0) {
break;
}
if (r == 0) {
ignore = true;
}
}
if (!ignore) {
ga_grow(&ga, 1);
((char **)ga.ga_data)[ga.ga_len++] = xstrdup(path);
}
}
os_closedir(&dir);
}
rettv->vval.v_list = tv_list_alloc(kListLenShouldKnow);
if (rettv->vval.v_list != NULL) {
tv_list_ref(rettv->vval.v_list);
sort_strings((char_u **)ga.ga_data, ga.ga_len);
for (int i = 0; i < ga.ga_len; i++) {
path = ((const char **)ga.ga_data)[i];
tv_list_append_string(rettv->vval.v_list, path, -1);
}
}
for (int i = 0; i < ga.ga_len; i++) {
xfree(((uint8_t **)ga.ga_data)[i]);
}
ga_clear(&ga);
}
/*
* "readfile()" function
*/

View File

@@ -1307,3 +1307,33 @@ func Test_bufadd_bufload()
bwipe otherName
call assert_equal(0, bufexists('someName'))
endfunc
func Test_readdir()
call mkdir('Xdir')
call writefile([], 'Xdir/foo.txt')
call writefile([], 'Xdir/bar.txt')
call mkdir('Xdir/dir')
" All results
let files = readdir('Xdir')
call assert_equal(['bar.txt', 'dir', 'foo.txt'], sort(files))
" Only results containing "f"
let files = readdir('Xdir', { x -> stridx(x, 'f') !=- 1 })
call assert_equal(['foo.txt'], sort(files))
" Only .txt files
let files = readdir('Xdir', { x -> x =~ '.txt$' })
call assert_equal(['bar.txt', 'foo.txt'], sort(files))
" Only .txt files with string
let files = readdir('Xdir', 'v:val =~ ".txt$"')
call assert_equal(['bar.txt', 'foo.txt'], sort(files))
" Limit to 1 result.
let l = []
let files = readdir('Xdir', {x -> len(add(l, x)) == 2 ? -1 : 1})
call assert_equal(1, len(files))
call delete('Xdir', 'rf')
endfunc