mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 14:03:58 +00:00
Experiment to rework wildcard matching
Preparation for zsh-style intermediate component tab completion
This commit is contained in:
parent
b7e16cb0dd
commit
fd96bafbc8
2 changed files with 47 additions and 19 deletions
|
@ -139,19 +139,26 @@ bool wildcard_has(const wcstring &str, bool internal)
|
||||||
\param wc The wildcard.
|
\param wc The wildcard.
|
||||||
\param is_first Whether files beginning with dots should not be matched against wildcards.
|
\param is_first Whether files beginning with dots should not be matched against wildcards.
|
||||||
*/
|
*/
|
||||||
static bool wildcard_match_internal(const wchar_t *str, const wchar_t *wc, bool leading_dots_fail_to_match, bool is_first)
|
static enum fuzzy_match_type_t wildcard_match_internal(const wchar_t *str, const wchar_t *wc, bool leading_dots_fail_to_match, bool is_first, enum fuzzy_match_type_t max_type)
|
||||||
{
|
{
|
||||||
if (*str == 0 && *wc==0)
|
if (*str == 0 && *wc==0)
|
||||||
{
|
{
|
||||||
/* We're done */
|
/* We're done */
|
||||||
return true;
|
return fuzzy_match_exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hackish fix for https://github.com/fish-shell/fish-shell/issues/270 . Prevent wildcards from matching . or .., but we must still allow literal matches. */
|
/* Hackish fix for #270 . Prevent wildcards from matching . or .., but we must still allow literal matches. */
|
||||||
if (leading_dots_fail_to_match && is_first && contains(str, L".", L".."))
|
if (leading_dots_fail_to_match && is_first && contains(str, L".", L".."))
|
||||||
{
|
{
|
||||||
/* The string is '.' or '..'. Return true if the wildcard exactly matches. */
|
/* The string is '.' or '..'. Return true if the wildcard exactly matches. */
|
||||||
return ! wcscmp(str, wc);
|
return wcscmp(str, wc) ? fuzzy_match_none : fuzzy_match_exact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hackish fuzzy match support */
|
||||||
|
if (0 && ! wildcard_has(wc, true))
|
||||||
|
{
|
||||||
|
const string_fuzzy_match_t match = string_fuzzy_match_string(wc, str);
|
||||||
|
return match.type <= max_type ? match.type : fuzzy_match_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*wc == ANY_STRING || *wc == ANY_STRING_RECURSIVE)
|
if (*wc == ANY_STRING || *wc == ANY_STRING_RECURSIVE)
|
||||||
|
@ -159,23 +166,23 @@ static bool wildcard_match_internal(const wchar_t *str, const wchar_t *wc, bool
|
||||||
/* Ignore hidden file */
|
/* Ignore hidden file */
|
||||||
if (leading_dots_fail_to_match && is_first && *str == L'.')
|
if (leading_dots_fail_to_match && is_first && *str == L'.')
|
||||||
{
|
{
|
||||||
return false;
|
return fuzzy_match_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common case of * at the end. In that case we can early out since we know it will match. */
|
/* Common case of * at the end. In that case we can early out since we know it will match. */
|
||||||
if (wc[1] == L'\0')
|
if (wc[1] == L'\0')
|
||||||
{
|
{
|
||||||
return true;
|
return fuzzy_match_exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try all submatches */
|
/* Try all submatches */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (wildcard_match_internal(str, wc+1, leading_dots_fail_to_match, false))
|
enum fuzzy_match_type_t subresult = wildcard_match_internal(str, wc+1, leading_dots_fail_to_match, false, max_type);
|
||||||
return true;
|
if (subresult != fuzzy_match_none)
|
||||||
}
|
return subresult;
|
||||||
while (*(str++) != 0);
|
} while (*str++ != 0);
|
||||||
return false;
|
return fuzzy_match_none;
|
||||||
}
|
}
|
||||||
else if (*str == 0)
|
else if (*str == 0)
|
||||||
{
|
{
|
||||||
|
@ -183,23 +190,23 @@ static bool wildcard_match_internal(const wchar_t *str, const wchar_t *wc, bool
|
||||||
End of string, but not end of wildcard, and the next wildcard
|
End of string, but not end of wildcard, and the next wildcard
|
||||||
element is not a '*', so this is not a match.
|
element is not a '*', so this is not a match.
|
||||||
*/
|
*/
|
||||||
return false;
|
return fuzzy_match_none;
|
||||||
}
|
}
|
||||||
else if (*wc == ANY_CHAR)
|
else if (*wc == ANY_CHAR)
|
||||||
{
|
{
|
||||||
if (is_first && *str == L'.')
|
if (is_first && *str == L'.')
|
||||||
{
|
{
|
||||||
return false;
|
return fuzzy_match_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wildcard_match_internal(str+1, wc+1, leading_dots_fail_to_match, false);
|
return wildcard_match_internal(str+1, wc+1, leading_dots_fail_to_match, false, max_type);
|
||||||
}
|
}
|
||||||
else if (*wc == *str)
|
else if (*wc == *str)
|
||||||
{
|
{
|
||||||
return wildcard_match_internal(str+1, wc+1, leading_dots_fail_to_match, false);
|
return wildcard_match_internal(str+1, wc+1, leading_dots_fail_to_match, false, max_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return fuzzy_match_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -407,7 +414,8 @@ bool wildcard_complete(const wcstring &str,
|
||||||
|
|
||||||
bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match)
|
bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match)
|
||||||
{
|
{
|
||||||
return wildcard_match_internal(str.c_str(), wc.c_str(), leading_dots_fail_to_match, true /* first */);
|
enum fuzzy_match_type_t match = wildcard_match_internal(str.c_str(), wc.c_str(), leading_dots_fail_to_match, true /* first */, fuzzy_match_exact);
|
||||||
|
return match != fuzzy_match_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -889,8 +897,25 @@ void wildcard_expander_t::expand(const wcstring &base_dir, const wchar_t *wc)
|
||||||
{
|
{
|
||||||
/* Literal intermediate match. Note that we may not be able to actually read the directory (#2099) */
|
/* Literal intermediate match. Note that we may not be able to actually read the directory (#2099) */
|
||||||
assert(next_slash != NULL);
|
assert(next_slash != NULL);
|
||||||
|
const wchar_t *wc_remainder = next_slash;
|
||||||
|
while (*wc_remainder == L'/')
|
||||||
|
{
|
||||||
|
wc_remainder++;
|
||||||
|
}
|
||||||
|
|
||||||
/* This just trumps everything */
|
/* This just trumps everything */
|
||||||
this->expand(base_dir + wc_segment + L'/', next_slash + 1);
|
size_t before = this->resolved_completions->size();
|
||||||
|
this->expand(base_dir + wc_segment + L'/', wc_remainder);
|
||||||
|
if (this->resolved_completions->size() == before)
|
||||||
|
{
|
||||||
|
/* Nothing was found with the literal match. Try a fuzzy match (#94). */
|
||||||
|
DIR *base_dir_fd = open_dir(base_dir);
|
||||||
|
if (base_dir_fd != NULL)
|
||||||
|
{
|
||||||
|
this->expand_intermediate_segment(base_dir, base_dir_fd, wc_segment, wc_remainder);
|
||||||
|
closedir(base_dir_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,6 +76,9 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_
|
||||||
*/
|
*/
|
||||||
bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match = false);
|
bool wildcard_match(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match = false);
|
||||||
|
|
||||||
|
/* Like wildcard_match, but returns a fuzzy match type */
|
||||||
|
enum fuzzy_match_type_t wildcard_match_fuzzy(const wcstring &str, const wcstring &wc, bool leading_dots_fail_to_match = false, enum fuzzy_match_type_t max_type = fuzzy_match_none);
|
||||||
|
|
||||||
/** Check if the specified string contains wildcards */
|
/** Check if the specified string contains wildcards */
|
||||||
bool wildcard_has(const wcstring &, bool internal);
|
bool wildcard_has(const wcstring &, bool internal);
|
||||||
bool wildcard_has(const wchar_t *, bool internal);
|
bool wildcard_has(const wchar_t *, bool internal);
|
||||||
|
|
Loading…
Reference in a new issue