diff --git a/src/autoload.cpp b/src/autoload.cpp index bf6828232..6a750cfd3 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -190,8 +190,7 @@ maybe_t 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 */); } diff --git a/src/autoload.h b/src/autoload.h index 2daed1a45..d59486364 100644 --- a/src/autoload.h +++ b/src/autoload.h @@ -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) { diff --git a/src/builtin_fg.cpp b/src/builtin_fg.cpp index 7ce712bd7..7a27f254c 100644 --- a/src/builtin_fg.cpp +++ b/src/builtin_fg.cpp @@ -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); diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index 91b334e6e..16a22128d 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -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)); } } diff --git a/src/complete.cpp b/src/complete.cpp index d7bb22017..95dffdc9d 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -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 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); } } diff --git a/src/function.cpp b/src/function.cpp index 75cd7b802..a158027af 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -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 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 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()) { diff --git a/src/function.h b/src/function.h index 89179d46f..ad9aee778 100644 --- a/src/function.h +++ b/src/function.h @@ -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); diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 5ec8152e1..5755a63cb 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -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; diff --git a/src/reader.cpp b/src/reader.cpp index 473cbac54..3426171d6 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -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; diff --git a/src/reader.h b/src/reader.h index a6c1bbffb..4be1328a0 100644 --- a/src/reader.h +++ b/src/reader.h @@ -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.