mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-01 06:09:45 +08:00
Remove most dynamic reader configuration
Have the reader accept a constant configuration object, which controls whether autosuggestions, etc. are enabled. These things don't change dynamically.
This commit is contained in:
parent
fadd429348
commit
272ca37582
|
@ -201,22 +201,25 @@ static int read_interactive(parser_t &parser, wcstring &buff, int nchars, bool s
|
|||
const wchar_t *commandline) {
|
||||
int exit_res = STATUS_CMD_OK;
|
||||
|
||||
// Don't keep history
|
||||
reader_push(parser, L"");
|
||||
reader_get_history()->resolve_pending();
|
||||
// Construct a configuration.
|
||||
reader_config_t conf;
|
||||
conf.complete_ok = shell;
|
||||
conf.highlight_ok = shell;
|
||||
conf.syntax_check_ok = shell;
|
||||
|
||||
reader_set_left_prompt(prompt);
|
||||
reader_set_right_prompt(right_prompt);
|
||||
if (shell) {
|
||||
reader_set_complete_ok(true);
|
||||
reader_set_highlight_ok(true);
|
||||
reader_set_syntax_check_ok(true);
|
||||
}
|
||||
// No autosuggestions or abbreviations in builtin_read.
|
||||
reader_set_allow_autosuggesting(false);
|
||||
reader_set_expand_abbreviations(false);
|
||||
reader_set_exit_on_interrupt(true);
|
||||
reader_set_silent_status(silent);
|
||||
conf.autosuggest_ok = false;
|
||||
conf.expand_abbrev_ok = false;
|
||||
|
||||
conf.exit_on_interrupt = true;
|
||||
conf.in_silent_mode = silent;
|
||||
|
||||
conf.left_prompt_cmd = prompt;
|
||||
conf.right_prompt_cmd = right_prompt;
|
||||
|
||||
// Don't keep history.
|
||||
reader_push(parser, wcstring{}, std::move(conf));
|
||||
reader_get_history()->resolve_pending();
|
||||
|
||||
reader_set_buffer(commandline, std::wcslen(commandline));
|
||||
scoped_push<bool> interactive{&parser.libdata().is_interactive, true};
|
||||
|
|
146
src/reader.cpp
146
src/reader.cpp
|
@ -452,6 +452,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<reader_data_t> {
|
||||
public:
|
||||
/// Configuration for the reader.
|
||||
const reader_config_t conf;
|
||||
/// The parser being used.
|
||||
std::shared_ptr<parser_t> parser_ref;
|
||||
/// String containing the whole current commandline.
|
||||
|
@ -466,14 +468,8 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
pager_t pager;
|
||||
/// Current page rendering.
|
||||
page_rendering_t current_page_rendering;
|
||||
/// Whether autosuggesting is allowed at all.
|
||||
bool allow_autosuggestion{false};
|
||||
/// When backspacing, we temporarily suppress autosuggestions.
|
||||
bool suppress_autosuggestion{false};
|
||||
/// Whether abbreviations are expanded.
|
||||
bool expand_abbreviations{false};
|
||||
/// Silent mode used for password input on the read command
|
||||
bool silent{false};
|
||||
/// The representation of the current screen contents.
|
||||
screen_t screen;
|
||||
/// The source of input events.
|
||||
|
@ -490,9 +486,6 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
size_t sel_start_pos{0};
|
||||
/// The stop position of the current selection, if one.
|
||||
size_t sel_stop_pos{0};
|
||||
/// The prompt commands.
|
||||
wcstring left_prompt;
|
||||
wcstring right_prompt;
|
||||
/// The output of the last evaluation of the prompt command.
|
||||
wcstring left_prompt_buff;
|
||||
wcstring mode_prompt_buff;
|
||||
|
@ -506,12 +499,6 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
std::vector<highlight_spec_t> colors;
|
||||
/// An array defining the block level at each character.
|
||||
std::vector<int> indents;
|
||||
/// Whether tab completion is allowed.
|
||||
bool complete_ok{false};
|
||||
/// Whether to perform syntax highlighting.
|
||||
bool highlight_ok{false};
|
||||
/// Whether to perform fish syntax checking.
|
||||
bool syntax_check_ok{false};
|
||||
/// If this is true, exit reader even if there are running jobs. This happens if we press e.g.
|
||||
/// ^D twice.
|
||||
bool prev_end_loop{false};
|
||||
|
@ -522,8 +509,6 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
bool repaint_needed{false};
|
||||
/// Whether a screen reset is needed after a repaint.
|
||||
bool screen_reset_needed{false};
|
||||
/// Whether the reader should exit on ^C.
|
||||
bool exit_on_interrupt{false};
|
||||
/// The target character of the last jump command.
|
||||
wchar_t last_jump_target{0};
|
||||
jump_direction_t last_jump_direction{jump_direction_t::forward};
|
||||
|
@ -563,8 +548,11 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
/// Access the parser.
|
||||
parser_t &parser() { return *parser_ref; }
|
||||
|
||||
reader_data_t(std::shared_ptr<parser_t> parser, history_t *hist)
|
||||
: parser_ref(std::move(parser)), inputter(*parser_ref), history(hist) {}
|
||||
reader_data_t(std::shared_ptr<parser_t> parser, history_t *hist, reader_config_t &&conf)
|
||||
: conf(std::move(conf)),
|
||||
parser_ref(std::move(parser)),
|
||||
inputter(*parser_ref),
|
||||
history(hist) {}
|
||||
|
||||
void update_buff_pos(editable_line_t *el, maybe_t<size_t> new_pos = none_t());
|
||||
void repaint();
|
||||
|
@ -593,7 +581,8 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
bool can_autosuggest() const;
|
||||
void autosuggest_completed(autosuggestion_result_t result);
|
||||
void update_autosuggestion();
|
||||
void accept_autosuggestion(bool full, bool single = false, move_word_style_t style = move_word_style_punctuation);
|
||||
void accept_autosuggestion(bool full, bool single = false,
|
||||
move_word_style_t style = move_word_style_punctuation);
|
||||
void super_highlight_me_plenty(int highlight_pos_adjust = 0, bool no_io = false);
|
||||
|
||||
void highlight_search();
|
||||
|
@ -818,7 +807,7 @@ void reader_data_t::repaint() {
|
|||
indents = parse_util_compute_indents(cmd_line->text());
|
||||
|
||||
wcstring full_line;
|
||||
if (silent) {
|
||||
if (conf.in_silent_mode) {
|
||||
full_line = wcstring(cmd_line->text().length(), get_obfuscation_read_char());
|
||||
} else {
|
||||
// Combine the command and autosuggestion into one string.
|
||||
|
@ -993,7 +982,7 @@ bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack) {
|
|||
bool result = false;
|
||||
editable_line_t *el = active_edit_line();
|
||||
|
||||
if (expand_abbreviations && el == &command_line) {
|
||||
if (conf.expand_abbrev_ok && el == &command_line) {
|
||||
// Try expanding abbreviations.
|
||||
size_t cursor_pos = el->position() - std::min(el->position(), cursor_backtrack);
|
||||
|
||||
|
@ -1088,35 +1077,35 @@ void reader_data_t::exec_prompt() {
|
|||
// Suppress fish_trace while in the prompt.
|
||||
scoped_push<bool> in_prompt(&parser().libdata().suppress_fish_trace, true);
|
||||
|
||||
// Do not allow the exit status of the prompts to leak through.
|
||||
const bool apply_exit_status = false;
|
||||
|
||||
// Update the termsize now.
|
||||
// This allows prompts to react to $COLUMNS.
|
||||
update_termsize();
|
||||
|
||||
// If we have any prompts, they must be run non-interactively.
|
||||
if (!left_prompt.empty() || !right_prompt.empty()) {
|
||||
if (!conf.left_prompt_cmd.empty() || !conf.right_prompt_cmd.empty()) {
|
||||
scoped_push<bool> noninteractive{&parser().libdata().is_interactive, false};
|
||||
|
||||
exec_mode_prompt();
|
||||
|
||||
if (!left_prompt.empty()) {
|
||||
if (!conf.left_prompt_cmd.empty()) {
|
||||
// Status is ignored.
|
||||
wcstring_list_t prompt_list;
|
||||
// Ignore return status.
|
||||
exec_subshell(left_prompt, parser(), prompt_list, apply_exit_status);
|
||||
for (size_t i = 0; i < prompt_list.size(); i++) {
|
||||
if (i > 0) left_prompt_buff += L'\n';
|
||||
left_prompt_buff += prompt_list.at(i);
|
||||
}
|
||||
// Historic compatibility hack.
|
||||
// If the left prompt function is deleted, then use a default prompt instead of
|
||||
// producing an error.
|
||||
bool left_prompt_deleted = conf.left_prompt_cmd == LEFT_PROMPT_FUNCTION_NAME &&
|
||||
!function_exists(conf.left_prompt_cmd, parser());
|
||||
exec_subshell(left_prompt_deleted ? DEFAULT_PROMPT : conf.left_prompt_cmd, parser(),
|
||||
prompt_list, false);
|
||||
left_prompt_buff = join_strings(prompt_list, L'\n');
|
||||
}
|
||||
|
||||
if (!right_prompt.empty()) {
|
||||
wcstring_list_t prompt_list;
|
||||
if (!conf.right_prompt_cmd.empty()) {
|
||||
// Status is ignored.
|
||||
exec_subshell(right_prompt, parser(), prompt_list, apply_exit_status);
|
||||
wcstring_list_t prompt_list;
|
||||
exec_subshell(conf.right_prompt_cmd, parser(), prompt_list, false);
|
||||
// Right prompt does not support multiple lines, so just concatenate all of them.
|
||||
for (const auto &i : prompt_list) {
|
||||
// Right prompt does not support multiple lines, so just concatenate all of them.
|
||||
right_prompt_buff += i;
|
||||
}
|
||||
}
|
||||
|
@ -1533,7 +1522,7 @@ bool reader_data_t::can_autosuggest() const {
|
|||
// and our command line contains a non-whitespace character.
|
||||
const editable_line_t *el = active_edit_line();
|
||||
const wchar_t *whitespace = L" \t\r\n\v";
|
||||
return allow_autosuggestion && !suppress_autosuggestion && history_search.is_at_end() &&
|
||||
return conf.autosuggest_ok && !suppress_autosuggestion && history_search.is_at_end() &&
|
||||
el == &command_line && el->text().find_first_not_of(whitespace) != wcstring::npos;
|
||||
}
|
||||
|
||||
|
@ -2293,7 +2282,7 @@ static std::function<highlight_result_t(void)> get_highlight_performer(parser_t
|
|||
/// \param no_io if true, do a highlight that does not perform I/O, synchronously. If false, perform
|
||||
/// an asynchronous highlight in the background, which may perform disk I/O.
|
||||
void reader_data_t::super_highlight_me_plenty(int match_highlight_pos_adjust, bool no_io) {
|
||||
if (!highlight_ok) return;
|
||||
if (!conf.highlight_ok) return;
|
||||
|
||||
const editable_line_t *el = &command_line;
|
||||
assert(el != nullptr);
|
||||
|
@ -2353,9 +2342,10 @@ void reader_change_history(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<reader_data_t>(parser.shared(), hist));
|
||||
void reader_push(parser_t &parser, const wcstring &history_name, reader_config_t &&conf) {
|
||||
history_t *hist = &history_t::history_with_name(history_name);
|
||||
reader_data_stack.push_back(
|
||||
std::make_shared<reader_data_t>(parser.shared(), hist, std::move(conf)));
|
||||
reader_data_t *data = current_data();
|
||||
data->command_line_changed(&data->command_line);
|
||||
if (reader_data_stack.size() == 1) {
|
||||
|
@ -2377,28 +2367,6 @@ void reader_pop() {
|
|||
}
|
||||
}
|
||||
|
||||
void reader_set_left_prompt(const wcstring &new_prompt) {
|
||||
current_data()->left_prompt = new_prompt;
|
||||
}
|
||||
|
||||
void reader_set_right_prompt(const wcstring &new_prompt) {
|
||||
current_data()->right_prompt = new_prompt;
|
||||
}
|
||||
|
||||
void reader_set_allow_autosuggesting(bool flag) { current_data()->allow_autosuggestion = flag; }
|
||||
|
||||
void reader_set_expand_abbreviations(bool flag) { current_data()->expand_abbreviations = flag; }
|
||||
|
||||
void reader_set_complete_ok(bool flag) { current_data()->complete_ok = flag; }
|
||||
|
||||
void reader_set_highlight_ok(bool flag) { current_data()->highlight_ok = flag; }
|
||||
|
||||
void reader_set_syntax_check_ok(bool flag) { current_data()->syntax_check_ok = flag; }
|
||||
|
||||
void reader_set_exit_on_interrupt(bool i) { current_data()->exit_on_interrupt = i; }
|
||||
|
||||
void reader_set_silent_status(bool flag) { current_data()->silent = flag; }
|
||||
|
||||
void reader_import_history_if_necessary() {
|
||||
// Import history from older location (config path) if our current history is empty.
|
||||
reader_data_t *data = current_data();
|
||||
|
@ -2482,12 +2450,26 @@ 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) {
|
||||
reader_push(parser, history_session_id(parser.vars()));
|
||||
reader_set_complete_ok(true);
|
||||
reader_set_highlight_ok(true);
|
||||
reader_set_syntax_check_ok(true);
|
||||
reader_set_allow_autosuggesting(true);
|
||||
reader_set_expand_abbreviations(true);
|
||||
reader_config_t conf;
|
||||
conf.complete_ok = true;
|
||||
conf.highlight_ok = true;
|
||||
conf.syntax_check_ok = true;
|
||||
conf.autosuggest_ok = true;
|
||||
conf.expand_abbrev_ok = true;
|
||||
|
||||
if (parser.libdata().is_breakpoint && function_exists(DEBUG_PROMPT_FUNCTION_NAME, parser)) {
|
||||
conf.left_prompt_cmd = DEBUG_PROMPT_FUNCTION_NAME;
|
||||
} else {
|
||||
conf.left_prompt_cmd = LEFT_PROMPT_FUNCTION_NAME;
|
||||
}
|
||||
|
||||
if (function_exists(RIGHT_PROMPT_FUNCTION_NAME, parser)) {
|
||||
conf.right_prompt_cmd = RIGHT_PROMPT_FUNCTION_NAME;
|
||||
} else {
|
||||
conf.right_prompt_cmd = wcstring{};
|
||||
}
|
||||
|
||||
reader_push(parser, history_session_id(parser.vars()), std::move(conf));
|
||||
reader_import_history_if_necessary();
|
||||
|
||||
reader_data_t *data = current_data();
|
||||
|
@ -2496,20 +2478,6 @@ static int read_i(parser_t &parser) {
|
|||
while (!shell_is_exiting()) {
|
||||
run_count++;
|
||||
|
||||
if (parser.libdata().is_breakpoint && function_exists(DEBUG_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_left_prompt(DEBUG_PROMPT_FUNCTION_NAME);
|
||||
} else if (function_exists(LEFT_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_left_prompt(LEFT_PROMPT_FUNCTION_NAME);
|
||||
} else {
|
||||
reader_set_left_prompt(DEFAULT_PROMPT);
|
||||
}
|
||||
|
||||
if (function_exists(RIGHT_PROMPT_FUNCTION_NAME, parser)) {
|
||||
reader_set_right_prompt(RIGHT_PROMPT_FUNCTION_NAME);
|
||||
} else {
|
||||
reader_set_right_prompt(L"");
|
||||
}
|
||||
|
||||
// Put buff in temporary string and clear buff, so that we can handle a call to
|
||||
// reader_set_buffer during evaluation.
|
||||
maybe_t<wcstring> tmp = reader_readline(0);
|
||||
|
@ -2756,7 +2724,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
}
|
||||
case rl::complete:
|
||||
case rl::complete_and_search: {
|
||||
if (!complete_ok) break;
|
||||
if (!conf.complete_ok) break;
|
||||
|
||||
// Use the command line only; it doesn't make sense to complete in any other line.
|
||||
editable_line_t *el = &command_line;
|
||||
|
@ -2996,7 +2964,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
|
||||
// See if this command is valid.
|
||||
parser_test_error_bits_t command_test_result = 0;
|
||||
if (syntax_check_ok) {
|
||||
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) {
|
||||
|
@ -3006,7 +2974,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.
|
||||
if (syntax_check_ok) {
|
||||
if (conf.syntax_check_ok) {
|
||||
command_test_result = reader_shell_test(parser(), el->text());
|
||||
}
|
||||
|
||||
|
@ -3022,7 +2990,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
// Finished command, execute it. Don't add items that start with a leading
|
||||
// space, or if in silent mode (#7230).
|
||||
const editable_line_t *el = &command_line;
|
||||
if (history != nullptr && !silent && may_add_to_history(el->text())) {
|
||||
if (history != nullptr && !conf.in_silent_mode && may_add_to_history(el->text())) {
|
||||
history->add_pending_with_file_detection(el->text(), vars.get_pwd_slash());
|
||||
}
|
||||
rls.finished = true;
|
||||
|
@ -3779,7 +3747,7 @@ bool reader_has_pager_contents() {
|
|||
int reader_reading_interrupted() {
|
||||
int res = reader_test_and_clear_interrupted();
|
||||
reader_data_t *data = current_data_or_null();
|
||||
if (res && data && data->exit_on_interrupt) {
|
||||
if (res && data && data->conf.exit_on_interrupt) {
|
||||
reader_set_end_loop(true);
|
||||
// We handled the interrupt ourselves, our caller doesn't need to handle it.
|
||||
return 0;
|
||||
|
|
61
src/reader.h
61
src/reader.h
|
@ -207,38 +207,43 @@ int reader_reading_interrupted();
|
|||
/// commandline.
|
||||
maybe_t<wcstring> reader_readline(int nchars);
|
||||
|
||||
/// Push a new reader environment.
|
||||
void reader_push(parser_t &parser, const wcstring &name);
|
||||
/// Configuration that we provide to a reader.
|
||||
struct reader_config_t {
|
||||
/// Left prompt command, typically fish_prompt.
|
||||
wcstring left_prompt_cmd{};
|
||||
|
||||
/// Right prompt command, typically fish_right_prompt.
|
||||
wcstring right_prompt_cmd{};
|
||||
|
||||
/// Whether tab completion is OK.
|
||||
bool complete_ok{false};
|
||||
|
||||
/// Whether to perform syntax highlighting.
|
||||
bool highlight_ok{false};
|
||||
|
||||
/// Whether to perform syntax checking before returning.
|
||||
bool syntax_check_ok{false};
|
||||
|
||||
/// Whether to allow autosuggestions.
|
||||
bool autosuggest_ok{false};
|
||||
|
||||
/// Whether to expand abbreviations.
|
||||
bool expand_abbrev_ok{false};
|
||||
|
||||
/// Whether to exit on interrupt (^C).
|
||||
bool exit_on_interrupt{false};
|
||||
|
||||
/// If set, do not show what is typed.
|
||||
bool in_silent_mode{false};
|
||||
};
|
||||
|
||||
/// Push a new reader environment controlled by \p conf.
|
||||
/// If \p history_name is not empty, then use the history with that name.
|
||||
void reader_push(parser_t &parser, const wcstring &history_name, reader_config_t &&conf);
|
||||
|
||||
/// Return to previous reader environment.
|
||||
void reader_pop();
|
||||
|
||||
/// Mark whether tab completion is enabled.
|
||||
void reader_set_complete_ok(bool flag);
|
||||
|
||||
/// Mark whether syntax highlighting is enabled.
|
||||
void reader_set_highlight_ok(bool flag);
|
||||
|
||||
/// Mark whether to check syntax.
|
||||
void reader_set_syntax_check_ok(bool flag);
|
||||
|
||||
/// Specify string of shell commands to be run in order to generate the prompt.
|
||||
void reader_set_left_prompt(const wcstring &prompt);
|
||||
|
||||
/// Specify string of shell commands to be run in order to generate the right prompt.
|
||||
void reader_set_right_prompt(const wcstring &prompt);
|
||||
|
||||
/// Sets whether autosuggesting is allowed.
|
||||
void reader_set_allow_autosuggesting(bool flag);
|
||||
|
||||
/// Sets whether abbreviation expansion is performed.
|
||||
void reader_set_expand_abbreviations(bool flag);
|
||||
|
||||
/// Sets whether the reader should exit on ^C.
|
||||
void reader_set_exit_on_interrupt(bool i);
|
||||
|
||||
void reader_set_silent_status(bool f);
|
||||
|
||||
/// Returns true if the shell is exiting, 0 otherwise.
|
||||
bool shell_is_exiting();
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user