mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Add wreaddir_for_dirs function
Eliminates some stat calls, speeding up wildcard expansion
This commit is contained in:
parent
f87268e2ac
commit
3a3a9f5cc1
3 changed files with 44 additions and 2 deletions
|
@ -814,7 +814,7 @@ void wildcard_expander_t::expand_trailing_slash(const wcstring &base_dir)
|
|||
void wildcard_expander_t::expand_intermediate_segment(const wcstring &base_dir, DIR *base_dir_fp, const wcstring &wc_segment, const wchar_t *wc_remainder)
|
||||
{
|
||||
wcstring name_str;
|
||||
while (!interrupted() && wreaddir(base_dir_fp, name_str))
|
||||
while (!interrupted() && wreaddir_for_dirs(base_dir_fp, &name_str))
|
||||
{
|
||||
/* Note that it's critical we ignore leading dots here, else we may descend into . and .. */
|
||||
if (! wildcard_match(name_str, wc_segment, true))
|
||||
|
@ -849,7 +849,7 @@ void wildcard_expander_t::expand_literal_intermediate_segment_with_fuzz(const wc
|
|||
// This only works with tab completions
|
||||
// Ordinary wildcard expansion should never go fuzzy
|
||||
wcstring name_str;
|
||||
while (!interrupted() && wreaddir(base_dir_fp, name_str))
|
||||
while (!interrupted() && wreaddir_for_dirs(base_dir_fp, &name_str))
|
||||
{
|
||||
/* Don't bother with . and .. */
|
||||
if (contains(name_str, L".", L".."))
|
||||
|
|
|
@ -115,6 +115,40 @@ bool wreaddir(DIR *dir, std::wstring &out_name)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name)
|
||||
{
|
||||
struct dirent *result = NULL;
|
||||
while (result == NULL)
|
||||
{
|
||||
struct dirent *d = readdir(dir);
|
||||
if (!d) break;
|
||||
|
||||
#if HAVE_STRUCT_DIRENT_D_TYPE
|
||||
switch (d->d_type)
|
||||
{
|
||||
// These may be directories
|
||||
case DT_DIR:
|
||||
case DT_LNK:
|
||||
case DT_UNKNOWN:
|
||||
result = d;
|
||||
break;
|
||||
|
||||
// Nothing else can
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* We can't determine if it's a directory or not, so just return it */
|
||||
result = d;
|
||||
#endif
|
||||
}
|
||||
if (result && out_name)
|
||||
{
|
||||
*out_name = str2wcstring(result->d_name);
|
||||
}
|
||||
return result != NULL;
|
||||
}
|
||||
|
||||
|
||||
wchar_t *wgetcwd(wchar_t *buff, size_t sz)
|
||||
{
|
||||
|
|
|
@ -94,6 +94,14 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path);
|
|||
bool wreaddir(DIR *dir, std::wstring &out_name);
|
||||
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name, bool *out_is_dir);
|
||||
|
||||
/**
|
||||
Like wreaddir, but skip items that are known to not be directories.
|
||||
If this requires a stat (i.e. the file is a symlink), then return it.
|
||||
Note that this does not guarantee that everything returned is a directory,
|
||||
it's just an optimization for cases where we would check for directories anyways.
|
||||
*/
|
||||
bool wreaddir_for_dirs(DIR *dir, wcstring *out_name);
|
||||
|
||||
/**
|
||||
Wide character version of dirname()
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue