mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-25 20:33:08 +00:00
Thread a parser into function_exists
Since this may autoload, it needs a parser with which to autoload.
This commit is contained in:
parent
bffacd2fbf
commit
1e57424011
10 changed files with 44 additions and 43 deletions
|
@ -190,8 +190,7 @@ maybe_t<wcstring> autoload_t::resolve_command(const wcstring &cmd, const environ
|
|||
return std::move(mfile->path);
|
||||
}
|
||||
|
||||
void autoload_t::perform_autoload(const wcstring &path) {
|
||||
void autoload_t::perform_autoload(const wcstring &path, parser_t &parser) {
|
||||
wcstring script_source = L"source " + escape_string(path, ESCAPE_ALL);
|
||||
exec_subshell(script_source, parser_t::principal_parser(),
|
||||
false /* do not apply exit status */);
|
||||
exec_subshell(script_source, parser, false /* do not apply exit status */);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
class autoload_file_cache_t;
|
||||
class environment_t;
|
||||
class parser_t;
|
||||
|
||||
/// autoload_t is a class that knows how to autoload .fish files from a list of directories. This
|
||||
/// is used by autoloading functions and completions. It maintains a file cache, which is
|
||||
|
@ -58,7 +59,7 @@ class autoload_t {
|
|||
/// Helper to actually perform an autoload.
|
||||
/// This is a static function because it executes fish script, and so must be called without
|
||||
/// holding any particular locks.
|
||||
static void perform_autoload(const wcstring &path);
|
||||
static void perform_autoload(const wcstring &path, parser_t &parser);
|
||||
|
||||
/// Mark that a command previously returned from path_to_autoload is finished autoloading.
|
||||
void mark_autoload_finished(const wcstring &cmd) {
|
||||
|
|
|
@ -101,7 +101,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
const wcstring ft = tok_first(job->command());
|
||||
//For compatibility with fish 2.0's $_, now replaced with `status current-command`
|
||||
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
|
||||
reader_write_title(job->command());
|
||||
reader_write_title(job->command(), parser);
|
||||
|
||||
job->promote();
|
||||
job->set_flag(job_flag_t::FOREGROUND, true);
|
||||
|
|
|
@ -225,14 +225,14 @@ static wcstring functions_def(const wcstring &name) {
|
|||
}
|
||||
|
||||
static int report_function_metadata(const wchar_t *funcname, bool verbose, io_streams_t &streams,
|
||||
bool metadata_as_comments) {
|
||||
parser_t &parser, bool metadata_as_comments) {
|
||||
const wchar_t *path = L"n/a";
|
||||
const wchar_t *autoloaded = L"n/a";
|
||||
const wchar_t *shadows_scope = L"n/a";
|
||||
wcstring description = L"n/a";
|
||||
int line_number = 0;
|
||||
|
||||
if (function_exists(funcname)) {
|
||||
if (function_exists(funcname, parser)) {
|
||||
auto props = function_get_properties(funcname);
|
||||
path = function_get_definition_file(funcname);
|
||||
if (path) {
|
||||
|
@ -301,13 +301,13 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
|
||||
func = argv[optind];
|
||||
if (!function_exists(func)) {
|
||||
if (!function_exists(func, parser)) {
|
||||
streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, func);
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
|
||||
function_set_desc(func, opts.description);
|
||||
function_set_desc(func, opts.description, parser);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
@ -319,7 +319,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
|
||||
const wchar_t *funcname = argv[optind];
|
||||
return report_function_metadata(funcname, opts.verbose, streams, false);
|
||||
return report_function_metadata(funcname, opts.verbose, streams, parser, false);
|
||||
}
|
||||
|
||||
if (opts.handlers) {
|
||||
|
@ -376,7 +376,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
current_func = argv[optind];
|
||||
new_func = argv[optind + 1];
|
||||
|
||||
if (!function_exists(current_func)) {
|
||||
if (!function_exists(current_func, parser)) {
|
||||
streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd,
|
||||
current_func.c_str());
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
|
@ -391,7 +391,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
|
||||
// Keep things simple: don't allow existing names to be copy targets.
|
||||
if (function_exists(new_func)) {
|
||||
if (function_exists(new_func, parser)) {
|
||||
streams.err.append_format(
|
||||
_(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), cmd,
|
||||
new_func.c_str(), current_func.c_str());
|
||||
|
@ -405,13 +405,13 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
|
||||
int res = STATUS_CMD_OK;
|
||||
for (int i = optind; i < argc; i++) {
|
||||
if (!function_exists(argv[i])) {
|
||||
if (!function_exists(argv[i], parser)) {
|
||||
res++;
|
||||
} else {
|
||||
if (!opts.query) {
|
||||
if (i != optind) streams.out.append(L"\n");
|
||||
const wchar_t *funcname = argv[optind];
|
||||
report_function_metadata(funcname, opts.verbose, streams, true);
|
||||
report_function_metadata(funcname, opts.verbose, streams, parser, true);
|
||||
streams.out.append(functions_def(funcname));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -859,7 +859,8 @@ static bool short_ok(const wcstring &arg, const complete_entry_opt_t *entry,
|
|||
static void complete_load(const wcstring &name, bool reload) {
|
||||
// We have to load this as a function, since it may define a --wraps or signature.
|
||||
// See issue #2466.
|
||||
function_load(name);
|
||||
auto &parser = parser_t::principal_parser();
|
||||
function_load(name, parser);
|
||||
|
||||
// It's important to NOT hold the lock around completion loading.
|
||||
// We need to take the lock to decide what to load, drop it to perform the load, then reacquire
|
||||
|
@ -867,7 +868,7 @@ static void complete_load(const wcstring &name, bool reload) {
|
|||
const environment_t &vars = parser_t::principal_parser().vars();
|
||||
maybe_t<wcstring> path_to_load = completion_autoloader.acquire()->resolve_command(name, vars);
|
||||
if (path_to_load) {
|
||||
autoload_t::perform_autoload(*path_to_load);
|
||||
autoload_t::perform_autoload(*path_to_load, parser);
|
||||
completion_autoloader.acquire()->mark_autoload_finished(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ bool function_set_t::allow_autoload(const wcstring &name) const {
|
|||
/// Make sure that if the specified function is a dynamically loaded function, it has been fully
|
||||
/// loaded.
|
||||
/// Note this executes fish script code.
|
||||
static void try_autoload(const wcstring &name) {
|
||||
static void try_autoload(const wcstring &name, parser_t &parser) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
maybe_t<wcstring> path_to_autoload;
|
||||
// Note we can't autoload while holding the funcset lock.
|
||||
|
@ -104,15 +104,14 @@ static void try_autoload(const wcstring &name) {
|
|||
{
|
||||
auto funcset = function_set.acquire();
|
||||
if (funcset->allow_autoload(name)) {
|
||||
const environment_t &vars = parser_t::principal_parser().vars();
|
||||
path_to_autoload = funcset->autoloader.resolve_command(name, vars);
|
||||
path_to_autoload = funcset->autoloader.resolve_command(name, parser.vars());
|
||||
}
|
||||
}
|
||||
|
||||
// Release the lock and perform any autoload, then reacquire the lock and clean up.
|
||||
if (path_to_autoload) {
|
||||
// Crucially, the lock is acquired *after* do_autoload_file_at_path().
|
||||
autoload_t::perform_autoload(*path_to_autoload);
|
||||
autoload_t::perform_autoload(*path_to_autoload, parser);
|
||||
function_set.acquire()->autoloader.mark_autoload_finished(name);
|
||||
}
|
||||
}
|
||||
|
@ -212,18 +211,18 @@ std::shared_ptr<const function_properties_t> function_get_properties(const wcstr
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int function_exists(const wcstring &cmd) {
|
||||
int function_exists(const wcstring &cmd, parser_t &parser) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
if (parser_keywords_is_reserved(cmd)) return 0;
|
||||
try_autoload(cmd);
|
||||
try_autoload(cmd, parser);
|
||||
auto funcset = function_set.acquire();
|
||||
return funcset->funcs.find(cmd) != funcset->funcs.end();
|
||||
}
|
||||
|
||||
void function_load(const wcstring &cmd) {
|
||||
void function_load(const wcstring &cmd, parser_t &parser) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
if (!parser_keywords_is_reserved(cmd)) {
|
||||
try_autoload(cmd);
|
||||
try_autoload(cmd, parser);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,9 +278,9 @@ bool function_get_desc(const wcstring &name, wcstring &out_desc) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void function_set_desc(const wcstring &name, const wcstring &desc) {
|
||||
void function_set_desc(const wcstring &name, const wcstring &desc, parser_t &parser) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
try_autoload(name);
|
||||
try_autoload(name, parser);
|
||||
auto funcset = function_set.acquire();
|
||||
auto iter = funcset->funcs.find(name);
|
||||
if (iter != funcset->funcs.end()) {
|
||||
|
|
|
@ -67,14 +67,14 @@ bool function_get_definition(const wcstring &name, wcstring &out_definition);
|
|||
bool function_get_desc(const wcstring &name, wcstring &out_desc);
|
||||
|
||||
/// Sets the description of the function with the name \c name.
|
||||
void function_set_desc(const wcstring &name, const wcstring &desc);
|
||||
void function_set_desc(const wcstring &name, const wcstring &desc, parser_t &parser);
|
||||
|
||||
/// Returns true if the function with the name name exists.
|
||||
/// This may autoload.
|
||||
int function_exists(const wcstring &name);
|
||||
int function_exists(const wcstring &name, parser_t &parser);
|
||||
|
||||
/// Attempts to load a function if not yet loaded. This is used by the completion machinery.
|
||||
void function_load(const wcstring &name);
|
||||
void function_load(const wcstring &name, parser_t &parser);
|
||||
|
||||
/// Returns true if the function with the name name exists, without triggering autoload.
|
||||
int function_exists_no_autoload(const wcstring &name, const environment_t &vars);
|
||||
|
|
|
@ -164,7 +164,7 @@ process_type_t parse_execution_context_t::process_type_for_command(
|
|||
process_type = process_type_t::builtin;
|
||||
break;
|
||||
case parse_statement_decoration_none:
|
||||
if (function_exists(cmd)) {
|
||||
if (function_exists(cmd, *parser)) {
|
||||
process_type = process_type_t::function;
|
||||
} else if (builtin_exists(cmd)) {
|
||||
process_type = process_type_t::builtin;
|
||||
|
@ -858,7 +858,8 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
|
|||
path_to_external_command.clear();
|
||||
|
||||
// If we have defined a wrapper around cd, use it, otherwise use the cd builtin.
|
||||
process_type = function_exists(L"cd") ? process_type_t::function : process_type_t::builtin;
|
||||
process_type =
|
||||
function_exists(L"cd", *parser) ? process_type_t::function : process_type_t::builtin;
|
||||
} else {
|
||||
// Not implicit cd.
|
||||
const globspec_t glob_behavior = (cmd == L"set" || cmd == L"count") ? nullglob : failglob;
|
||||
|
|
|
@ -874,11 +874,11 @@ bool reader_thread_job_is_stale() {
|
|||
return read_generation_count() != s_thread_generation;
|
||||
}
|
||||
|
||||
void reader_write_title(const wcstring &cmd, bool reset_cursor_position) {
|
||||
void reader_write_title(const wcstring &cmd, parser_t &parser, bool reset_cursor_position) {
|
||||
if (!term_supports_setting_title()) return;
|
||||
|
||||
wcstring fish_title_command = DEFAULT_TITLE;
|
||||
if (function_exists(L"fish_title")) {
|
||||
if (function_exists(L"fish_title", parser)) {
|
||||
fish_title_command = L"fish_title";
|
||||
if (!cmd.empty()) {
|
||||
fish_title_command.append(L" ");
|
||||
|
@ -889,8 +889,7 @@ 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, parser_t::principal_parser(), lst,
|
||||
false /* ignore exit status */) != -1 &&
|
||||
if (exec_subshell(fish_title_command, parser, lst, false /* ignore exit status */) != -1 &&
|
||||
!lst.empty()) {
|
||||
std::fputws(L"\x1B]0;", stdout);
|
||||
for (size_t i = 0; i < lst.size(); i++) {
|
||||
|
@ -909,7 +908,7 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) {
|
|||
|
||||
void reader_data_t::exec_mode_prompt() {
|
||||
mode_prompt_buff.clear();
|
||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME)) {
|
||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
||||
wcstring_list_t mode_indicator_list;
|
||||
exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list,
|
||||
false);
|
||||
|
@ -966,7 +965,7 @@ void reader_data_t::exec_prompt() {
|
|||
// Write the screen title. Do not reset the cursor position: exec_prompt is called when there
|
||||
// may still be output on the line from the previous command (#2499) and we need our PROMPT_SP
|
||||
// hack to work.
|
||||
reader_write_title(L"", false);
|
||||
reader_write_title(L"", parser(), false);
|
||||
}
|
||||
|
||||
void reader_init() {
|
||||
|
@ -1957,7 +1956,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
|||
if (!ft.empty()) parser.vars().set_one(L"_", ENV_GLOBAL, ft);
|
||||
|
||||
outputter_t &outp = outputter_t::stdoutput();
|
||||
reader_write_title(cmd);
|
||||
reader_write_title(cmd, parser);
|
||||
term_donate(outp);
|
||||
|
||||
gettimeofday(&time_before, NULL);
|
||||
|
@ -2278,15 +2277,15 @@ static int read_i() {
|
|||
event_fire_generic(L"fish_prompt");
|
||||
run_count++;
|
||||
|
||||
if (is_breakpoint && function_exists(DEBUG_PROMPT_FUNCTION_NAME)) {
|
||||
if (is_breakpoint && function_exists(DEBUG_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_left_prompt(DEBUG_PROMPT_FUNCTION_NAME);
|
||||
} else if (function_exists(LEFT_PROMPT_FUNCTION_NAME)) {
|
||||
} else if (function_exists(LEFT_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_left_prompt(LEFT_PROMPT_FUNCTION_NAME);
|
||||
} else {
|
||||
reader_set_left_prompt(DEFAULT_PROMPT);
|
||||
}
|
||||
|
||||
if (function_exists(RIGHT_PROMPT_FUNCTION_NAME)) {
|
||||
if (function_exists(RIGHT_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_right_prompt(RIGHT_PROMPT_FUNCTION_NAME);
|
||||
} else {
|
||||
reader_set_right_prompt(L"");
|
||||
|
@ -2500,7 +2499,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
// Repaint the mode-prompt only if it exists.
|
||||
// This is an optimization basically exclusively for vi-mode, since the prompt
|
||||
// may sometimes take a while but when switching the mode all we care about is the mode-prompt.
|
||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME)) {
|
||||
if (function_exists(MODE_PROMPT_FUNCTION_NAME, parser())) {
|
||||
exec_mode_prompt();
|
||||
s_reset(&screen, screen_reset_current_line_and_prompt);
|
||||
screen_reset_needed = false;
|
||||
|
|
|
@ -82,8 +82,9 @@ void reader_pop_current_filename();
|
|||
/// executing and just after it finishes.
|
||||
///
|
||||
/// \param cmd Command line string passed to \c fish_title if is defined.
|
||||
/// \param parser The parser to use for autoloading fish_title.
|
||||
/// \param reset_cursor_position If set, issue a \r so the line driver knows where we are
|
||||
void reader_write_title(const wcstring &cmd, bool reset_cursor_position = true);
|
||||
void reader_write_title(const wcstring &cmd, parser_t &parser, bool reset_cursor_position = true);
|
||||
|
||||
/// Call this function to tell the reader that a repaint is needed, and should be performed when
|
||||
/// possible.
|
||||
|
|
Loading…
Reference in a new issue