builtin read: don't enable TTY protocols while echo is off

When I run "read" and press enter on the foot terminal, I see a "^[[I"
echoed in the TTY.  This is because

1. builtin read creates a TtyHandoff and runs enable_tty_protocols()
2. it runs Reader::readline(), which creates another TtyHandoff.
3. before Reader::readline() returns, it unsets shell modes
   (turning ECHO back on). It also drops its TtyHandoff,
   which enables TTY protocols again.
4. Enabling focus reporting causes this terminal to send
   focus-in event immediately.

This is our fault; we should not have TTY protocols enabled while
ECHO is on.

Fix this by removing the first TtyHandoff (which seems redundant),
meaning that the second one will not try to re-enable protocols.
This commit is contained in:
Johannes Altmanninger
2025-12-19 15:44:49 +01:00
parent 765305d0e4
commit 5545c648d9

View File

@@ -18,13 +18,11 @@
use crate::parse_execution::varname_error;
use crate::reader::ReaderConfig;
use crate::reader::commandline_set_buffer;
use crate::reader::reader_save_screen_state;
use crate::reader::{reader_pop, reader_push, reader_readline, set_shell_modes_temporarily};
use crate::tokenizer::TOK_ACCEPT_UNFINISHED;
use crate::tokenizer::TOK_ARGUMENT_LIST;
use crate::tokenizer::Tok;
use crate::tokenizer::Tokenizer;
use crate::tty_handoff::TtyHandoff;
use crate::wcstringutil::split_about;
use crate::wcstringutil::split_string_tok;
use crate::wutil;
@@ -292,8 +290,6 @@ fn read_interactive(
let mline = {
let _interactive = parser.push_scope(|s| s.is_interactive = true);
let mut scoped_handoff = TtyHandoff::new(reader_save_screen_state);
scoped_handoff.enable_tty_protocols();
reader_readline(parser, old_modes, nchars)
};
if let Some(line) = mline {