Save the screen status more often

The fix for #3481 caused us to save the screen status after external
commands were run, fixing an unnecessary abandon-line when switching
modes. But we may also run commands not directly as part of a binding,
but instead via an on-variable event, e.g. for fish_bind_mode.

Extend this fix to all bindings, guarded by changes to exec_count. Now
any time an external command runs as part of a binding we should pick up
changes to the tty and not abandon the line.

Fixes #3481 again.
This commit is contained in:
ridiculousfish 2022-06-12 12:29:41 -07:00
parent 68f67ff46c
commit 9f2cc4df36
2 changed files with 19 additions and 5 deletions

View File

@ -95,7 +95,7 @@ Interactive improvements
- ``time`` now emits an error if used after the first command in a pipeline (:issue:`8841`).
- ``fish_add_path`` now prints a message for skipped non-existent paths when using the ``-v`` flag (:issue:`8884`).
- Since fish 3.2.0, pressing :kbd:`Control-D` while a command is running would end up inserting a space into the next commandline, which has been fixed (:issue:`8871`).
- A bug that caused multi-line prompts to be moved down a line when switching between insert and normal mode has been fixed (:issue:`3481`).
- A bug that caused multi-line prompts to be moved down a line when pasting or switching modes has been fixed (:issue:`3481`).
- The web-based configuration system no longer strips too many quotes in the abbreviation display (:issue:`8917`, :issue:`8918`).
- Fish started with ``--no-config`` will now use the default keybindings (:issue:`8493`)
- When fish inherits a $USER value that doesn't correspond to the euid, it will now correct it in all cases instead of just when euid is 0 (:issue:`8879`, :issue:`8583`).

View File

@ -738,6 +738,9 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
parser_t &parser() { return *parser_ref; }
const parser_t &parser() const { return *parser_ref; }
/// Convenience cover over exec_count().
uint64_t exec_count() const { return parser().libdata().exec_count; }
reader_data_t(std::shared_ptr<parser_t> parser, std::shared_ptr<history_t> hist,
reader_config_t &&conf)
: conf(std::move(conf)),
@ -3079,10 +3082,6 @@ void reader_data_t::run_input_command_scripts(const wcstring_list_t &cmds) {
wperror(L"tcsetattr");
}
termsize_container_t::shared().invalidate_tty();
// The input command scripts may have changed our tty - ignore any such changes.
// See #3481.
screen.save_status();
}
/// Read normal characters, inserting them into the command line.
@ -3098,6 +3097,10 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
};
command_handler_t empty_handler = {};
// We repaint our prompt if fstat reports the tty as having changed.
// But don't react to tty changes that we initiated, because of commands or
// on-variable events (e.g. for fish_bind_mode). See #3481.
uint64_t last_exec_count = exec_count();
while (accumulated_chars.size() < limit) {
bool allow_commands = (accumulated_chars.empty());
auto evt = inputter.read_char(allow_commands ? normal_handler : empty_handler);
@ -3111,6 +3114,11 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
} else {
accumulated_chars.push_back(evt.get_char());
}
if (last_exec_count != exec_count()) {
last_exec_count = exec_count();
screen.save_status();
}
}
if (!accumulated_chars.empty()) {
@ -3125,6 +3133,12 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
// Since we handled a normal character, we don't have a last command.
rls.last_cmd.reset();
}
if (last_exec_count != exec_count()) {
last_exec_count = exec_count();
screen.save_status();
}
return event_needing_handling;
}