Eliminate the global list of scoped transient commandlines

Store this in a parser's libdata instead.
This commit is contained in:
ridiculousfish 2019-06-09 14:11:25 -07:00
parent 421cf92380
commit 1baa479bbf
5 changed files with 20 additions and 55 deletions

View file

@ -85,24 +85,6 @@ wcstring_list_t builtin_get_names();
void builtin_get_names(std::vector<completion_t> *list);
const wchar_t *builtin_get_desc(const wcstring &b);
/// Support for setting and removing transient command lines. This is used by
/// 'complete -C' in order to make the commandline builtin operate on the string
/// to complete instead of operating on whatever is to be completed. It's also
/// used by completion wrappers, to allow a command to appear as the command
/// being wrapped for the purposes of completion.
///
/// Instantiating an instance of builtin_commandline_scoped_transient_t pushes
/// the command as the new transient commandline. The destructor removes it. It
/// will assert if construction/destruction does not happen in a stack-like
/// (LIFO) order.
class builtin_commandline_scoped_transient_t {
size_t token;
public:
explicit builtin_commandline_scoped_transient_t(const wcstring &cmd);
~builtin_commandline_scoped_transient_t();
};
wcstring builtin_help_get(parser_t &parser, const wchar_t *cmd);
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,

View file

@ -12,6 +12,7 @@
#include "input.h"
#include "io.h"
#include "parse_util.h"
#include "parser.h"
#include "proc.h"
#include "reader.h"
#include "tokenizer.h"
@ -35,36 +36,6 @@ enum {
APPEND_MODE // insert at end of current token/command/buffer
};
static owning_lock<wcstring_list_t> &get_transient_stack() {
ASSERT_IS_MAIN_THREAD();
static owning_lock<wcstring_list_t> s_transient_stack;
return s_transient_stack;
}
static bool get_top_transient(wcstring *out_result) {
auto stack = get_transient_stack().acquire();
if (stack->empty()) {
return false;
}
out_result->assign(stack->back());
return true;
}
builtin_commandline_scoped_transient_t::builtin_commandline_scoped_transient_t(
const wcstring &cmd) {
ASSERT_IS_MAIN_THREAD();
auto stack = get_transient_stack().acquire();
stack->push_back(cmd);
this->token = stack->size();
}
builtin_commandline_scoped_transient_t::~builtin_commandline_scoped_transient_t() {
ASSERT_IS_MAIN_THREAD();
auto stack = get_transient_stack().acquire();
assert(this->token == stack->size());
stack->pop_back();
}
/// Replace/append/insert the selection with/at/after the specified string.
///
/// \param begin beginning of selection
@ -178,8 +149,10 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
int paging_mode = 0;
const wchar_t *begin = NULL, *end = NULL;
const auto &ld = parser.libdata();
wcstring transient_commandline;
if (get_top_transient(&transient_commandline)) {
if (!ld.transient_commandlines.empty()) {
transient_commandline = ld.transient_commandlines.back();
current_buffer = transient_commandline.c_str();
current_cursor_pos = transient_commandline.size();
} else {

View file

@ -329,9 +329,10 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0, 0,
0);
// Create a scoped transient command line, so that bulitin_commandline will see our
// Create a scoped transient command line, so that builtin_commandline will see our
// argument, not the reader buffer.
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
parser.libdata().transient_commandlines.push_back(do_complete_param);
cleanup_t remove_transient([&] { parser.libdata().transient_commandlines.pop_back(); });
if (parser.libdata().builtin_complete_recursion_level < 1) {
parser.libdata().builtin_complete_recursion_level++;

View file

@ -1557,15 +1557,19 @@ void completer_t::perform() {
// Perhaps set a transient commandline so that custom completions
// buitin_commandline will refer to the wrapped command. But not if
// we're doing autosuggestions.
std::unique_ptr<builtin_commandline_scoped_transient_t> bcst;
if (depth > 0 && !(flags & completion_request_t::autosuggestion)) {
bcst = make_unique<builtin_commandline_scoped_transient_t>(cmdline);
bool wants_transient =
depth > 0 && !(flags & completion_request_t::autosuggestion);
if (wants_transient) {
parser->libdata().transient_commandlines.push_back(cmdline);
}
// Now invoke any custom completions for this command.
if (!complete_param(cmd, previous_argument_unescape,
current_argument_unescape, !had_ddash)) {
do_file = false;
}
if (wants_transient) {
parser->libdata().transient_commandlines.pop_back();
}
};
walk_wrap_chain(cmd, *cmd_node.source_range(), receiver);
}

View file

@ -163,7 +163,12 @@ struct library_data_t {
const wchar_t *current_filename{};
/// List of events that have been sent but have not yet been delivered because they are blocked.
std::vector<shared_ptr<event_t>> blocked_events;
std::vector<shared_ptr<event_t>> blocked_events{};
/// A stack of fake values to be returned by builtin_commandline. This is used by the completion
/// machinery when wrapping: e.g. if `tig` wraps `git` then git completions need to see git on
/// the command line.
wcstring_list_t transient_commandlines{};
};
class parser_t : public std::enable_shared_from_this<parser_t> {