mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-25 09:39:52 +08:00
Factor out the "read coalescing" part of reader_data_t::readline
This commit is contained in:
parent
7ae7865071
commit
42f4d2bd86
124
src/reader.cpp
124
src/reader.cpp
|
@ -105,7 +105,7 @@
|
||||||
/// The maximum number of characters to read from the keyboard without repainting. Note that this
|
/// The maximum number of characters to read from the keyboard without repainting. Note that this
|
||||||
/// readahead will only occur if new characters are available for reading, fish will never block for
|
/// readahead will only occur if new characters are available for reading, fish will never block for
|
||||||
/// more input without repainting.
|
/// more input without repainting.
|
||||||
#define READAHEAD_MAX 256
|
static constexpr size_t READAHEAD_MAX = 256;
|
||||||
|
|
||||||
/// A mode for calling the reader_kill function. In this mode, the new string is appended to the
|
/// A mode for calling the reader_kill function. In this mode, the new string is appended to the
|
||||||
/// current contents of the kill buffer.
|
/// current contents of the kill buffer.
|
||||||
|
@ -316,6 +316,8 @@ struct highlight_result_t {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
struct readline_loop_state_t;
|
||||||
|
|
||||||
/// A struct describing the state of the interactive reader. These states can be stacked, in case
|
/// A struct describing the state of the interactive reader. These states can be stacked, in case
|
||||||
/// reader_readline() calls are nested. This happens when the 'read' builtin is used.
|
/// reader_readline() calls are nested. This happens when the 'read' builtin is used.
|
||||||
class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
||||||
|
@ -441,6 +443,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
||||||
bool newv);
|
bool newv);
|
||||||
|
|
||||||
maybe_t<wcstring> readline(int nchars);
|
maybe_t<wcstring> readline(int nchars);
|
||||||
|
maybe_t<char_event_t> read_normal_chars(readline_loop_state_t &rls);
|
||||||
|
|
||||||
void clear_pager();
|
void clear_pager();
|
||||||
void select_completion_in_direction(enum selection_direction_t dir);
|
void select_completion_in_direction(enum selection_direction_t dir);
|
||||||
|
@ -2426,13 +2429,72 @@ struct readline_loop_state_t {
|
||||||
/// Whether the loop has finished, due to reaching the character limit or through executing a
|
/// Whether the loop has finished, due to reaching the character limit or through executing a
|
||||||
/// command.
|
/// command.
|
||||||
bool finished{false};
|
bool finished{false};
|
||||||
|
|
||||||
|
/// Maximum number of characters to read.
|
||||||
|
size_t nchars{std::numeric_limits<size_t>::max()};
|
||||||
};
|
};
|
||||||
|
|
||||||
maybe_t<wcstring> reader_data_t::readline(int nchars) {
|
/// Read normal characters, inserting them into the command line.
|
||||||
|
/// \return the next unhandled event.
|
||||||
|
maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rls) {
|
||||||
|
int was_interactive_read = is_interactive_read;
|
||||||
|
is_interactive_read = 1;
|
||||||
|
maybe_t<char_event_t> event_needing_handling = input_readch();
|
||||||
|
is_interactive_read = was_interactive_read;
|
||||||
|
|
||||||
|
if (!event_is_normal_char(*event_needing_handling) || !can_read(STDIN_FILENO))
|
||||||
|
return event_needing_handling;
|
||||||
|
|
||||||
|
// This is a normal character input.
|
||||||
|
// We are going to handle it directly, accumulating more.
|
||||||
|
char_event_t evt = event_needing_handling.acquire();
|
||||||
|
size_t limit = std::min(rls.nchars - command_line.size(), READAHEAD_MAX);
|
||||||
|
|
||||||
|
wchar_t arr[READAHEAD_MAX + 1] = {};
|
||||||
|
arr[0] = evt.get_char();
|
||||||
|
|
||||||
|
for (size_t i = 1; i < limit; ++i) {
|
||||||
|
if (!can_read(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
if (event_is_normal_char(next_event)) {
|
||||||
|
arr[i] = next_event.get_char();
|
||||||
|
} else {
|
||||||
|
// We need to process this in the outer loop.
|
||||||
|
assert(!event_needing_handling && "Should not have an unhandled event");
|
||||||
|
event_needing_handling = next_event;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editable_line_t *el = active_edit_line();
|
||||||
|
insert_string(el, arr, true);
|
||||||
|
|
||||||
|
// End paging upon inserting into the normal command line.
|
||||||
|
if (el == &command_line) {
|
||||||
|
clear_pager();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we handled a normal character, we don't have a last command.
|
||||||
|
rls.last_cmd.reset();
|
||||||
|
return event_needing_handling;
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
||||||
using rl = readline_cmd_t;
|
using rl = readline_cmd_t;
|
||||||
readline_loop_state_t rls{};
|
readline_loop_state_t rls{};
|
||||||
struct termios old_modes;
|
struct termios old_modes;
|
||||||
|
|
||||||
|
// If nchars_or_0 is positive, then that's the maximum number of chars. Otherwise keep it at
|
||||||
|
// SIZE_MAX.
|
||||||
|
if (nchars_or_0 > 0) {
|
||||||
|
rls.nchars = static_cast<size_t>(nchars_or_0);
|
||||||
|
}
|
||||||
|
|
||||||
// The command line before completion.
|
// The command line before completion.
|
||||||
cycle_command_line.clear();
|
cycle_command_line.clear();
|
||||||
cycle_cursor_pos = 0;
|
cycle_cursor_pos = 0;
|
||||||
|
@ -2465,70 +2527,18 @@ maybe_t<wcstring> reader_data_t::readline(int nchars) {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!rls.finished && !shell_is_exiting()) {
|
while (!rls.finished && !shell_is_exiting()) {
|
||||||
if (0 < nchars && (size_t)nchars <= command_line.size()) {
|
if (rls.nchars <= command_line.size()) {
|
||||||
// We've already hit the specified character limit.
|
// We've already hit the specified character limit.
|
||||||
rls.finished = true;
|
rls.finished = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes strange input sequences seem to generate a zero byte. I believe these simply
|
|
||||||
// mean a character was pressed but it should be ignored. (Example: Trying to add a tilde
|
|
||||||
// (~) to digit).
|
|
||||||
maybe_t<char_event_t> event_needing_handling{};
|
maybe_t<char_event_t> event_needing_handling{};
|
||||||
while (1) {
|
while (1) {
|
||||||
int was_interactive_read = is_interactive_read;
|
event_needing_handling = read_normal_chars(rls);
|
||||||
is_interactive_read = 1;
|
|
||||||
event_needing_handling = input_readch();
|
|
||||||
is_interactive_read = was_interactive_read;
|
|
||||||
// std::fwprintf(stderr, L"C: %lx\n", (long)c);
|
|
||||||
|
|
||||||
if (event_is_normal_char(*event_needing_handling) && can_read(STDIN_FILENO)) {
|
|
||||||
// This is a normal character input.
|
|
||||||
// We are going to handle it directly, accumulating more.
|
|
||||||
// Clear 'mevt' to mark that we handled this.
|
|
||||||
char_event_t evt = event_needing_handling.acquire();
|
|
||||||
size_t limit = 0 < nchars ? std::min((size_t)nchars - command_line.size(),
|
|
||||||
(size_t)READAHEAD_MAX)
|
|
||||||
: READAHEAD_MAX;
|
|
||||||
|
|
||||||
wchar_t arr[READAHEAD_MAX + 1] = {};
|
|
||||||
arr[0] = evt.get_char();
|
|
||||||
|
|
||||||
for (size_t i = 1; i < limit; ++i) {
|
|
||||||
if (!can_read(0)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 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);
|
|
||||||
if (event_is_normal_char(next_event)) {
|
|
||||||
arr[i] = next_event.get_char();
|
|
||||||
} else {
|
|
||||||
// We need to process this in the outer loop.
|
|
||||||
assert(!event_needing_handling && "Should not have an unhandled event");
|
|
||||||
event_needing_handling = next_event;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editable_line_t *el = active_edit_line();
|
|
||||||
insert_string(el, arr, true);
|
|
||||||
|
|
||||||
// End paging upon inserting into the normal command line.
|
|
||||||
if (el == &command_line) {
|
|
||||||
clear_pager();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we handled a normal character, we don't have a last command.
|
|
||||||
rls.last_cmd.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's still an event that we were unable to handle, then end the coalescing
|
|
||||||
// loop.
|
|
||||||
if (event_needing_handling.has_value()) break;
|
if (event_needing_handling.has_value()) break;
|
||||||
|
|
||||||
if (0 < nchars && (size_t)nchars <= command_line.size()) {
|
if (rls.nchars <= command_line.size()) {
|
||||||
event_needing_handling.reset();
|
event_needing_handling.reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user