From d5f2d472d0e5b119d0e9366c758e019901e5007b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 26 May 2019 18:51:26 -0700 Subject: [PATCH] Thread a parser into reader Eliminates uses of principal_parser --- src/builtin.cpp | 2 +- src/builtin_read.cpp | 2 +- src/builtin_source.cpp | 2 +- src/fish.cpp | 4 +-- src/reader.cpp | 68 +++++++++++++++++++++--------------------- src/reader.h | 12 ++++---- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index a017ed264..9aef6e344 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -316,7 +316,7 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t * } const block_t *bpb = parser.push_block(block_t::breakpoint_block()); - reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); + reader_read(parser, STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(bpb); return parser.get_last_status(); } diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index 7210a983e..913293a15 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -205,7 +205,7 @@ static int read_interactive(parser_t &parser, wcstring &buff, int nchars, bool s const auto &vars = parser.vars(); wcstring read_history_ID = history_session_id(vars); if (!read_history_ID.empty()) read_history_ID += L"_read"; - reader_push(read_history_ID); + reader_push(parser, read_history_ID); reader_set_left_prompt(prompt); reader_set_right_prompt(right_prompt); diff --git a/src/builtin_source.cpp b/src/builtin_source.cpp index 5bdc7c4b2..8f4b4f14b 100644 --- a/src/builtin_source.cpp +++ b/src/builtin_source.cpp @@ -83,7 +83,7 @@ int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { null_terminated_array_t::to_list(argv + optind + (argc == optind ? 0 : 1)); parser.vars().set_argv(std::move(argv_list)); - retval = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); + retval = reader_read(parser, fd, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(sb); diff --git a/src/fish.cpp b/src/fish.cpp index 389dfc4d2..2ea6db5ac 100644 --- a/src/fish.cpp +++ b/src/fish.cpp @@ -451,7 +451,7 @@ int main(int argc, char **argv) { reader_set_end_loop(false); } else if (my_optind == argc) { // Implicitly interactive mode. - res = reader_read(STDIN_FILENO, {}); + res = reader_read(parser, STDIN_FILENO, {}); } else { char *file = *(argv + (my_optind++)); int fd = open(file, O_RDONLY); @@ -471,7 +471,7 @@ int main(int argc, char **argv) { wcstring rel_filename = str2wcstring(file); scoped_push filename_push{&ld.current_filename, intern(rel_filename.c_str())}; - res = reader_read(fd, {}); + res = reader_read(parser, fd, {}); if (res) { debug(1, _(L"Error while reading file %ls\n"), ld.current_filename ? ld.current_filename : _(L"Standard input")); diff --git a/src/reader.cpp b/src/reader.cpp index bdefa3e6e..0a94bc8d0 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -148,7 +148,7 @@ namespace { /// Test if the given string contains error. Since this is the error detection for general purpose, /// there are no invalid strings, so this function always returns false. -parser_test_error_bits_t default_test(const wcstring &b) { +parser_test_error_bits_t default_test(parser_t &parser, const wcstring &b) { UNUSED(b); return 0; } @@ -323,6 +323,8 @@ struct readline_loop_state_t; /// reader_readline() calls are nested. This happens when the 'read' builtin is used. class reader_data_t : public std::enable_shared_from_this { public: + /// The parser being used. + std::shared_ptr parser_ref; /// String containing the whole current commandline. editable_line_t command_line; /// String containing the autosuggestion. @@ -420,14 +422,14 @@ class reader_data_t : public std::enable_shared_from_this { void repaint_if_needed(); /// Return the variable set used for e.g. command duration. - env_stack_t &vars() { return parser_t::principal_parser().vars(); } + env_stack_t &vars() { return parser_ref->vars(); } + const env_stack_t &vars() const { return parser_ref->vars(); } - /// Hackish access to the parser. TODO: rationalize this. - parser_t &parser() { return parser_t::principal_parser(); } + /// Access the parser. + parser_t &parser() { return *parser_ref; } - const env_stack_t &vars() const { return parser_t::principal_parser().vars(); } - - reader_data_t(history_t *hist) : history(hist) {} + reader_data_t(std::shared_ptr parser, history_t *hist) + : parser_ref(std::move(parser)), history(hist) {} void update_buff_pos(editable_line_t *el, size_t buff_pos); void repaint(); @@ -1238,9 +1240,9 @@ void reader_data_t::completion_insert(const wchar_t *val, complete_flags_t flags // Returns a function that can be invoked (potentially // on a background thread) to determine the autosuggestion static std::function get_autosuggestion_performer( - const wcstring &search_string, size_t cursor_pos, history_t *history) { + parser_t &parser, const wcstring &search_string, size_t cursor_pos, history_t *history) { const unsigned int generation_count = read_generation_count(); - auto vars = parser_t::principal_parser().vars().snapshot(); + auto vars = parser.vars().snapshot(); const wcstring working_directory = vars->get_pwd_slash(); // TODO: suspicious use of 'history' here // This is safe because histories are immortal, but perhaps @@ -1331,7 +1333,7 @@ void reader_data_t::update_autosuggestion() { autosuggestion.clear(); if (can_autosuggest()) { const editable_line_t *el = active_edit_line(); - auto performer = get_autosuggestion_performer(el->text, el->position, history); + auto performer = get_autosuggestion_performer(parser(), el->text, el->position, history); auto shared_this = this->shared_from_this(); iothread_perform(performer, [shared_this](autosuggestion_result_t result) { shared_this->autosuggest_completed(std::move(result)); @@ -1943,7 +1945,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) { } } -parser_test_error_bits_t reader_shell_test(const wcstring &b) { +parser_test_error_bits_t reader_shell_test(parser_t &parser, const wcstring &b) { wcstring bstr = b; // Append a newline, to act as a statement terminator. @@ -1955,7 +1957,7 @@ parser_test_error_bits_t reader_shell_test(const wcstring &b) { if (res & PARSER_TEST_ERROR) { wcstring error_desc; - parser_t::principal_parser().get_backtrace(bstr, errors, error_desc); + parser.get_backtrace(bstr, errors, error_desc); // Ensure we end with a newline. Also add an initial newline, because it's likely the user // just hit enter and so there's junk on the current line. @@ -2001,8 +2003,9 @@ void reader_data_t::highlight_complete(highlight_result_t result) { // Given text, bracket matching position, and whether IO is allowed, // return a function that performs highlighting. The function may be invoked on a background thread. static std::function get_highlight_performer( - const wcstring &text, long match_highlight_pos, highlight_function_t highlight_func) { - auto vars = parser_t::principal_parser().vars().snapshot(); + parser_t &parser, const wcstring &text, long match_highlight_pos, + highlight_function_t highlight_func) { + auto vars = parser.vars().snapshot(); unsigned int generation_count = read_generation_count(); return [=]() -> highlight_result_t { if (text.empty()) return {}; @@ -2034,7 +2037,7 @@ void reader_data_t::super_highlight_me_plenty(int match_highlight_pos_adjust, bo sanity_check(); auto highlight_performer = get_highlight_performer( - el->text, match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func); + parser(), el->text, match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func); if (no_io) { // Highlighting without IO, we just do it. highlight_complete(highlight_performer()); @@ -2083,9 +2086,9 @@ void reader_change_history(const wcstring &name) { } } -void reader_push(const wcstring &name) { +void reader_push(parser_t &parser, const wcstring &name) { history_t *hist = &history_t::history_with_name(name); - reader_data_stack.push_back(std::make_shared(hist)); + reader_data_stack.push_back(std::make_shared(parser.shared(), hist)); reader_data_t *data = current_data(); data->command_line_changed(&data->command_line); if (reader_data_stack.size() == 1) { @@ -2222,9 +2225,8 @@ static relaxed_atomic_t run_count{0}; uint64_t reader_run_count() { return run_count; } /// Read interactively. Read input from stdin while providing editing facilities. -static int read_i() { - parser_t &parser = parser_t::principal_parser(); - reader_push(history_session_id(parser.vars())); +static int read_i(parser_t &parser) { + reader_push(parser, history_session_id(parser.vars())); reader_set_complete_function(&complete); reader_set_highlight_function(&highlight_shell); reader_set_test_function(&reader_shell_test); @@ -2413,7 +2415,7 @@ maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rl /// Handle a readline command \p c, updating the state \p rls. void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_state_t &rls) { - const auto &vars = parser_t::principal_parser().vars(); + const auto &vars = this->vars(); using rl = readline_cmd_t; switch (c) { // Go to beginning of line. @@ -2460,10 +2462,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // may sometimes take a while but when switching the mode all we care about is the // mode-prompt. // - // Because some users set `fish_mode_prompt` to an empty function and display the mode elsewhere, - // we detect if the mode output is empty. + // Because some users set `fish_mode_prompt` to an empty function and display the mode + // elsewhere, we detect if the mode output is empty. exec_mode_prompt(); - if(!mode_prompt_buff.empty()) { + if (!mode_prompt_buff.empty()) { s_reset(&screen, screen_reset_current_line_and_prompt); screen_reset_needed = false; repaint(); @@ -2547,9 +2549,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str()); completion_request_flags_t complete_flags = {completion_request_t::descriptions, completion_request_t::fuzzy_match}; - // TODO: eliminate this principal_parser. - complete_func(buffcpy, &rls.comp, complete_flags, vars, - parser_t::principal_parser().shared()); + complete_func(buffcpy, &rls.comp, complete_flags, vars, parser_ref); // Munge our completions. completions_sort_and_prioritize(&rls.comp); @@ -2725,7 +2725,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } // See if this command is valid. - int command_test_result = test_func(el->text); + int command_test_result = test_func(parser(), el->text); if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) { // This command is valid, but an abbreviation may make it invalid. If so, we // will have to test again. @@ -2733,7 +2733,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat if (abbreviation_expanded) { // It's our reponsibility to rehighlight and repaint. But everything we do // below triggers a repaint. - command_test_result = test_func(el->text.c_str()); + command_test_result = test_func(parser(), el->text.c_str()); // If the command is OK, then we're going to execute it. We still want to do // syntax highlighting, but a synchronous variant that performs no I/O, so @@ -3257,7 +3257,8 @@ maybe_t reader_data_t::readline(int nchars_or_0) { handle_readline_command(readline_cmd, rls); if (command_ends_history_search(readline_cmd)) { - // "cancel" means to abort the whole thing, other ending commands mean to finish the search. + // "cancel" means to abort the whole thing, other ending commands mean to finish the + // search. if (history_search.active() && readline_cmd == rl::cancel) { history_search.go_to_end(); update_command_line_from_history_search(); @@ -3449,8 +3450,7 @@ bool reader_get_selection(size_t *start, size_t *len) { /// Read non-interactively. Read input from stdin without displaying the prompt, using syntax /// highlighting. This is used for reading scripts and init files. -static int read_ni(int fd, const io_chain_t &io) { - parser_t &parser = parser_t::principal_parser(); +static int read_ni(parser_t &parser, int fd, const io_chain_t &io) { FILE *in_stream; wchar_t *buff = 0; std::vector acc; @@ -3524,7 +3524,7 @@ static int read_ni(int fd, const io_chain_t &io) { return res; } -int reader_read(int fd, const io_chain_t &io) { +int reader_read(parser_t &parser, int fd, const io_chain_t &io) { int res; // If reader_read is called recursively through the '.' builtin, we need to preserve @@ -3546,7 +3546,7 @@ int reader_read(int fd, const io_chain_t &io) { } proc_push_interactive(inter); - res = shell_is_interactive() ? read_i() : read_ni(fd, io); + res = shell_is_interactive() ? read_i(parser) : read_ni(parser, fd, io); // If the exit command was called in a script, only exit the script, not the program. reader_set_end_loop(false); diff --git a/src/reader.h b/src/reader.h index 45c3431ea..21a0f216d 100644 --- a/src/reader.h +++ b/src/reader.h @@ -47,7 +47,7 @@ class editable_line_t { }; /// Read commands from \c fd until encountering EOF. -int reader_read(int fd, const io_chain_t &io); +int reader_read(parser_t &parser, int fd, const io_chain_t &io); /// Tell the shell whether it should exit after the currently running command finishes. void reader_set_end_loop(bool flag); @@ -140,7 +140,7 @@ bool reader_thread_job_is_stale(); maybe_t reader_readline(int nchars); /// Push a new reader environment. -void reader_push(const wcstring &name); +void reader_push(parser_t &parser, const wcstring &name); /// Return to previous reader environment. void reader_pop(); @@ -152,11 +152,11 @@ typedef void (*complete_function_t)(const wcstring &, std::vector void reader_set_complete_function(complete_function_t); /// The type of a highlight function. -typedef void (*highlight_function_t)(const wcstring &, std::vector &, size_t, - wcstring_list_t *, const environment_t &vars); +using highlight_function_t = void (*)(const wcstring &, std::vector &, size_t, + wcstring_list_t *, const environment_t &vars); /// Function type for testing if a string is valid for the reader to return. -using test_function_t = parser_test_error_bits_t (*)(const wcstring &); +using test_function_t = parser_test_error_bits_t (*)(parser_t &, const wcstring &); /// Specify function for syntax highlighting. The function must take these arguments: /// @@ -198,7 +198,7 @@ bool reader_exit_forced(); /// Test if the given shell command contains errors. Uses parser_test for testing. Suitable for /// reader_set_test_function(). -parser_test_error_bits_t reader_shell_test(const wcstring &); +parser_test_error_bits_t reader_shell_test(parser_t &parser, const wcstring &); /// Test whether the interactive reader is in search mode. bool reader_is_in_search_mode();