diff --git a/src/builtins/fg.cpp b/src/builtins/fg.cpp index 6e453633f..93397dc80 100644 --- a/src/builtins/fg.cpp +++ b/src/builtins/fg.cpp @@ -108,8 +108,12 @@ maybe_t builtin_fg(parser_t &parser, io_streams_t &streams, const wchar_t * } wcstring ft = tok_command(job->command()); - // For compatibility with fish 2.0's $_, now replaced with `status current-command` - if (!ft.empty()) parser.set_var_and_fire(L"_", ENV_EXPORT, std::move(ft)); + if (!ft.empty()) { + // Provide value for `status current-command` + parser.set_status_var(parser_status_var_t::current_command, ft); + // Also provide a value for the deprecated fish 2.0 $_ variable + parser.set_var_and_fire(L"_", ENV_EXPORT, std::move(ft)); + } reader_write_title(job->command(), parser); // Note if tty transfer fails, we still try running the job. diff --git a/src/builtins/status.cpp b/src/builtins/status.cpp index 8bc10e769..4058131be 100644 --- a/src/builtins/status.cpp +++ b/src/builtins/status.cpp @@ -449,10 +449,9 @@ maybe_t builtin_status(parser_t &parser, io_streams_t &streams, const wchar } case STATUS_CURRENT_CMD: { CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd) - // HACK: Go via the deprecated variable to get the command. - const auto var = parser.vars().get(L"_"); - if (!var.missing_or_empty()) { - streams.out.append(var->as_string()); + const auto &var = parser.get_status_var(parser_status_var_t::current_command); + if (!var.empty()) { + streams.out.append(var); streams.out.push_back(L'\n'); } else { streams.out.append(program_name); diff --git a/src/parser.h b/src/parser.h index 0a3acacd2..82a66cab3 100644 --- a/src/parser.h +++ b/src/parser.h @@ -244,6 +244,11 @@ struct eval_res_t { : status(status), break_expand(break_expand), was_empty(was_empty), no_status(no_status) {} }; +enum class parser_status_var_t : uint8_t { + current_command, + count_, +}; + class parser_t : public std::enable_shared_from_this { friend class parse_execution_context_t; @@ -264,6 +269,9 @@ class parser_t : public std::enable_shared_from_this { /// top down using range-based for loops. std::deque block_list; + /// Variables set by the single-threaded parser or reader and queryable by any consumer. + std::array status_vars_; + /// The 'depth' of the fish call stack. int eval_level = -1; @@ -389,6 +397,17 @@ class parser_t : public std::enable_shared_from_this { statuses_t get_last_statuses() const { return vars().get_last_statuses(); } void set_last_statuses(statuses_t s) { vars().set_last_statuses(std::move(s)); } + /// Get a parser status variable + const wcstring& get_status_var(parser_status_var_t var) const { + return status_vars_.at((int) var); + } + + /// Set a parser status variable + void set_status_var(parser_status_var_t var, wcstring val) { + ASSERT_IS_MAIN_THREAD(); + status_vars_[(int) var] = std::move(val); + } + /// Cover of vars().set(), which also fires any returned event handlers. /// \return a value like ENV_OK. int set_var_and_fire(const wcstring &key, env_mode_flags_t mode, wcstring val); diff --git a/src/reader.cpp b/src/reader.cpp index 43132abee..521dbb0f9 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -2494,7 +2494,9 @@ static void reader_interactive_init(parser_t &parser) { termsize_container_t::shared().invalidate_tty(); - // For compatibility with fish 2.0's $_, now replaced with `status current-command` + // Provide value for `status current-command` + parser.set_status_var(parser_status_var_t::current_command, L"fish"); + // Also provide a value for the deprecated fish 2.0 $_ variable parser.vars().set_one(L"_", ENV_GLOBAL, L"fish"); } @@ -2628,8 +2630,12 @@ void reader_data_t::set_buffer_maintaining_pager(const wcstring &b, size_t pos, static eval_res_t reader_run_command(parser_t &parser, const wcstring &cmd) { wcstring ft = tok_command(cmd); - // For compatibility with fish 2.0's $_, now replaced with `status current-command` - if (!ft.empty()) parser.vars().set_one(L"_", ENV_GLOBAL, ft); + // Provide values for `status current-command` and `status current-commandline` + if (!ft.empty()) { + parser.set_status_var(parser_status_var_t::current_command, ft); + // Also provide a value for the deprecated fish 2.0 $_ variable + parser.vars().set_one(L"_", ENV_GLOBAL, ft); + } outputter_t &outp = outputter_t::stdoutput(); reader_write_title(cmd, parser); @@ -2651,7 +2657,9 @@ static eval_res_t reader_run_command(parser_t &parser, const wcstring &cmd) { term_steal(); - // For compatibility with fish 2.0's $_, now replaced with `status current-command` + // Provide value for `status current-command` + parser.set_status_var(parser_status_var_t::current_command, program_name); + // Also provide a value for the deprecated fish 2.0 $_ variable parser.vars().set_one(L"_", ENV_GLOBAL, program_name); if (have_proc_stat()) {