mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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:
parent
48c2198297
commit
d2766b06c8
@ -6688,6 +6688,33 @@ range({expr} [, {max} [, {stride}]]) *range()*
|
|||||||
range(2, -2, -1) " [2, 1, 0, -1, -2]
|
range(2, -2, -1) " [2, 1, 0, -1, -2]
|
||||||
range(0) " []
|
range(0) " []
|
||||||
range(2, 0) " error!
|
range(2, 0) " error!
|
||||||
|
<
|
||||||
|
*readdir()*
|
||||||
|
readdir({directory} [, {expr}])
|
||||||
|
Return a list with file and directory names in {directory}.
|
||||||
|
|
||||||
|
When {expr} is omitted all entries are included.
|
||||||
|
When {expr} is given, it is evaluated to check what to do:
|
||||||
|
If {expr} results in -1 then no further entries will
|
||||||
|
be handled.
|
||||||
|
If {expr} results in 0 then this entry will not be
|
||||||
|
added to the list.
|
||||||
|
If {expr} results in 1 then this entry will be added
|
||||||
|
to the list.
|
||||||
|
Each time {expr} is evaluated |v:val| is set to the entry name.
|
||||||
|
When {expr} is a function the name is passed as the argument.
|
||||||
|
For example, to get a list of files ending in ".txt": >
|
||||||
|
readdir(dirname, {n -> n =~ '.txt$'})
|
||||||
|
< To skip hidden and backup files: >
|
||||||
|
readdir(dirname, {n -> n !~ '^\.\|\~$'})
|
||||||
|
|
||||||
|
< If you want to get a directory tree: >
|
||||||
|
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(".")
|
||||||
<
|
<
|
||||||
*readfile()*
|
*readfile()*
|
||||||
readfile({fname} [, {binary} [, {max}]])
|
readfile({fname} [, {binary} [, {max}]])
|
||||||
@ -6720,17 +6747,6 @@ readfile({fname} [, {binary} [, {max}]])
|
|||||||
the result is an empty list.
|
the result is an empty list.
|
||||||
Also see |writefile()|.
|
Also see |writefile()|.
|
||||||
|
|
||||||
*readdir()*
|
|
||||||
readdir({directory} [, {expr}])
|
|
||||||
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.
|
|
||||||
|
|
||||||
When {expr} is omitted all entries are included.
|
|
||||||
When {expr} is given, it is evaluated to check what to do:
|
|
||||||
If {expr} results in -1 then no further entries will
|
|
||||||
be handled.
|
|
||||||
|
|
||||||
reg_executing() *reg_executing()*
|
reg_executing() *reg_executing()*
|
||||||
Returns the single letter name of the register being executed.
|
Returns the single letter name of the register being executed.
|
||||||
Returns an empty string when no register is being executed.
|
Returns an empty string when no register is being executed.
|
||||||
|
@ -915,7 +915,7 @@ varnumber_T eval_to_number(char_u *expr)
|
|||||||
* Save the current typeval in "save_tv".
|
* Save the current typeval in "save_tv".
|
||||||
* When not used yet add the variable to the v: hashtable.
|
* 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;
|
*save_tv = vimvars[idx].vv_tv;
|
||||||
if (vimvars[idx].vv_type == VAR_UNKNOWN)
|
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".
|
* Restore v: variable "idx" to typeval "save_tv".
|
||||||
* When no longer defined, remove the variable from the v: hashtable.
|
* 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;
|
hashitem_T *hi;
|
||||||
|
|
||||||
|
@ -255,6 +255,7 @@ return {
|
|||||||
pyeval={args=1},
|
pyeval={args=1},
|
||||||
pyxeval={args=1},
|
pyxeval={args=1},
|
||||||
range={args={1, 3}},
|
range={args={1, 3}},
|
||||||
|
readdir={args={1, 2}},
|
||||||
readfile={args={1, 3}},
|
readfile={args={1, 3}},
|
||||||
reg_executing={},
|
reg_executing={},
|
||||||
reg_recording={},
|
reg_recording={},
|
||||||
|
@ -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
|
* "readfile()" function
|
||||||
*/
|
*/
|
||||||
|
@ -1307,3 +1307,33 @@ func Test_bufadd_bufload()
|
|||||||
bwipe otherName
|
bwipe otherName
|
||||||
call assert_equal(0, bufexists('someName'))
|
call assert_equal(0, bufexists('someName'))
|
||||||
endfunc
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user