mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-01-21 04:52:01 +08:00
Factor out handling of readline_cmd_t::execute
This reduces the size of handle_readline_command. No functional change.
This commit is contained in:
parent
7fb4b7c8bd
commit
1dff1cb2c4
228
src/reader.cpp
228
src/reader.cpp
|
@ -846,6 +846,10 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
||||||
maybe_t<char_event_t> read_normal_chars(readline_loop_state_t &rls);
|
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 handle_readline_command(readline_cmd_t cmd, readline_loop_state_t &rls);
|
||||||
|
|
||||||
|
// Handle readline_cmd_t::execute. This may mean inserting a newline if the command is
|
||||||
|
// unfinished.
|
||||||
|
void handle_execute(readline_loop_state_t &rls);
|
||||||
|
|
||||||
void clear_pager();
|
void clear_pager();
|
||||||
void select_completion_in_direction(selection_motion_t dir,
|
void select_completion_in_direction(selection_motion_t dir,
|
||||||
bool force_selection_change = false);
|
bool force_selection_change = false);
|
||||||
|
@ -3563,118 +3567,8 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Evaluate. If the current command is unfinished, or if the charater is escaped
|
|
||||||
// using a backslash, insert a newline.
|
|
||||||
case rl::execute: {
|
case rl::execute: {
|
||||||
// If the user hits return while navigating the pager, it only clears the pager.
|
this->handle_execute(rls);
|
||||||
if (is_navigating_pager_contents()) {
|
|
||||||
clear_pager();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete any autosuggestion.
|
|
||||||
autosuggestion.clear();
|
|
||||||
|
|
||||||
// The user may have hit return with pager contents, but while not navigating them.
|
|
||||||
// Clear the pager in that event.
|
|
||||||
clear_pager();
|
|
||||||
|
|
||||||
// We only execute the command line.
|
|
||||||
editable_line_t *el = &command_line;
|
|
||||||
|
|
||||||
// Allow backslash-escaped newlines.
|
|
||||||
bool continue_on_next_line = false;
|
|
||||||
if (el->position() >= el->size()) {
|
|
||||||
// We're at the end of the text and not in a comment (issue #1225).
|
|
||||||
continue_on_next_line =
|
|
||||||
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()))) {
|
|
||||||
continue_on_next_line = true;
|
|
||||||
// Check if the end of the line is backslashed (issue #4467).
|
|
||||||
} else if (is_backslashed(el->text(), el->size()) &&
|
|
||||||
!text_ends_in_comment(el->text())) {
|
|
||||||
// Move the cursor to the end of the line.
|
|
||||||
el->set_position(el->size());
|
|
||||||
continue_on_next_line = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the conditions are met, insert a new line at the position of the cursor.
|
|
||||||
if (continue_on_next_line) {
|
|
||||||
insert_char(el, L'\n');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if this command is valid.
|
|
||||||
parser_test_error_bits_t command_test_result = 0;
|
|
||||||
if (conf.syntax_check_ok) {
|
|
||||||
command_test_result = reader_shell_test(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.
|
|
||||||
if (expand_abbreviation_as_necessary(0)) {
|
|
||||||
// Trigger syntax highlighting as we are likely about to execute this command.
|
|
||||||
this->super_highlight_me_plenty();
|
|
||||||
if (conf.syntax_check_ok) {
|
|
||||||
command_test_result = reader_shell_test(parser(), el->text());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command_test_result == 0) {
|
|
||||||
// Finished command, execute it. Don't add items in silent mode (#7230).
|
|
||||||
wcstring text = command_line.text();
|
|
||||||
if (text.empty()) {
|
|
||||||
// Here the user just hit return. Make a new prompt, don't remove ephemeral
|
|
||||||
// items.
|
|
||||||
rls.finished = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Historical behavior is to trim trailing spaces.
|
|
||||||
// However, escaped spaces ('\ ') should not be trimmed (#7661)
|
|
||||||
// This can be done by counting pre-trailing '\'
|
|
||||||
// If there's an odd number, this must be an escaped space.
|
|
||||||
while (!text.empty() && text.back() == L' ' &&
|
|
||||||
count_preceding_backslashes(text, text.size() - 1) % 2 == 0) {
|
|
||||||
text.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (history && !conf.in_silent_mode) {
|
|
||||||
// Remove ephemeral items - even if the text is empty
|
|
||||||
history->remove_ephemeral_items();
|
|
||||||
|
|
||||||
if (!text.empty()) {
|
|
||||||
// Mark this item as ephemeral if there is a leading space (#615).
|
|
||||||
history_persistence_mode_t mode;
|
|
||||||
if (text.front() == L' ') {
|
|
||||||
// Leading spaces are ephemeral (#615).
|
|
||||||
mode = history_persistence_mode_t::ephemeral;
|
|
||||||
} else if (in_private_mode(vars)) {
|
|
||||||
// Private mode means in-memory only.
|
|
||||||
mode = history_persistence_mode_t::memory;
|
|
||||||
} else {
|
|
||||||
mode = history_persistence_mode_t::disk;
|
|
||||||
}
|
|
||||||
history_t::add_pending_with_file_detection(history, text, vars.snapshot(),
|
|
||||||
mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rls.finished = true;
|
|
||||||
update_buff_pos(&command_line, command_line.size());
|
|
||||||
} else if (command_test_result == PARSER_TEST_INCOMPLETE) {
|
|
||||||
// We are incomplete, continue editing.
|
|
||||||
insert_char(el, L'\n');
|
|
||||||
} else {
|
|
||||||
// Result must be some combination including an error. The error message will
|
|
||||||
// already be printed, all we need to do is repaint.
|
|
||||||
event_fire_generic(parser(), L"fish_posterror", {el->text()});
|
|
||||||
screen.reset_abandoning_line(termsize_last().width);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4248,6 +4142,118 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reader_data_t::handle_execute(readline_loop_state_t &rls) {
|
||||||
|
// Evaluate. If the current command is unfinished, or if the charater is escaped
|
||||||
|
// using a backslash, insert a newline.
|
||||||
|
// If the user hits return while navigating the pager, it only clears the pager.
|
||||||
|
if (is_navigating_pager_contents()) {
|
||||||
|
clear_pager();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete any autosuggestion.
|
||||||
|
autosuggestion.clear();
|
||||||
|
|
||||||
|
// The user may have hit return with pager contents, but while not navigating them.
|
||||||
|
// Clear the pager in that event.
|
||||||
|
clear_pager();
|
||||||
|
|
||||||
|
// We only execute the command line.
|
||||||
|
editable_line_t *el = &command_line;
|
||||||
|
|
||||||
|
// Allow backslash-escaped newlines.
|
||||||
|
bool continue_on_next_line = false;
|
||||||
|
if (el->position() >= el->size()) {
|
||||||
|
// We're at the end of the text and not in a comment (issue #1225).
|
||||||
|
continue_on_next_line =
|
||||||
|
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()))) {
|
||||||
|
continue_on_next_line = true;
|
||||||
|
// Check if the end of the line is backslashed (issue #4467).
|
||||||
|
} else if (is_backslashed(el->text(), el->size()) && !text_ends_in_comment(el->text())) {
|
||||||
|
// Move the cursor to the end of the line.
|
||||||
|
el->set_position(el->size());
|
||||||
|
continue_on_next_line = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the conditions are met, insert a new line at the position of the cursor.
|
||||||
|
if (continue_on_next_line) {
|
||||||
|
insert_char(el, L'\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if this command is valid.
|
||||||
|
parser_test_error_bits_t command_test_result = 0;
|
||||||
|
if (conf.syntax_check_ok) {
|
||||||
|
command_test_result = reader_shell_test(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.
|
||||||
|
if (expand_abbreviation_as_necessary(0)) {
|
||||||
|
// Trigger syntax highlighting as we are likely about to execute this command.
|
||||||
|
this->super_highlight_me_plenty();
|
||||||
|
if (conf.syntax_check_ok) {
|
||||||
|
command_test_result = reader_shell_test(parser(), el->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command_test_result == 0) {
|
||||||
|
// Finished command, execute it. Don't add items in silent mode (#7230).
|
||||||
|
wcstring text = command_line.text();
|
||||||
|
if (text.empty()) {
|
||||||
|
// Here the user just hit return. Make a new prompt, don't remove ephemeral
|
||||||
|
// items.
|
||||||
|
rls.finished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Historical behavior is to trim trailing spaces.
|
||||||
|
// However, escaped spaces ('\ ') should not be trimmed (#7661)
|
||||||
|
// This can be done by counting pre-trailing '\'
|
||||||
|
// If there's an odd number, this must be an escaped space.
|
||||||
|
while (!text.empty() && text.back() == L' ' &&
|
||||||
|
count_preceding_backslashes(text, text.size() - 1) % 2 == 0) {
|
||||||
|
text.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (history && !conf.in_silent_mode) {
|
||||||
|
// Remove ephemeral items - even if the text is empty
|
||||||
|
history->remove_ephemeral_items();
|
||||||
|
|
||||||
|
if (!text.empty()) {
|
||||||
|
// Mark this item as ephemeral if there is a leading space (#615).
|
||||||
|
history_persistence_mode_t mode;
|
||||||
|
if (text.front() == L' ') {
|
||||||
|
// Leading spaces are ephemeral (#615).
|
||||||
|
mode = history_persistence_mode_t::ephemeral;
|
||||||
|
} else if (in_private_mode(this->vars())) {
|
||||||
|
// Private mode means in-memory only.
|
||||||
|
mode = history_persistence_mode_t::memory;
|
||||||
|
} else {
|
||||||
|
mode = history_persistence_mode_t::disk;
|
||||||
|
}
|
||||||
|
history_t::add_pending_with_file_detection(history, text, this->vars().snapshot(),
|
||||||
|
mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rls.finished = true;
|
||||||
|
update_buff_pos(&command_line, command_line.size());
|
||||||
|
} else if (command_test_result == PARSER_TEST_INCOMPLETE) {
|
||||||
|
// We are incomplete, continue editing.
|
||||||
|
insert_char(el, L'\n');
|
||||||
|
} else {
|
||||||
|
// Result must be some combination including an error. The error message will
|
||||||
|
// already be printed, all we need to do is repaint.
|
||||||
|
event_fire_generic(parser(), L"fish_posterror", {el->text()});
|
||||||
|
screen.reset_abandoning_line(termsize_last().width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
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{};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user