From a48dbf23b8c4e2a579e871784857fad461e882bd Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 2 Jun 2019 15:41:23 -0700 Subject: [PATCH] Instantize the character event queue Wrap this stuff up in structs so it's no longer global. --- src/builtin_commandline.cpp | 5 +-- src/fish_key_reader.cpp | 3 +- src/fish_tests.cpp | 5 ++- src/input.cpp | 90 ++++++++++++++++++------------------- src/input.h | 61 +++++++++++++++++-------- src/input_common.cpp | 72 ++++++++++++----------------- src/input_common.h | 49 +++++++++++++------- src/reader.cpp | 26 +++++++---- src/reader.h | 4 ++ 9 files changed, 177 insertions(+), 138 deletions(-) diff --git a/src/builtin_commandline.cpp b/src/builtin_commandline.cpp index b8ab7e82b..a84c53be1 100644 --- a/src/builtin_commandline.cpp +++ b/src/builtin_commandline.cpp @@ -326,9 +326,8 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) for (i = w.woptind; i < argc; i++) { if (auto mc = input_function_get_code(argv[i])) { - // input_unreadch inserts the specified keypress or readline function at the back of - // the queue of unused keypresses. - input_queue_ch(*mc); + // Inserts the readline function at the back of the queue. + reader_queue_ch(*mc); } else { streams.err.append_format(_(L"%ls: Unknown input function '%ls'"), cmd, argv[i]); builtin_print_error_trailer(parser, streams.err, cmd); diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp index 4f802eb69..d949bc8af 100644 --- a/src/fish_key_reader.cpp +++ b/src/fish_key_reader.cpp @@ -201,6 +201,7 @@ static double output_elapsed_time(double prev_tstamp, bool first_char_seen) { static void process_input(bool continuous_mode) { bool first_char_seen = false; double prev_tstamp = 0.0; + input_event_queue_t queue; std::vector bind_chars; std::fwprintf(stderr, L"Press a key\n\n"); @@ -209,7 +210,7 @@ static void process_input(bool continuous_mode) { if (reader_test_and_clear_interrupted()) { evt = char_event_t{shell_modes.c_cc[VINTR]}; } else { - evt = input_common_readch_timed(true); + evt = queue.readch_timed(true); } if (!evt.is_char()) { output_bind_command(bind_chars); diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 546772f8b..5153a0fa6 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -3003,6 +3003,7 @@ static bool history_contains(const std::unique_ptr &history, const wc static void test_input() { say(L"Testing input"); + inputter_t input{}; // Ensure sequences are order independent. Here we add two bindings where the first is a prefix // of the second, and then emit the second key list. The second binding should be invoked, not // the first! @@ -3013,11 +3014,11 @@ static void test_input() { // Push the desired binding to the queue. for (size_t idx = 0; idx < desired_binding.size(); idx++) { - input_queue_ch(desired_binding.at(idx)); + input.queue_ch(desired_binding.at(idx)); } // Now test. - auto evt = input_readch(); + auto evt = input.readch(); if (!evt.is_readline()) { err(L"Event is not a readline"); } else if (evt.get_readline() != readline_cmd_t::down_line) { diff --git a/src/input.cpp b/src/input.cpp index cb151ce7b..878ae2c4e 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -160,10 +160,6 @@ static latch_t> s_terminfo_mappings; /// \return the input terminfo. static std::vector create_input_terminfo(); -static wchar_t input_function_args[MAX_INPUT_FUNCTION_ARGS]; -static bool input_function_status; -static int input_function_args_index = 0; - /// Return the current bind mode. wcstring input_get_bind_mode(const environment_t &vars) { auto mode = vars.get(FISH_BIND_MODE_VAR); @@ -195,9 +191,6 @@ static int input_function_arity(readline_cmd_t function) { } } -/// Sets the return status of the most recently executed input function. -void input_function_set_status(bool status) { input_function_status = status; } - /// Helper function to compare the lengths of sequences. static bool length_is_greater_than(const input_mapping_t &m1, const input_mapping_t &m2) { return m1.seq.size() > m2.seq.size(); @@ -294,13 +287,16 @@ void init_input() { } } -void input_function_push_arg(wchar_t arg) { - input_function_args[input_function_args_index++] = arg; +void inputter_t::function_push_arg(wchar_t arg) { input_function_args_.push_back(arg); } + +wchar_t inputter_t::function_pop_arg() { + assert(!input_function_args_.empty() && "function_pop_arg underflow"); + auto result = input_function_args_.back(); + input_function_args_.pop_back(); + return result; } -wchar_t input_function_pop_arg() { return input_function_args[--input_function_args_index]; } - -void input_function_push_args(readline_cmd_t code) { +void inputter_t::function_push_args(readline_cmd_t code) { int arity = input_function_arity(code); std::vector skipped; @@ -308,26 +304,26 @@ void input_function_push_args(readline_cmd_t code) { // Skip and queue up any function codes. See issue #2357. wchar_t arg{}; for (;;) { - auto evt = input_common_readch(); + auto evt = event_queue_.readch(); if (evt.is_char()) { arg = evt.get_char(); break; } skipped.push_back(evt); } - input_function_push_arg(arg); + function_push_arg(arg); } // Push the function codes back into the input stream. size_t idx = skipped.size(); while (idx--) { - input_common_next_ch(skipped.at(idx)); + event_queue_.push_front(skipped.at(idx)); } } /// Perform the action of the specified binding. allow_commands controls whether fish commands /// should be executed, or should be deferred until later. -static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) { +void inputter_t::mapping_execute(const input_mapping_t &m, bool allow_commands) { // has_functions: there are functions that need to be put on the input queue // has_commands: there are shell commands that need to be evaluated bool has_commands = false, has_functions = false; @@ -349,9 +345,9 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) // We don't want to run commands yet. Put the characters back and return check_exit. for (wcstring::const_reverse_iterator it = m.seq.rbegin(), end = m.seq.rend(); it != end; ++it) { - input_common_next_ch(*it); + event_queue_.push_front(*it); } - input_common_next_ch(char_event_type_t::check_exit); + event_queue_.push_front(char_event_type_t::check_exit); return; // skip the input_set_bind_mode } else if (has_functions && !has_commands) { // Functions are added at the head of the input queue. @@ -359,8 +355,8 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) end = m.commands.rend(); it != end; ++it) { readline_cmd_t code = input_function_get_code(*it).value(); - input_function_push_args(code); - input_common_next_ch(code); + function_push_args(code); + event_queue_.push_front(code); } } else if (has_commands && !has_functions) { // Execute all commands. @@ -373,11 +369,11 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) parser.eval(cmd, io_chain_t(), TOP); } parser.set_last_statuses(std::move(last_statuses)); - input_common_next_ch(char_event_type_t::check_exit); + event_queue_.push_front(char_event_type_t::check_exit); } else { // Invalid binding, mixed commands and functions. We would need to execute these one by // one. - input_common_next_ch(char_event_type_t::check_exit); + event_queue_.push_front(char_event_type_t::check_exit); } // Empty bind mode indicates to not reset the mode (#2871) @@ -385,20 +381,20 @@ static void input_mapping_execute(const input_mapping_t &m, bool allow_commands) } /// Try reading the specified function mapping. -static bool input_mapping_is_match(const input_mapping_t &m) { +bool inputter_t::mapping_is_match(const input_mapping_t &m) { const wcstring &str = m.seq; assert(str.size() > 0 && "zero-length input string passed to input_mapping_is_match!"); bool timed = false; for (size_t i = 0; i < str.size(); ++i) { - auto evt = timed ? input_common_readch_timed() : input_common_readch(); + auto evt = timed ? event_queue_.readch_timed() : event_queue_.readch(); if (!evt.is_char() || evt.get_char() != str[i]) { // We didn't match the bind sequence/input mapping, (it timed out or they entered // something else) Undo consumption of the read characters since we didn't match the // bind sequence and abort. - input_common_next_ch(evt); - while (i--) input_common_next_ch(str[i]); + event_queue_.push_front(evt); + while (i--) event_queue_.push_front(str[i]); return false; } @@ -410,11 +406,13 @@ static bool input_mapping_is_match(const input_mapping_t &m) { return true; } -void input_queue_ch(char_event_t ch) { input_common_queue_ch(ch); } +void inputter_t::queue_ch(char_event_t ch) { event_queue_.push_back(ch); } + +void inputter_t::push_front(char_event_t ch) { event_queue_.push_front(ch); } /// \return the first mapping that matches, walking first over the user's mapping list, then the /// preset list. \return null if nothing matches. -static const input_mapping_t *find_mapping() { +const input_mapping_t *inputter_t::find_mapping() { const input_mapping_t *generic = NULL; const auto &vars = parser_t::principal_parser().vars(); const wcstring bind_mode = input_get_bind_mode(vars); @@ -429,7 +427,7 @@ static const input_mapping_t *find_mapping() { if (m.is_generic()) { if (!generic) generic = &m; - } else if (input_mapping_is_match(m)) { + } else if (mapping_is_match(m)) { return &m; } } @@ -437,26 +435,26 @@ static const input_mapping_t *find_mapping() { return generic; } -static void input_mapping_execute_matching_or_generic(bool allow_commands) { +void inputter_t::mapping_execute_matching_or_generic(bool allow_commands) { const input_mapping_t *mapping = find_mapping(); if (mapping) { - input_mapping_execute(*mapping, allow_commands); + mapping_execute(*mapping, allow_commands); } else { debug(2, L"no generic found, ignoring char..."); - auto evt = input_common_readch(); + auto evt = event_queue_.readch(); if (evt.is_eof()) { - input_common_next_ch(evt); + event_queue_.push_front(evt); } } } /// Helper function. Picks through the queue of incoming characters until we get to one that's not a /// readline function. -static char_event_t input_read_characters_no_readline() { +char_event_t inputter_t::read_characters_no_readline() { std::vector saved_events; char_event_t evt_to_return{0}; for (;;) { - auto evt = input_common_readch(); + auto evt = event_queue_.readch(); if (evt.is_readline()) { saved_events.push_back(evt); } else { @@ -466,34 +464,34 @@ static char_event_t input_read_characters_no_readline() { } // Restore any readline functions, in reverse to preserve their original order. for (auto iter = saved_events.rbegin(); iter != saved_events.rend(); ++iter) { - input_common_next_ch(*iter); + event_queue_.push_front(*iter); } return evt_to_return; } -char_event_t input_readch(bool allow_commands) { +char_event_t inputter_t::readch(bool allow_commands) { // Clear the interrupted flag. reader_reset_interrupted(); // Search for sequence in mapping tables. while (true) { - auto evt = input_common_readch(); + auto evt = event_queue_.readch(); if (evt.is_readline()) { switch (evt.get_readline()) { case readline_cmd_t::self_insert: { // Issue #1595: ensure we only insert characters, not readline functions. The // common case is that this will be empty. - return input_read_characters_no_readline(); + return read_characters_no_readline(); } case readline_cmd_t::func_and: { - if (input_function_status) { - return input_readch(); + if (function_status_) { + return readch(); } do { - evt = input_common_readch(); + evt = event_queue_.readch(); } while (evt.is_readline()); - input_common_next_ch(evt); - return input_readch(); + event_queue_.push_front(evt); + return readch(); } default: { return evt; @@ -504,8 +502,8 @@ char_event_t input_readch(bool allow_commands) { // There's no need to go through the input functions. return evt; } else { - input_common_next_ch(evt); - input_mapping_execute_matching_or_generic(allow_commands); + event_queue_.push_front(evt); + mapping_execute_matching_or_generic(allow_commands); // Regarding allow_commands, we're in a loop, but if a fish command is executed, // check_exit is unread, so the next pass through the loop we'll break out and return // it. diff --git a/src/input.h b/src/input.h index 08b271ad4..7168e2771 100644 --- a/src/input.h +++ b/src/input.h @@ -21,23 +21,50 @@ wcstring describe_char(wint_t c); /// initializations for our input subsystem. void init_input(); -/// Read a character from fd 0. Try to convert some escape sequences into character constants, but -/// do not permanently block the escape character. -/// -/// This is performed in the same way vim does it, i.e. if an escape character is read, wait for -/// more input for a short time (a few milliseconds). If more input is avaialable, it is assumed to -/// be an escape sequence for a special character (such as an arrow key), and readch attempts to -/// parse it. If no more input follows after the escape key, it is assumed to be an actual escape -/// key press, and is returned as such. -/// -/// The argument determines whether fish commands are allowed to be run as bindings. If false, when -/// a character is encountered that would invoke a fish command, it is unread and -/// char_event_type_t::check_exit is returned. -char_event_t input_readch(bool allow_commands = true); +struct input_mapping_t; +class inputter_t { + input_event_queue_t event_queue_{}; + std::vector input_function_args_{}; + bool function_status_{false}; -/// Enqueue a character or a readline function to the queue of unread characters that input_readch -/// will return before actually reading from fd 0. -void input_queue_ch(char_event_t ch); + void function_push_arg(wchar_t arg); + void function_push_args(readline_cmd_t code); + void mapping_execute(const input_mapping_t &m, bool allow_commands); + void mapping_execute_matching_or_generic(bool allow_commands); + bool mapping_is_match(const input_mapping_t &m); + const input_mapping_t *find_mapping(); + char_event_t read_characters_no_readline(); + + public: + inputter_t() = default; + + /// Read a character from fd 0. Try to convert some escape sequences into character constants, + /// but do not permanently block the escape character. + /// + /// This is performed in the same way vim does it, i.e. if an escape character is read, wait for + /// more input for a short time (a few milliseconds). If more input is avaialable, it is assumed + /// to be an escape sequence for a special character (such as an arrow key), and readch attempts + /// to parse it. If no more input follows after the escape key, it is assumed to be an actual + /// escape key press, and is returned as such. + /// + /// The argument determines whether fish commands are allowed to be run as bindings. If false, + /// when a character is encountered that would invoke a fish command, it is unread and + /// char_event_type_t::check_exit is returned. + char_event_t readch(bool allow_commands = true); + + /// Enqueue a char event to the queue of unread characters that input_readch will return before + /// actually reading from fd 0. + void queue_ch(char_event_t ch); + + /// Enqueue a char event to the front of the queue; this will be the next event returned. + void push_front(char_event_t ch); + + /// Sets the return status of the most recently executed input function. + void function_set_status(bool status) { function_status_ = status; } + + /// Pop an argument from the function argument stack. + wchar_t function_pop_arg(); +}; /// Add a key mapping from the specified sequence to the specified command. /// @@ -77,8 +104,6 @@ wcstring input_get_bind_mode(const environment_t &vars); /// Set the current bind mode. void input_set_bind_mode(const wcstring &bind_mode); -wchar_t input_function_pop_arg(); - /// Sets the return status of the most recently executed input function. void input_function_set_status(bool status); diff --git a/src/input_common.cpp b/src/input_common.cpp index fb82b1842..c9457fe9a 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -34,36 +34,6 @@ #define WAIT_ON_ESCAPE_DEFAULT 30 static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT; -struct input_lookahead_t { - /// Events which have been read and returned by the sequence matching code. - std::deque lookahead_list; - - bool has_lookahead() const { return !lookahead_list.empty(); } - - char_event_t pop() { - auto result = lookahead_list.front(); - lookahead_list.pop_front(); - return result; - } - - /// \return the next lookahead char, or none if none. Discards timeouts. - maybe_t pop_evt() { - while (has_lookahead()) { - auto evt = pop(); - if (!evt.is_timeout()) { - return evt; - } - } - return none(); - } - - void push_back(char_event_t c) { lookahead_list.push_back(c); } - - void push_front(char_event_t c) { lookahead_list.push_front(c); } -}; - -static mainthread_t s_lookahead; - /// Callback function for handling interrupts on reading. static interrupt_func_t interrupt_handler; @@ -71,7 +41,7 @@ void input_common_init(interrupt_func_t func) { interrupt_handler = func; } /// Internal function used by input_common_readch to read one byte from fd 0. This function should /// only be called by input_common_readch(). -static char_event_t readb() { +char_event_t input_event_queue_t::readb() { for (;;) { fd_set fdset; int fd_max = 0; @@ -110,7 +80,7 @@ static char_event_t readb() { if (interrupt_handler) { if (auto interrupt_evt = interrupt_handler()) { return *interrupt_evt; - } else if (auto mc = s_lookahead->pop_evt()) { + } else if (auto mc = pop_discard_timeouts()) { return *mc; } } @@ -128,7 +98,7 @@ static char_event_t readb() { if (barrier_from_poll || barrier_from_readability) { if (env_universal_barrier()) { // A variable change may have triggered a repaint, etc. - if (auto mc = s_lookahead->pop_evt()) { + if (auto mc = pop_discard_timeouts()) { return *mc; } } @@ -136,7 +106,7 @@ static char_event_t readb() { if (ioport > 0 && FD_ISSET(ioport, &fdset)) { iothread_service_completion(); - if (auto mc = s_lookahead->pop_evt()) { + if (auto mc = pop_discard_timeouts()) { return *mc; } } @@ -175,9 +145,25 @@ void update_wait_on_escape_ms(const environment_t &vars) { } } -char_event_t input_common_readch() { +char_event_t input_event_queue_t::pop() { + auto result = queue_.front(); + queue_.pop_front(); + return result; +} + +maybe_t input_event_queue_t::pop_discard_timeouts() { + while (has_lookahead()) { + auto evt = pop(); + if (!evt.is_timeout()) { + return evt; + } + } + return none(); +} + +char_event_t input_event_queue_t::readch() { ASSERT_IS_MAIN_THREAD(); - if (auto mc = s_lookahead->pop_evt()) { + if (auto mc = pop_discard_timeouts()) { return *mc; } wchar_t res; @@ -215,27 +201,27 @@ char_event_t input_common_readch() { } } -char_event_t input_common_readch_timed(bool dequeue_timeouts) { +char_event_t input_event_queue_t::readch_timed(bool dequeue_timeouts) { char_event_t result{char_event_type_t::timeout}; - if (s_lookahead->has_lookahead()) { - result = s_lookahead->pop(); + if (has_lookahead()) { + result = pop(); } else { fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); struct timeval tm = {wait_on_escape_ms / 1000, 1000 * (wait_on_escape_ms % 1000)}; if (select(1, &fds, 0, 0, &tm) > 0) { - result = input_common_readch(); + result = readch(); } } // If we got a timeout, either through dequeuing or creating, ensure it stays on the queue. if (result.is_timeout()) { - if (!dequeue_timeouts) s_lookahead->push_front(char_event_type_t::timeout); + if (!dequeue_timeouts) queue_.push_front(char_event_type_t::timeout); return char_event_type_t::timeout; } return result; } -void input_common_queue_ch(char_event_t ch) { s_lookahead->push_back(ch); } +void input_event_queue_t::push_back(char_event_t ch) { queue_.push_back(ch); } -void input_common_next_ch(char_event_t ch) { s_lookahead->push_front(ch); } +void input_event_queue_t::push_front(char_event_t ch) { queue_.push_front(ch); } diff --git a/src/input_common.h b/src/input_common.h index 2f00c7148..d27ecf165 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -6,6 +6,7 @@ #include "maybe.h" #include +#include enum class readline_cmd_t { beginning_of_line, @@ -150,24 +151,40 @@ void input_common_init(interrupt_func_t func); class environment_t; void update_wait_on_escape_ms(const environment_t &vars); -/// Function used by input_readch to read bytes from stdin until enough bytes have been read to -/// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously been -/// read and then 'unread' using \c input_common_unreadch, that character is returned. -/// This function never returns a timeout. -char_event_t input_common_readch(); +/// A class which knows how to produce a stream of input events. +class input_event_queue_t { + std::deque queue_; -/// Like input_common_readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a -/// character to be available for reading. -/// If \p dequeue_timeouts is set, remove any timeout from the queue; otherwise retain them. -char_event_t input_common_readch_timed(bool dequeue_timeouts = false); + /// \return if we have any lookahead. + bool has_lookahead() { return !queue_.empty(); } -/// Enqueue a character or a readline function to the queue of unread characters that input_readch -/// will return before actually reading from fd 0. -void input_common_queue_ch(char_event_t ch); + /// \return the next event in the queue. + char_event_t pop(); -/// Add a character or a readline function to the front of the queue of unread characters. This -/// will be the first character returned by input_readch (unless this function is called more than -/// once). -void input_common_next_ch(char_event_t ch); + /// \return the next event in the queue, discarding timeouts. + maybe_t pop_discard_timeouts(); + + char_event_t readb(); + + public: + /// Function used by input_readch to read bytes from stdin until enough bytes have been read to + /// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously + /// been read and then 'unread' using \c input_common_unreadch, that character is returned. This + /// function never returns a timeout. + char_event_t readch(); + + /// Like readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a + /// character to be available for reading. + /// If \p dequeue_timeouts is set, remove any timeout from the queue; otherwise retain them. + char_event_t readch_timed(bool dequeue_timeouts = false); + + /// Enqueue a character or a readline function to the queue of unread characters that + /// readch will return before actually reading from fd 0. + void push_back(char_event_t ch); + + /// Add a character or a readline function to the front of the queue of unread characters. This + /// will be the next character returned by readch. + void push_front(char_event_t ch); +}; #endif diff --git a/src/reader.cpp b/src/reader.cpp index 8e870590c..4884b5bda 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -345,6 +345,8 @@ class reader_data_t : public std::enable_shared_from_this { bool silent{false}; /// The representation of the current screen contents. screen_t screen; + /// The source of input events. + inputter_t inputter; /// The history. history_t *history{nullptr}; /// The history search. @@ -2371,7 +2373,7 @@ struct readline_loop_state_t { /// Read normal characters, inserting them into the command line. /// \return the next unhandled event. maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rls) { - maybe_t event_needing_handling = input_readch(); + maybe_t event_needing_handling = inputter.readch(); if (!event_is_normal_char(*event_needing_handling) || !can_read(STDIN_FILENO)) return event_needing_handling; @@ -2391,7 +2393,7 @@ maybe_t reader_data_t::read_normal_chars(readline_loop_state_t &rl // Only allow commands on the first key; otherwise, we might have data we // need to insert on the commandline that the commmand might need to be able // to see. - auto next_event = input_readch(false); + auto next_event = inputter.readch(false); if (event_is_normal_char(next_event)) { arr[i] = next_event.get_char(); } else { @@ -3101,10 +3103,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat ? jump_precision_t::to : jump_precision_t::till; editable_line_t *el = active_edit_line(); - wchar_t target = input_function_pop_arg(); + wchar_t target = inputter.function_pop_arg(); bool success = jump(direction, precision, el, target); - input_function_set_status(success); + inputter.function_set_status(success); reader_repaint_needed(); break; } @@ -3116,7 +3118,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat success = jump(last_jump_direction, last_jump_precision, el, last_jump_target); } - input_function_set_status(success); + inputter.function_set_status(success); reader_repaint_needed(); break; } @@ -3138,7 +3140,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat last_jump_direction = original_dir; - input_function_set_status(success); + inputter.function_set_status(success); reader_repaint_needed(); break; } @@ -3147,9 +3149,9 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat if (expand_abbreviation_as_necessary(1)) { super_highlight_me_plenty(); mark_repaint_needed(); - input_function_set_status(true); + inputter.function_set_status(true); } else { - input_function_set_status(false); + inputter.function_set_status(false); } break; } @@ -3394,6 +3396,12 @@ void reader_repaint_if_needed() { } } +void reader_queue_ch(const char_event_t &ch) { + if (reader_data_t *data = current_data_or_null()) { + data->inputter.queue_ch(ch); + } +} + void reader_react_to_color_change() { reader_data_t *data = current_data_or_null(); if (!data) return; @@ -3401,7 +3409,7 @@ void reader_react_to_color_change() { if (!data->repaint_needed || !data->screen_reset_needed) { data->repaint_needed = true; data->screen_reset_needed = true; - input_common_queue_ch(readline_cmd_t::repaint); + data->inputter.queue_ch(readline_cmd_t::repaint); } } diff --git a/src/reader.h b/src/reader.h index 21a0f216d..efd768304 100644 --- a/src/reader.h +++ b/src/reader.h @@ -85,6 +85,10 @@ void reader_react_to_color_change(); /// Repaint immediately if needed. void reader_repaint_if_needed(); +/// Enqueue an event to the back of the reader's input queue. +class char_event_t; +void reader_queue_ch(const char_event_t &ch); + /// Run the specified command with the correct terminal modes, and while taking care to perform job /// notification, set the title, etc. void reader_run_command(const wcstring &buff);