From db275b7770cc527ea02f950f3990e2e94a815f54 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 16 Aug 2026 13:33:46 +0800 Subject: [PATCH] docs(cli): say that a newline inside send's TEXT presses Enter $ tty7 send %1 "$(printf 'echo ONE\necho TWO')" ... echo ONE ONE ... echo TWO <- typed, waiting Correct for a verb whose first line is "types TEXT into the pane exactly as a keyboard would" -- typing a newline is pressing Enter. But `--enter` is documented right next to it as the way to submit, which reads as though TEXT alone cannot, and an orchestrator passing along text it did not write runs it a line at a time. So `--help` and the reference now say it, with the shape it takes: the text before the newline runs, and what follows is left typed at the prompt it asked for. A test pins the bytes -- neither stripped nor split into two writes -- so the pages and the behaviour cannot drift apart. Found while feeding a pane input it does not expect. Three neighbours came through that unchanged and are worth recording: invalid UTF-8 in output becomes U+FFFD with correct recovery (`\xc3\x28` is one replacement and a literal `(`), `capture --json` stays valid JSON over it, and an OSC title carrying bad bytes is folded before storage so `machine.json` stays parseable and the tab table stays aligned. --- crates/tty7-cli/src/commands.rs | 22 ++++++++++++++++++++++ crates/tty7-cli/src/keys.rs | 5 +++++ docs/cli/reference.mdx | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/crates/tty7-cli/src/commands.rs b/crates/tty7-cli/src/commands.rs index a9de55ed..e8c5f59d 100644 --- a/crates/tty7-cli/src/commands.rs +++ b/crates/tty7-cli/src/commands.rs @@ -2625,6 +2625,28 @@ mod tests { assert_eq!(backend.sent, vec![(3, b"echo hi".to_vec())]); } + /// A newline in TEXT goes out as a newline, which a shell runs. + /// + /// `--enter` exists to submit, so it reads as though TEXT alone cannot — + /// and text that came from somewhere else then runs a line at a time. The + /// behaviour is right for a verb that types what a keyboard would; what it + /// needs is to be written down, and both the `--help` and the reference + /// now say so. This keeps the bytes matching what they say. + #[test] + fn a_newline_in_the_text_is_sent_as_one() { + let mut backend = mock(); + run_cli( + &["tty7", "send", "%1", "deploy\nyes"], + &Context::default(), + &mut backend, + ); + assert_eq!( + backend.sent, + vec![(1, b"deploy\nyes".to_vec())], + "neither stripped nor split into two writes" + ); + } + /// The keystrokes text cannot express. Each goes out as its own write, in /// the order given, because a pane reads them as separate key events — /// which is what walking a menu and then confirming it requires. diff --git a/crates/tty7-cli/src/keys.rs b/crates/tty7-cli/src/keys.rs index 6762cf05..4c27d0f4 100644 --- a/crates/tty7-cli/src/keys.rs +++ b/crates/tty7-cli/src/keys.rs @@ -83,6 +83,11 @@ pub fn send_long_help() -> String { let aliases: Vec<&str> = ALIASES.iter().map(|(from, _)| *from).collect(); format!( "Types TEXT into the pane exactly as a keyboard would.\n\n\ + Exactly as a keyboard would includes the newlines: one inside TEXT is \ + Enter, and runs what stands before it. `send %1 $'deploy\\nyes'` runs \ + `deploy` and leaves `yes` typed at the prompt it asked. Worth knowing \ + before passing along text somebody else wrote — --enter is the way to \ + submit on purpose.\n\n\ --key sends a keystroke rather than characters, which is what a pane wants once \ something is already running in it: answering a prompt that only takes arrow keys, \ closing a TUI with escape, stopping a build with C-c. Repeat it for a sequence.\n\n\ diff --git a/docs/cli/reference.mdx b/docs/cli/reference.mdx index 06a9837e..445f0f2a 100644 --- a/docs/cli/reference.mdx +++ b/docs/cli/reference.mdx @@ -134,6 +134,11 @@ pane — while text that merely starts with `%` (`%s/foo/bar/`, `%!sort`) types as given, as does anything unmarked that is not a plain number (`3x`, `+5`). To type an address-shaped string, name the pane as well: `tty7 send %42 %3x`. +A newline inside `TEXT` is Enter, because typing one is. `tty7 send %1 +$'deploy\nyes'` runs `deploy` and leaves `yes` typed at the prompt it asked +for — so text that came from somewhere else runs a line at a time, and `--enter` +is the way to submit on purpose. + `--key` presses a key instead of typing characters, which is what a pane wants once something is already running in it: answering a prompt that only takes arrow keys, closing a TUI with `escape`, stopping a build with `C-c`. Repeat it