mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-28 20:34:07 +08:00
Factor readline command handling into new function handle_readline_command()
This commit is contained in:
parent
42f4d2bd86
commit
6ba94fd81b
231
src/reader.cpp
231
src/reader.cpp
|
@ -444,6 +444,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
|
||||
maybe_t<wcstring> readline(int nchars);
|
||||
maybe_t<char_event_t> read_normal_chars(readline_loop_state_t &rls);
|
||||
void handle_readline_command(readline_cmd_t cmd, readline_loop_state_t &rls);
|
||||
|
||||
void clear_pager();
|
||||
void select_completion_in_direction(enum selection_direction_t dir);
|
||||
|
@ -2484,104 +2485,10 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
|
|||
return event_needing_handling;
|
||||
}
|
||||
|
||||
maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
||||
using rl = readline_cmd_t;
|
||||
readline_loop_state_t rls{};
|
||||
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.
|
||||
cycle_command_line.clear();
|
||||
cycle_cursor_pos = 0;
|
||||
|
||||
history_search.reset();
|
||||
|
||||
exec_prompt();
|
||||
|
||||
super_highlight_me_plenty();
|
||||
s_reset(&screen, screen_reset_abandon_line);
|
||||
repaint();
|
||||
|
||||
/// 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();
|
||||
|
||||
// Get the current terminal modes. These will be restored when the function returns.
|
||||
if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output();
|
||||
|
||||
// Set the new modes.
|
||||
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
|
||||
int err = errno;
|
||||
if (err == EIO) {
|
||||
redirect_tty_output();
|
||||
}
|
||||
// This check is required to work around certain issues with fish's approach to
|
||||
// terminal control when launching interactive processes while in non-interactive
|
||||
// mode. See #4178 for one such example.
|
||||
if (err != ENOTTY || is_interactive_session) {
|
||||
wperror(L"tcsetattr");
|
||||
}
|
||||
}
|
||||
|
||||
while (!rls.finished && !shell_is_exiting()) {
|
||||
if (rls.nchars <= command_line.size()) {
|
||||
// We've already hit the specified character limit.
|
||||
rls.finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
maybe_t<char_event_t> event_needing_handling{};
|
||||
while (1) {
|
||||
event_needing_handling = read_normal_chars(rls);
|
||||
if (event_needing_handling.has_value()) break;
|
||||
|
||||
if (rls.nchars <= command_line.size()) {
|
||||
event_needing_handling.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event_needing_handling || event_needing_handling->is_check_exit()) {
|
||||
repaint_if_needed();
|
||||
continue;
|
||||
} else if (event_needing_handling->is_eof()) {
|
||||
reader_force_exit();
|
||||
continue;
|
||||
}
|
||||
assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) &&
|
||||
"Should have a char or readline");
|
||||
maybe_t<readline_cmd_t> readline_cmd{};
|
||||
maybe_t<wchar_t> ordinary_char{};
|
||||
if (event_needing_handling->is_readline()) {
|
||||
readline_cmd = event_needing_handling->get_readline();
|
||||
} else {
|
||||
ordinary_char = event_needing_handling->get_char();
|
||||
}
|
||||
|
||||
// If we get something other than a repaint, then stop coalescing them.
|
||||
if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false;
|
||||
|
||||
if (rls.last_cmd != rl::R_YANK && rls.last_cmd != rl::R_YANK_POP) {
|
||||
rls.yank_len = 0;
|
||||
}
|
||||
|
||||
// Restore the text.
|
||||
if (readline_cmd) {
|
||||
if (*readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) {
|
||||
set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos);
|
||||
}
|
||||
|
||||
// Clear the pager if necessary.
|
||||
bool focused_on_search_field = (active_edit_line() == &pager.search_field_line);
|
||||
if (command_ends_paging(*readline_cmd, focused_on_search_field)) {
|
||||
clear_pager();
|
||||
}
|
||||
}
|
||||
|
||||
readline_cmd_t c = readline_cmd ? *readline_cmd : static_cast<readline_cmd_t>(0);
|
||||
using rl = readline_cmd_t;
|
||||
switch (c) {
|
||||
// Go to beginning of line.
|
||||
case rl::R_BEGINNING_OF_LINE: {
|
||||
|
@ -2795,8 +2702,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
assert(end >= begin);
|
||||
|
||||
if (end > begin) {
|
||||
kill(el, begin, end - begin, KILL_APPEND,
|
||||
rls.last_cmd != rl::R_KILL_WHOLE_LINE);
|
||||
kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != rl::R_KILL_WHOLE_LINE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2857,8 +2763,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
is_backslashed(el->text, el->position) && !text_ends_in_comment(el->text);
|
||||
} else {
|
||||
// Allow mid line split if the following character is whitespace (issue #613).
|
||||
if (is_backslashed(el->text, el->position) &&
|
||||
iswspace(el->text.at(el->position))) {
|
||||
if (is_backslashed(el->text, el->position) && iswspace(el->text.at(el->position))) {
|
||||
continue_on_next_line = true;
|
||||
// Check if the end of the line is backslashed (issue #4467).
|
||||
} else if (is_backslashed(el->text, el->size()) &&
|
||||
|
@ -2939,8 +2844,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
}
|
||||
} else {
|
||||
// Searching by line.
|
||||
history_search.reset_to_mode(el->text, history,
|
||||
reader_history_search_t::line);
|
||||
history_search.reset_to_mode(el->text, history, reader_history_search_t::line);
|
||||
|
||||
// Skip the autosuggestion in the history unless it was truncated.
|
||||
const wcstring &suggest = autosuggestion;
|
||||
|
@ -2950,8 +2854,8 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
}
|
||||
}
|
||||
if (history_search.active()) {
|
||||
history_search_direction_t dir = (c == rl::R_HISTORY_SEARCH_BACKWARD ||
|
||||
c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD)
|
||||
history_search_direction_t dir =
|
||||
(c == rl::R_HISTORY_SEARCH_BACKWARD || c == rl::R_HISTORY_TOKEN_SEARCH_BACKWARD)
|
||||
? history_search_direction_t::backward
|
||||
: history_search_direction_t::forward;
|
||||
history_search.move_in_direction(dir);
|
||||
|
@ -3000,8 +2904,8 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
case rl::R_KILL_BIGWORD: {
|
||||
// The "bigword" functions differ only in that they move to the next whitespace, not
|
||||
// punctuation.
|
||||
auto move_style = (c == rl::R_KILL_WORD) ? move_word_style_punctuation
|
||||
: move_word_style_whitespace;
|
||||
auto move_style =
|
||||
(c == rl::R_KILL_WORD) ? move_word_style_punctuation : move_word_style_whitespace;
|
||||
move_word(active_edit_line(), MOVE_DIR_RIGHT, true /* erase */, move_style,
|
||||
rls.last_cmd != c /* same kill item if same movement */);
|
||||
break;
|
||||
|
@ -3030,8 +2934,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
case rl::R_END_OF_HISTORY: {
|
||||
bool up = (c == rl::R_BEGINNING_OF_HISTORY);
|
||||
if (is_navigating_pager_contents()) {
|
||||
select_completion_in_direction(up ? direction_page_north
|
||||
: direction_page_south);
|
||||
select_completion_in_direction(up ? direction_page_north : direction_page_south);
|
||||
} else {
|
||||
if (up) {
|
||||
history_search.go_to_beginning();
|
||||
|
@ -3153,8 +3056,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
if (tok_begin == &buff[len]) {
|
||||
// ...retry beginning from the previous token.
|
||||
size_t pos = prev_end - &buff[0];
|
||||
parse_util_token_extent(buff, pos, &tok_begin, &tok_end, &prev_begin,
|
||||
&prev_end);
|
||||
parse_util_token_extent(buff, pos, &tok_begin, &tok_end, &prev_begin, &prev_end);
|
||||
}
|
||||
|
||||
// Make sure we have two tokens.
|
||||
|
@ -3306,6 +3208,109 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
||||
using rl = readline_cmd_t;
|
||||
readline_loop_state_t rls{};
|
||||
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.
|
||||
cycle_command_line.clear();
|
||||
cycle_cursor_pos = 0;
|
||||
|
||||
history_search.reset();
|
||||
|
||||
exec_prompt();
|
||||
|
||||
super_highlight_me_plenty();
|
||||
s_reset(&screen, screen_reset_abandon_line);
|
||||
repaint();
|
||||
|
||||
// Get the current terminal modes. These will be restored when the function returns.
|
||||
if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output();
|
||||
|
||||
// Set the new modes.
|
||||
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
|
||||
int err = errno;
|
||||
if (err == EIO) {
|
||||
redirect_tty_output();
|
||||
}
|
||||
// This check is required to work around certain issues with fish's approach to
|
||||
// terminal control when launching interactive processes while in non-interactive
|
||||
// mode. See #4178 for one such example.
|
||||
if (err != ENOTTY || is_interactive_session) {
|
||||
wperror(L"tcsetattr");
|
||||
}
|
||||
}
|
||||
|
||||
while (!rls.finished && !shell_is_exiting()) {
|
||||
if (rls.nchars <= command_line.size()) {
|
||||
// We've already hit the specified character limit.
|
||||
rls.finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
maybe_t<char_event_t> event_needing_handling{};
|
||||
while (1) {
|
||||
event_needing_handling = read_normal_chars(rls);
|
||||
if (event_needing_handling.has_value()) break;
|
||||
|
||||
if (rls.nchars <= command_line.size()) {
|
||||
event_needing_handling.reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event_needing_handling || event_needing_handling->is_check_exit()) {
|
||||
repaint_if_needed();
|
||||
continue;
|
||||
} else if (event_needing_handling->is_eof()) {
|
||||
reader_force_exit();
|
||||
continue;
|
||||
}
|
||||
assert((event_needing_handling->is_char() || event_needing_handling->is_readline()) &&
|
||||
"Should have a char or readline");
|
||||
maybe_t<readline_cmd_t> readline_cmd{};
|
||||
maybe_t<wchar_t> ordinary_char{};
|
||||
if (event_needing_handling->is_readline()) {
|
||||
readline_cmd = event_needing_handling->get_readline();
|
||||
} else {
|
||||
ordinary_char = event_needing_handling->get_char();
|
||||
}
|
||||
|
||||
// If we get something other than a repaint, then stop coalescing them.
|
||||
if (readline_cmd != rl::R_REPAINT) rls.coalescing_repaints = false;
|
||||
|
||||
if (rls.last_cmd != rl::R_YANK && rls.last_cmd != rl::R_YANK_POP) {
|
||||
rls.yank_len = 0;
|
||||
}
|
||||
|
||||
// Restore the text.
|
||||
if (readline_cmd) {
|
||||
if (*readline_cmd == rl::R_CANCEL && is_navigating_pager_contents()) {
|
||||
set_command_line_and_position(&command_line, cycle_command_line, cycle_cursor_pos);
|
||||
}
|
||||
|
||||
// Clear the pager if necessary.
|
||||
bool focused_on_search_field = (active_edit_line() == &pager.search_field_line);
|
||||
if (command_ends_paging(*readline_cmd, focused_on_search_field)) {
|
||||
clear_pager();
|
||||
}
|
||||
|
||||
handle_readline_command(*readline_cmd, rls);
|
||||
|
||||
if (!readline_cmd || command_ends_history_search(*readline_cmd)) {
|
||||
history_search.reset();
|
||||
}
|
||||
rls.last_cmd = readline_cmd;
|
||||
}
|
||||
|
||||
if (ordinary_char) {
|
||||
wchar_t c = *ordinary_char;
|
||||
|
@ -3336,10 +3341,6 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!readline_cmd || command_ends_history_search(*readline_cmd)) {
|
||||
history_search.reset();
|
||||
}
|
||||
rls.last_cmd = readline_cmd;
|
||||
repaint_if_needed();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user