Instantize contents of exec.cpp and others

This commit is contained in:
ridiculousfish 2018-09-21 21:52:47 -07:00
parent 038f3cca6d
commit 6f52e6bb1c
14 changed files with 131 additions and 93 deletions

View File

@ -19,6 +19,7 @@
#include "common.h"
#include "env.h"
#include "exec.h"
#include "parser.h"
#include "wutil.h" // IWYU pragma: keep
/// The time before we'll recheck an autoloaded file.
@ -256,7 +257,8 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
// If we have a script, either built-in or a file source, then run it.
if (really_load && !script_source.empty()) {
// Do nothing on failure.
exec_subshell(script_source, false /* do not apply exit status */);
exec_subshell(script_source, parser_t::principal_parser(),
false /* do not apply exit status */);
}
if (really_load) {

View File

@ -169,7 +169,7 @@ wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t
wcstring out;
const wcstring name_esc = escape_string(name, 1);
wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str());
if (exec_subshell(cmd, lst, false /* don't apply exit status */) >= 0) {
if (exec_subshell(cmd, parser, lst, false /* don't apply exit status */) >= 0) {
for (size_t i = 0; i < lst.size(); i++) {
out.append(lst.at(i));
out.push_back(L'\n');

View File

@ -453,7 +453,7 @@ static int validate_arg(parser_t &parser, const argparse_cmd_opts_t &opts, optio
}
vars.set_one(var_name_prefix + L"value", ENV_LOCAL, woptarg);
int retval = exec_subshell(opt_spec->validation_command, cmd_output, false);
int retval = exec_subshell(opt_spec->validation_command, parser, cmd_output, false);
for (const auto &output : cmd_output) {
streams.err.append(output);
streams.err.push_back(L'\n');

View File

@ -410,7 +410,9 @@ bool completer_t::condition_test(const wcstring &condition) {
condition_cache_t::iterator cached_entry = condition_cache.find(condition);
if (cached_entry == condition_cache.end()) {
// Compute new value and reinsert it.
test_res = (0 == exec_subshell(condition, false /* don't apply exit status */));
// TODO: rationalize this parser_t usage.
test_res = (0 == exec_subshell(condition, parser_t::principal_parser(),
false /* don't apply exit status */));
condition_cache[condition] = test_res;
} else {
// Use the old value.
@ -591,7 +593,9 @@ void completer_t::complete_cmd_desc(const wcstring &str) {
// search if we know the location of the whatis database. This can take some time on slower
// systems with a large set of manuals, but it should be ok since apropos is only called once.
wcstring_list_t list;
if (exec_subshell(lookup_cmd, list, false /* don't apply exit status */) != -1) {
// TODO: rationalize this use of principal_parser.
if (exec_subshell(lookup_cmd, parser_t::principal_parser(), list,
false /* don't apply exit status */) != -1) {
std::unordered_map<wcstring, wcstring> lookup;
lookup.reserve(list.size());

View File

@ -369,7 +369,7 @@ void internal_exec(env_stack_t &vars, job_t *j, const io_chain_t &all_ios) {
// really make sense, so I'm not trying to fix it here.
if (!setup_child_process(0, all_ios)) {
// Decrement SHLVL as we're removing ourselves from the shell "stack".
auto shlvl_var = env_get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
auto shlvl_var = vars.get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
wcstring shlvl_str = L"0";
if (shlvl_var) {
long shlvl = fish_wcstol(shlvl_var->as_string().c_str());
@ -1085,14 +1085,14 @@ bool exec_job(parser_t &parser, shared_ptr<job_t> j) {
return true;
}
static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, bool apply_exit_status,
bool is_subcmd) {
static int exec_subshell_internal(const wcstring &cmd, parser_t &parser, wcstring_list_t *lst,
bool apply_exit_status, bool is_subcmd) {
ASSERT_IS_MAIN_THREAD();
bool prev_subshell = is_subshell;
const int prev_status = proc_get_last_status();
bool split_output = false;
const auto ifs = env_get(L"IFS");
const auto ifs = parser.vars().get(L"IFS");
if (!ifs.missing_or_empty()) {
split_output = true;
}
@ -1163,13 +1163,13 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo
return subcommand_status;
}
int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool apply_exit_status,
bool is_subcmd) {
int exec_subshell(const wcstring &cmd, parser_t &parser, std::vector<wcstring> &outputs,
bool apply_exit_status, bool is_subcmd) {
ASSERT_IS_MAIN_THREAD();
return exec_subshell_internal(cmd, &outputs, apply_exit_status, is_subcmd);
return exec_subshell_internal(cmd, parser, &outputs, apply_exit_status, is_subcmd);
}
int exec_subshell(const wcstring &cmd, bool apply_exit_status, bool is_subcmd) {
int exec_subshell(const wcstring &cmd, parser_t &parser, bool apply_exit_status, bool is_subcmd) {
ASSERT_IS_MAIN_THREAD();
return exec_subshell_internal(cmd, NULL, apply_exit_status, is_subcmd);
return exec_subshell_internal(cmd, parser, NULL, apply_exit_status, is_subcmd);
}

View File

@ -23,9 +23,10 @@ bool exec_job(parser_t &parser, std::shared_ptr<job_t> j);
/// \param outputs The list to insert output into.
///
/// \return the status of the last job to exit, or -1 if en error was encountered.
int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs, bool preserve_exit_status,
int exec_subshell(const wcstring &cmd, parser_t &parser, std::vector<wcstring> &outputs,
bool preserve_exit_status, bool is_subcmd = false);
int exec_subshell(const wcstring &cmd, parser_t &parser, bool preserve_exit_status,
bool is_subcmd = false);
int exec_subshell(const wcstring &cmd, bool preserve_exit_status, bool is_subcmd = false);
/// Loops over close until the syscall was run without being interrupted.
void exec_close(int fd);

View File

@ -43,6 +43,7 @@
#include "iothread.h"
#include "parse_constants.h"
#include "parse_util.h"
#include "parser.h"
#include "path.h"
#include "proc.h"
#include "reader.h"
@ -292,7 +293,7 @@ static size_t parse_slice(const wchar_t *in, wchar_t **end_ptr, std::vector<long
/// actually starts operating on last_idx-1. As such, to process a string fully, pass string.size()
/// as last_idx instead of string.size()-1.
static bool expand_variables(wcstring instr, std::vector<completion_t> *out, size_t last_idx,
parse_error_list_t *errors) {
const environment_t &vars, parse_error_list_t *errors) {
const size_t insize = instr.size();
// last_idx may be 1 past the end of the string, but no further.
@ -356,7 +357,7 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
history = &history_t::history_with_name(history_session_id(env_stack_t::principal()));
}
} else if (var_name != wcstring{VARIABLE_EXPAND_EMPTY}) {
var = env_get(var_name);
var = vars.get(var_name);
}
// Parse out any following slice.
@ -406,7 +407,7 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
res.push_back(VARIABLE_EXPAND_EMPTY);
}
res.append(instr, var_name_and_slice_stop, wcstring::npos);
return expand_variables(std::move(res), out, varexp_char_idx, errors);
return expand_variables(std::move(res), out, varexp_char_idx, vars, errors);
}
}
@ -463,7 +464,7 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
// Append all entries in var_item_list, separated by the delimiter.
res.append(join_strings(var_item_list, delimit));
res.append(instr, var_name_and_slice_stop, wcstring::npos);
return expand_variables(std::move(res), out, varexp_char_idx, errors);
return expand_variables(std::move(res), out, varexp_char_idx, vars, errors);
} else {
// Normal cartesian-product expansion.
for (const wcstring &item : var_item_list) {
@ -480,7 +481,7 @@ static bool expand_variables(wcstring instr, std::vector<completion_t> *out, siz
}
new_in.append(item);
new_in.append(instr, var_name_and_slice_stop, wcstring::npos);
if (!expand_variables(std::move(new_in), out, varexp_char_idx, errors)) {
if (!expand_variables(std::move(new_in), out, varexp_char_idx, vars, errors)) {
return false;
}
}
@ -637,7 +638,10 @@ static bool expand_cmdsubst(const wcstring &input, std::vector<completion_t> *ou
wcstring_list_t sub_res;
const wcstring subcmd(paren_begin + 1, paren_end - paren_begin - 1);
if (exec_subshell(subcmd, sub_res, true /* apply_exit_status */, true /* is_subcmd */) == -1) {
// TODO: justify this parser_t::principal_parser
auto &parser = parser_t::principal_parser();
if (exec_subshell(subcmd, parser, sub_res, true /* apply_exit_status */,
true /* is_subcmd */) == -1) {
append_cmdsub_error(errors, SOURCE_LOCATION_UNKNOWN,
L"Unknown error while evaulating command substitution");
return false;
@ -742,7 +746,7 @@ static wcstring get_home_directory_name(const wcstring &input, size_t *out_tail_
}
/// Attempts tilde expansion of the string specified, modifying it in place.
static void expand_home_directory(wcstring &input) {
static void expand_home_directory(wcstring &input, const environment_t &vars) {
if (!input.empty() && input.at(0) == HOME_DIRECTORY) {
size_t tail_idx;
wcstring username = get_home_directory_name(input, &tail_idx);
@ -750,7 +754,7 @@ static void expand_home_directory(wcstring &input) {
maybe_t<wcstring> home;
if (username.empty()) {
// Current users home directory.
auto home_var = env_get(L"HOME");
auto home_var = vars.get(L"HOME");
if (home_var.missing_or_empty()) {
input.clear();
return;
@ -787,16 +791,17 @@ static void expand_percent_self(wcstring &input) {
}
}
void expand_tilde(wcstring &input) {
void expand_tilde(wcstring &input, const environment_t &vars) {
// Avoid needless COW behavior by ensuring we use const at.
const wcstring &tmp = input;
if (!tmp.empty() && tmp.at(0) == L'~') {
input.at(0) = HOME_DIRECTORY;
expand_home_directory(input);
expand_home_directory(input, vars);
}
}
static void unexpand_tildes(const wcstring &input, std::vector<completion_t> *completions) {
static void unexpand_tildes(const wcstring &input, const environment_t &vars,
std::vector<completion_t> *completions) {
// If input begins with tilde, then try to replace the corresponding string in each completion
// with the tilde. If it does not, there's nothing to do.
if (input.empty() || input.at(0) != L'~') return;
@ -818,7 +823,7 @@ static void unexpand_tildes(const wcstring &input, std::vector<completion_t> *co
// Expand username_with_tilde.
wcstring home = username_with_tilde;
expand_tilde(home);
expand_tilde(home, vars);
// Now for each completion that starts with home, replace it with the username_with_tilde.
for (size_t i = 0; i < completions->size(); i++) {
@ -835,12 +840,12 @@ static void unexpand_tildes(const wcstring &input, std::vector<completion_t> *co
// If the given path contains the user's home directory, replace that with a tilde. We don't try to
// be smart about case insensitivity, etc.
wcstring replace_home_directory_with_tilde(const wcstring &str) {
wcstring replace_home_directory_with_tilde(const wcstring &str, const environment_t &vars) {
// Only absolute paths get this treatment.
wcstring result = str;
if (string_prefixes_string(L"/", result)) {
wcstring home_directory = L"~";
expand_tilde(home_directory);
expand_tilde(home_directory, vars);
if (!string_suffixes_string(L"/", home_directory)) {
home_directory.push_back(L'/');
}
@ -928,7 +933,7 @@ static expand_error_t expand_stage_variables(wcstring input, std::vector<complet
append_completion(out, std::move(next));
} else {
size_t size = next.size();
if (!expand_variables(std::move(next), out, size, errors)) {
if (!expand_variables(std::move(next), out, size, vars, errors)) {
return EXPAND_ERROR;
}
}
@ -946,7 +951,7 @@ static expand_error_t expand_stage_home_and_self(wcstring input, std::vector<com
parse_error_list_t *errors) {
(void)errors;
if (!(EXPAND_SKIP_HOME_DIRECTORIES & flags)) {
expand_home_directory(input);
expand_home_directory(input, vars);
}
expand_percent_self(input);
append_completion(out, std::move(input));
@ -1087,7 +1092,7 @@ expand_error_t expand_string(wcstring input, std::vector<completion_t> *out_comp
if (total_result != EXPAND_ERROR) {
// Hack to un-expand tildes (see #647).
if (!(flags & EXPAND_SKIP_HOME_DIRECTORIES)) {
unexpand_tildes(input, &completions);
unexpand_tildes(input, vars, &completions);
}
out_completions->insert(out_completions->end(),
std::make_move_iterator(completions.begin()),

View File

@ -17,6 +17,7 @@
#include "maybe.h"
#include "parse_constants.h"
class environment_t;
class env_var_t;
class environment_t;
@ -152,10 +153,10 @@ wcstring expand_escape_variable(const env_var_t &var);
/// Perform tilde expansion and nothing else on the specified string, which is modified in place.
///
/// \param input the string to tilde expand
void expand_tilde(wcstring &input);
void expand_tilde(wcstring &input, const environment_t &vars);
/// Perform the opposite of tilde expansion on the string, which is modified in place.
wcstring replace_home_directory_with_tilde(const wcstring &str);
wcstring replace_home_directory_with_tilde(const wcstring &str, const environment_t &vars);
/// Abbreviation support. Expand src as an abbreviation, returning the expanded form if found,
/// none() if not.

View File

@ -1502,11 +1502,17 @@ static void test_lru() {
/// A crappy environment_t that only knows about PWD.
struct pwd_environment_t : public environment_t {
std::map<wcstring, wcstring> extras;
virtual maybe_t<env_var_t> get(const wcstring &key,
env_mode_flags_t mode = ENV_DEFAULT) const override {
if (key == L"PWD") {
return env_var_t{wgetcwd(), 0};
}
auto extra = extras.find(key);
if (extra != extras.end()) {
return env_var_t(extra->second, ENV_DEFAULT);
}
return {};
}
@ -2620,9 +2626,9 @@ static void test_completion_insertions() {
}
static void perform_one_autosuggestion_cd_test(const wcstring &command, const wcstring &expected,
long line) {
const environment_t &vars, long line) {
std::vector<completion_t> comps;
complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, pwd_environment_t{});
complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, vars);
bool expects_error = (expected == L"<error>");
@ -2694,7 +2700,6 @@ static void perform_one_completion_cd_test(const wcstring &command, const wcstri
// Testing test_autosuggest_suggest_special, in particular for properly handling quotes and
// backslashes.
static void test_autosuggest_suggest_special() {
auto &vars = parser_t::principal_parser().vars();
if (system("mkdir -p 'test/autosuggest_test/0foobar'")) err(L"mkdir failed");
if (system("mkdir -p 'test/autosuggest_test/1foo bar'")) err(L"mkdir failed");
if (system("mkdir -p 'test/autosuggest_test/2foo bar'")) err(L"mkdir failed");
@ -2724,60 +2729,72 @@ static void test_autosuggest_suggest_special() {
const wcstring wd = L"test/autosuggest_test";
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/5", L"foo\"bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/5", L"foo\"bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/5", L"foo\"bar/", __LINE__);
pwd_environment_t vars{};
vars.extras[L"HOME"] = parser_t::principal_parser().vars().get(L"HOME")->as_string();
vars.set_one(L"AUTOSUGGEST_TEST_LOC", ENV_LOCAL, wd);
perform_one_autosuggestion_cd_test(L"cd $AUTOSUGGEST_TEST_LOC/0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~/test_autosuggest_suggest_specia", L"l/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/start/", L"unique2/unique3/",
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/1", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/1", L"foo bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/1", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/2", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/2", L"foo bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/2", L"foo bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/3", L"foo\\bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/3", L"foo\\bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/3", L"foo\\bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/4", L"foo'bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/4", L"foo'bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/4", L"foo'bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/5", L"foo\"bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/5", L"foo\"bar/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/5", L"foo\"bar/", vars,
__LINE__);
vars.extras[L"AUTOSUGGEST_TEST_LOC"] = wd;
perform_one_autosuggestion_cd_test(L"cd $AUTOSUGGEST_TEST_LOC/0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~/test_autosuggest_suggest_specia", L"l/", vars,
__LINE__);
perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/start/", L"unique2/unique3/",
vars, __LINE__);
if (!pushd(wcs2string(wd).c_str())) return;
perform_one_autosuggestion_cd_test(L"cd 0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '0", L"foobar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '1", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '2", L"foo bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '3", L"foo\\bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '4", L"foo'bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 5", L"foo\"bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"5", L"foo\"bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd '5", L"foo\"bar/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd 0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '0", L"foobar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 1", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"1", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '1", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 2", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"2", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '2", L"foo bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 3", L"foo\\bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"3", L"foo\\bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '3", L"foo\\bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 4", L"foo'bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"4", L"foo'bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '4", L"foo'bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd 5", L"foo\"bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd \"5", L"foo\"bar/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd '5", L"foo\"bar/", vars, __LINE__);
// A single quote should defeat tilde expansion.
perform_one_autosuggestion_cd_test(L"cd '~/test_autosuggest_suggest_specia'", L"<error>",
perform_one_autosuggestion_cd_test(L"cd '~/test_autosuggest_suggest_specia'", L"<error>", vars,
__LINE__);
// Don't crash on ~ (issue #2696). Note this is cwd dependent.
if (system("mkdir -p '~hahaha/path1/path2/'")) err(L"mkdir failed");
perform_one_autosuggestion_cd_test(L"cd ~haha", L"ha/path1/path2/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~hahaha/", L"path1/path2/", __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~haha", L"ha/path1/path2/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~hahaha/", L"path1/path2/", vars, __LINE__);
perform_one_completion_cd_test(L"cd ~haha", L"ha/", __LINE__);
perform_one_completion_cd_test(L"cd ~hahaha/", L"path1/", __LINE__);

View File

@ -114,7 +114,7 @@ bool is_potential_path(const wcstring &potential_path_fragment, const wcstring_l
bool result = false;
wcstring path_with_magic(potential_path_fragment);
if (flags & PATH_EXPAND_TILDE) expand_tilde(path_with_magic);
if (flags & PATH_EXPAND_TILDE) expand_tilde(path_with_magic, vars);
// debug( 1, L"%ls -> %ls ->%ls", path, tilde, unescaped );

View File

@ -96,8 +96,8 @@ static const struct block_lookup_entry block_lookup[] = {
{(block_type_t)0, 0, 0}};
// Given a file path, return something nicer. Currently we just "unexpand" tildes.
static wcstring user_presentable_path(const wcstring &path) {
return replace_home_directory_with_tilde(path);
wcstring parser_t::user_presentable_path(const wcstring &path) const {
return replace_home_directory_with_tilde(path, vars());
}
parser_t::parser_t() : variables(env_stack_t::principal()) {}

View File

@ -199,6 +199,9 @@ class parser_t {
/// every block if it is of type FUNCTION_CALL.
const wchar_t *is_function(size_t idx = 0) const;
// Given a file path, return something nicer. Currently we just "unexpand" tildes.
wcstring user_presentable_path(const wcstring &path) const;
/// Helper for stack_trace().
void stack_trace_internal(size_t block_idx, wcstring *out) const;

View File

@ -187,7 +187,7 @@ maybe_t<wcstring> path_get_cdpath(const wcstring &dir, const wcstring &wd,
// TODO: if next_path starts with ./ we need to replace the . with the wd.
next_path = wd;
}
expand_tilde(next_path);
expand_tilde(next_path, env_vars);
if (next_path.empty()) continue;
wcstring whole_path = next_path;
@ -213,7 +213,7 @@ maybe_t<wcstring> path_get_cdpath(const wcstring &dir, const wcstring &wd,
maybe_t<wcstring> path_as_implicit_cd(const wcstring &path, const wcstring &wd,
const environment_t &vars) {
wcstring exp_path = path;
expand_tilde(exp_path);
expand_tilde(exp_path, vars);
if (string_prefixes_string(L"/", exp_path) || string_prefixes_string(L"./", exp_path) ||
string_prefixes_string(L"../", exp_path) || string_suffixes_string(L"/", exp_path) ||
exp_path == L"..") {

View File

@ -400,6 +400,9 @@ class reader_data_t {
/// Return the variable set used for e.g. command duration.
env_stack_t &vars() { return parser_t::principal_parser().vars(); }
/// Hackish access to the parser. TODO: rationalize this.
parser_t &parser() { return parser_t::principal_parser(); }
const env_stack_t &vars() const { return parser_t::principal_parser().vars(); }
/// Constructor
@ -829,7 +832,8 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) {
wcstring_list_t lst;
proc_push_interactive(0);
if (exec_subshell(fish_title_command, lst, false /* ignore exit status */) != -1 &&
if (exec_subshell(fish_title_command, current_data()->parser(), lst,
false /* ignore exit status */) != -1 &&
!lst.empty()) {
fputws(L"\x1B]0;", stdout);
for (size_t i = 0; i < lst.size(); i++) {
@ -867,7 +871,8 @@ static void exec_prompt() {
// Prepend any mode indicator to the left prompt (issue #1988).
if (function_exists(MODE_PROMPT_FUNCTION_NAME)) {
wcstring_list_t mode_indicator_list;
exec_subshell(MODE_PROMPT_FUNCTION_NAME, mode_indicator_list, apply_exit_status);
exec_subshell(MODE_PROMPT_FUNCTION_NAME, data->parser(), mode_indicator_list,
apply_exit_status);
// We do not support multiple lines in the mode indicator, so just concatenate all of
// them.
for (size_t i = 0; i < mode_indicator_list.size(); i++) {
@ -878,7 +883,7 @@ static void exec_prompt() {
if (!data->left_prompt.empty()) {
wcstring_list_t prompt_list;
// Ignore return status.
exec_subshell(data->left_prompt, prompt_list, apply_exit_status);
exec_subshell(data->left_prompt, data->parser(), prompt_list, apply_exit_status);
for (size_t i = 0; i < prompt_list.size(); i++) {
if (i > 0) data->left_prompt_buff += L'\n';
data->left_prompt_buff += prompt_list.at(i);
@ -888,7 +893,7 @@ static void exec_prompt() {
if (!data->right_prompt.empty()) {
wcstring_list_t prompt_list;
// Status is ignored.
exec_subshell(data->right_prompt, prompt_list, apply_exit_status);
exec_subshell(data->right_prompt, data->parser(), prompt_list, apply_exit_status);
for (size_t i = 0; i < prompt_list.size(); i++) {
// Right prompt does not support multiple lines, so just concatenate all of them.
data->right_prompt_buff += prompt_list.at(i);
@ -2155,9 +2160,9 @@ void reader_import_history_if_necessary() {
// Try opening a bash file. We make an effort to respect $HISTFILE; this isn't very complete
// (AFAIK it doesn't have to be exported), and to really get this right we ought to ask bash
// itself. But this is better than nothing.
const auto var = env_get(L"HISTFILE");
const auto var = data->vars().get(L"HISTFILE");
wcstring path = (var ? var->as_string() : L"~/.bash_history");
expand_tilde(path);
expand_tilde(path, data->vars());
FILE *f = wfopen(path, "r");
if (f) {
data->history->populate_from_bash(f);