mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-29 05:13:43 +00:00
Thread a cancellation function into is_potential_path
Allows sooner cancellation of redundant operations like highlighting.
This commit is contained in:
parent
a65e3f1876
commit
f6e5a5c521
3 changed files with 34 additions and 29 deletions
|
@ -2356,26 +2356,26 @@ static void test_is_potential_path() {
|
||||||
const wcstring wd = L"test/is_potential_path_test/";
|
const wcstring wd = L"test/is_potential_path_test/";
|
||||||
const wcstring_list_t wds({L".", wd});
|
const wcstring_list_t wds({L".", wd});
|
||||||
|
|
||||||
const auto &vars = env_stack_t::principal();
|
operation_context_t ctx{env_stack_t::principal()};
|
||||||
do_test(is_potential_path(L"al", wds, vars, PATH_REQUIRE_DIR));
|
do_test(is_potential_path(L"al", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(is_potential_path(L"alpha/", wds, vars, PATH_REQUIRE_DIR));
|
do_test(is_potential_path(L"alpha/", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(is_potential_path(L"aard", wds, vars, 0));
|
do_test(is_potential_path(L"aard", wds, ctx, 0));
|
||||||
|
|
||||||
do_test(!is_potential_path(L"balpha/", wds, vars, PATH_REQUIRE_DIR));
|
do_test(!is_potential_path(L"balpha/", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(!is_potential_path(L"aard", wds, vars, PATH_REQUIRE_DIR));
|
do_test(!is_potential_path(L"aard", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(!is_potential_path(L"aarde", wds, vars, PATH_REQUIRE_DIR));
|
do_test(!is_potential_path(L"aarde", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(!is_potential_path(L"aarde", wds, vars, 0));
|
do_test(!is_potential_path(L"aarde", wds, ctx, 0));
|
||||||
|
|
||||||
do_test(is_potential_path(L"test/is_potential_path_test/aardvark", wds, vars, 0));
|
do_test(is_potential_path(L"test/is_potential_path_test/aardvark", wds, ctx, 0));
|
||||||
do_test(is_potential_path(L"test/is_potential_path_test/al", wds, vars, PATH_REQUIRE_DIR));
|
do_test(is_potential_path(L"test/is_potential_path_test/al", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(is_potential_path(L"test/is_potential_path_test/aardv", wds, vars, 0));
|
do_test(is_potential_path(L"test/is_potential_path_test/aardv", wds, ctx, 0));
|
||||||
|
|
||||||
do_test(
|
do_test(
|
||||||
!is_potential_path(L"test/is_potential_path_test/aardvark", wds, vars, PATH_REQUIRE_DIR));
|
!is_potential_path(L"test/is_potential_path_test/aardvark", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
do_test(!is_potential_path(L"test/is_potential_path_test/al/", wds, vars, 0));
|
do_test(!is_potential_path(L"test/is_potential_path_test/al/", wds, ctx, 0));
|
||||||
do_test(!is_potential_path(L"test/is_potential_path_test/ar", wds, vars, 0));
|
do_test(!is_potential_path(L"test/is_potential_path_test/ar", wds, ctx, 0));
|
||||||
|
|
||||||
do_test(is_potential_path(L"/usr", wds, vars, PATH_REQUIRE_DIR));
|
do_test(is_potential_path(L"/usr", wds, ctx, PATH_REQUIRE_DIR));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test the 'test' builtin.
|
/// Test the 'test' builtin.
|
||||||
|
|
|
@ -204,16 +204,18 @@ bool fs_is_case_insensitive(const wcstring &path, int fd,
|
||||||
///
|
///
|
||||||
/// We expect the path to already be unescaped.
|
/// We expect the path to already be unescaped.
|
||||||
bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_list_t &directories,
|
bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_list_t &directories,
|
||||||
const environment_t &vars, path_flags_t flags) {
|
const operation_context_t &ctx, path_flags_t flags) {
|
||||||
ASSERT_IS_BACKGROUND_THREAD();
|
ASSERT_IS_BACKGROUND_THREAD();
|
||||||
|
|
||||||
|
if (ctx.check_cancel()) return false;
|
||||||
|
|
||||||
const bool require_dir = static_cast<bool>(flags & PATH_REQUIRE_DIR);
|
const bool require_dir = static_cast<bool>(flags & PATH_REQUIRE_DIR);
|
||||||
wcstring clean_potential_path_fragment;
|
wcstring clean_potential_path_fragment;
|
||||||
int has_magic = 0;
|
int has_magic = 0;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
wcstring path_with_magic(potential_path_fragment);
|
wcstring path_with_magic(potential_path_fragment);
|
||||||
if (flags & PATH_EXPAND_TILDE) expand_tilde(path_with_magic, vars);
|
if (flags & PATH_EXPAND_TILDE) expand_tilde(path_with_magic, ctx.vars);
|
||||||
|
|
||||||
for (auto c : path_with_magic) {
|
for (auto c : path_with_magic) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -250,9 +252,8 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
// Keep a cache of which paths / filesystems are case sensitive.
|
// Keep a cache of which paths / filesystems are case sensitive.
|
||||||
case_sensitivity_cache_t case_sensitivity_cache;
|
case_sensitivity_cache_t case_sensitivity_cache;
|
||||||
|
|
||||||
for (size_t wd_idx = 0; wd_idx < directories.size() && !result; wd_idx++) {
|
for (const wcstring &wd : directories) {
|
||||||
const wcstring &wd = directories.at(wd_idx);
|
if (ctx.check_cancel()) return false;
|
||||||
|
|
||||||
const wcstring abs_path = path_apply_working_directory(clean_potential_path_fragment, wd);
|
const wcstring abs_path = path_apply_working_directory(clean_potential_path_fragment, wd);
|
||||||
|
|
||||||
// Skip this if it's empty or we've already checked it.
|
// Skip this if it's empty or we've already checked it.
|
||||||
|
@ -275,6 +276,8 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
// cd ///.... No autosuggestion.
|
// cd ///.... No autosuggestion.
|
||||||
result = true;
|
result = true;
|
||||||
} else if ((dir = wopendir(dir_name))) {
|
} else if ((dir = wopendir(dir_name))) {
|
||||||
|
cleanup_t cleanup_dir([&] { closedir(dir); });
|
||||||
|
|
||||||
// Check if we're case insensitive.
|
// Check if we're case insensitive.
|
||||||
const bool do_case_insensitive =
|
const bool do_case_insensitive =
|
||||||
fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache);
|
fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache);
|
||||||
|
@ -287,6 +290,8 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
wcstring ent;
|
wcstring ent;
|
||||||
bool is_dir = false;
|
bool is_dir = false;
|
||||||
while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : nullptr)) {
|
while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : nullptr)) {
|
||||||
|
if (ctx.check_cancel()) return false;
|
||||||
|
|
||||||
// Maybe skip directories.
|
// Maybe skip directories.
|
||||||
if (require_dir && !is_dir) {
|
if (require_dir && !is_dir) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -299,7 +304,6 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
result = !matched_file.empty(); // we succeeded if we found a match
|
result = !matched_file.empty(); // we succeeded if we found a match
|
||||||
}
|
}
|
||||||
|
@ -312,7 +316,7 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
|
||||||
// Given a string, return whether it prefixes a path that we could cd into. Return that path in
|
// Given a string, return whether it prefixes a path that we could cd into. Return that path in
|
||||||
// out_path. Expects path to be unescaped.
|
// out_path. Expects path to be unescaped.
|
||||||
static bool is_potential_cd_path(const wcstring &path, const wcstring &working_directory,
|
static bool is_potential_cd_path(const wcstring &path, const wcstring &working_directory,
|
||||||
const environment_t &vars, path_flags_t flags) {
|
const operation_context_t &ctx, path_flags_t flags) {
|
||||||
wcstring_list_t directories;
|
wcstring_list_t directories;
|
||||||
|
|
||||||
if (string_prefixes_string(L"./", path)) {
|
if (string_prefixes_string(L"./", path)) {
|
||||||
|
@ -320,7 +324,7 @@ static bool is_potential_cd_path(const wcstring &path, const wcstring &working_d
|
||||||
directories.push_back(working_directory);
|
directories.push_back(working_directory);
|
||||||
} else {
|
} else {
|
||||||
// Get the CDPATH.
|
// Get the CDPATH.
|
||||||
auto cdpath = vars.get(L"CDPATH");
|
auto cdpath = ctx.vars.get(L"CDPATH");
|
||||||
wcstring_list_t pathsv =
|
wcstring_list_t pathsv =
|
||||||
cdpath.missing_or_empty() ? wcstring_list_t{L"."} : cdpath->as_list();
|
cdpath.missing_or_empty() ? wcstring_list_t{L"."} : cdpath->as_list();
|
||||||
|
|
||||||
|
@ -332,7 +336,7 @@ static bool is_potential_cd_path(const wcstring &path, const wcstring &working_d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call is_potential_path with all of these directories.
|
// Call is_potential_path with all of these directories.
|
||||||
return is_potential_path(path, directories, vars, flags | PATH_REQUIRE_DIR);
|
return is_potential_path(path, directories, ctx, flags | PATH_REQUIRE_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a plain statement node in a parse tree, get the command and return it, expanded
|
// Given a plain statement node in a parse tree, get the command and return it, expanded
|
||||||
|
@ -905,7 +909,8 @@ void highlighter_t::color_argument(tnode_t<g::tok_string> node) {
|
||||||
/// Indicates whether the source range of the given node forms a valid path in the given
|
/// Indicates whether the source range of the given node forms a valid path in the given
|
||||||
/// working_directory.
|
/// working_directory.
|
||||||
static bool node_is_potential_path(const wcstring &src, const parse_node_t &node,
|
static bool node_is_potential_path(const wcstring &src, const parse_node_t &node,
|
||||||
const environment_t &vars, const wcstring &working_directory) {
|
const operation_context_t &ctx,
|
||||||
|
const wcstring &working_directory) {
|
||||||
if (!node.has_source()) return false;
|
if (!node.has_source()) return false;
|
||||||
|
|
||||||
// Get the node source, unescape it, and then pass it to is_potential_path along with the
|
// Get the node source, unescape it, and then pass it to is_potential_path along with the
|
||||||
|
@ -918,7 +923,7 @@ static bool node_is_potential_path(const wcstring &src, const parse_node_t &node
|
||||||
if (!token.empty() && token.at(0) == HOME_DIRECTORY) token.at(0) = L'~';
|
if (!token.empty() && token.at(0) == HOME_DIRECTORY) token.at(0) = L'~';
|
||||||
|
|
||||||
const wcstring_list_t working_directory_list(1, working_directory);
|
const wcstring_list_t working_directory_list(1, working_directory);
|
||||||
result = is_potential_path(token, working_directory_list, vars, PATH_EXPAND_TILDE);
|
result = is_potential_path(token, working_directory_list, ctx, PATH_EXPAND_TILDE);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -948,7 +953,7 @@ void highlighter_t::color_arguments(const std::vector<tnode_t<g::argument>> &arg
|
||||||
bool is_help = string_prefixes_string(param, L"--help") ||
|
bool is_help = string_prefixes_string(param, L"--help") ||
|
||||||
string_prefixes_string(param, L"-h");
|
string_prefixes_string(param, L"-h");
|
||||||
if (!is_help && this->io_ok &&
|
if (!is_help && this->io_ok &&
|
||||||
!is_potential_cd_path(param, working_directory, ctx.vars, PATH_EXPAND_TILDE)) {
|
!is_potential_cd_path(param, working_directory, ctx, PATH_EXPAND_TILDE)) {
|
||||||
this->color_node(arg, highlight_role_t::error);
|
this->color_node(arg, highlight_role_t::error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1301,7 +1306,7 @@ highlighter_t::color_array_t highlighter_t::highlight() {
|
||||||
if (ctx.check_cancel()) return std::move(color_array);
|
if (ctx.check_cancel()) return std::move(color_array);
|
||||||
|
|
||||||
// Underline every valid path.
|
// Underline every valid path.
|
||||||
if (node_is_potential_path(buff, node, ctx.vars, working_directory)) {
|
if (node_is_potential_path(buff, node, ctx, working_directory)) {
|
||||||
// It is, underline it.
|
// It is, underline it.
|
||||||
for (size_t i = node.source_start; i < node.source_start + node.source_length; i++) {
|
for (size_t i = node.source_start; i < node.source_start + node.source_length; i++) {
|
||||||
// Don't color highlight_role_t::error because it looks dorky. For example,
|
// Don't color highlight_role_t::error because it looks dorky. For example,
|
||||||
|
|
|
@ -126,6 +126,6 @@ enum {
|
||||||
};
|
};
|
||||||
typedef unsigned int path_flags_t;
|
typedef unsigned int path_flags_t;
|
||||||
bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_list_t &directories,
|
bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_list_t &directories,
|
||||||
const environment_t &vars, path_flags_t flags);
|
const operation_context_t &ctx, path_flags_t flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue