Skip to content

feat(terminal): send text to the Claude pane (:ClaudeCodeSendText) (#197)#272

Merged
ThomasK33 merged 1 commit into
mainfrom
feat/send-text-to-terminal
Jun 9, 2026
Merged

feat(terminal): send text to the Claude pane (:ClaudeCodeSendText) (#197)#272
ThomasK33 merged 1 commit into
mainfrom
feat/send-text-to-terminal

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Adds a way to send arbitrary text to the currently-open Claude Code terminal pane, as if typed at the prompt — the feature requested in #197 (for scripting and keymaps).

  • :ClaudeCodeSendText {text} — types {text} into the open Claude terminal and submits it. :ClaudeCodeSendText! (bang) inserts without submitting.
  • require("claudecode.terminal").send_to_terminal(text, opts) — the programmatic primitive (opts.submit default true, opts.focus default false).

It writes to the terminal's job channel with vim.fn.chansend; a trailing carriage return (\r) is what submits at Claude's prompt. No window focus is required, which is the point for scripting.

Closes #197.

How it works

chansend into a Neovim :terminal writes to the same PTY master Neovim uses when forwarding a real keypress, so chansend(chan, "\r") is byte-identical to pressing Enter and submits. (This is not affected by anthropics/claude-code#15553, which is about VS Code's terminal.sendText — a different layer.)

Implementation notes:

  • Channel resolved from the plugin's own get_active_terminal_bufnr()b:terminal_job_id, with a bo.channel fallback for a recovered terminal whose module-level job id was lost.
  • Gated on nvim_buf_is_valid + a resolvable, non-zero channel; the chansend write result is honored (a closed channel → warn + false), so the boolean return is truthful.
  • Multi-line text is wrapped in one bracketed-paste block (ESC[200~ … ESC[201~) and line endings are normalized, so interior newlines/CRs don't fire premature submits; the submit \r is sent after the closing marker. (chansend bypasses vim.paste, so the fix_streamed_paste shim is irrelevant here.)
  • In-editor providers only (native/snacks). external/none run Claude outside Neovim — there's no pane to write to, so the call warns and returns false (same structural limit as focus_after_send; see the ClaudeCodeSendComplete event for focusing an out-of-editor session).

Verification

Verified end-to-end against the real Claude CLI (2.1.169) driving the plugin's native terminal in an isolated PTY (cursor never left a separate buffer — no focus needed):

Scenario Result
:ClaudeCodeSendText What is 7 times 6? … submitted → Claude replied 42
:ClaudeCodeSendText! this is a draft … inserted into the prompt, not submitted
send_to_terminal("…\nWhat is 9 plus 10?") sent as one bracketed-paste block → submitted once → 19

Tests: 22 new unit tests (tests/unit/terminal/send_text_spec.lua, tests/unit/claudecode_send_text_command_spec.lua) covering single/multi-line, submit/bang, CRLF + lone-CR normalization, the terminal_job_idbo.channel fallback (incl. job id 0), nil/stale channel, focus, and the external/none warnings. mise run all is green (608 tests, lint + format clean).

Relates to #234 (not closed here)

#234 ("send prompt with selection") builds directly on this primitive, and the content composition works — live testing confirmed that broadcasting the selection's at_mention (Claude inserts @file#Lx-y) and then chansend-ing the prompt produces the correct @file#Lx-y <prompt> and Claude reads the file. However, an @-mention in Claude's input box (whether MCP-inserted or typed) absorbs the immediately-following \r, so reliable auto-submit needs a separate, timing-gapped \r after the prompt is inserted. That extra timing dependency (against an async TUI, plus a dependency on undocumented CLI mention-insertion behavior) is fragile enough that I've kept it out of this PR rather than bundle a flaky auto-submit. This PR provides the clean primitive #234 needs; a focused follow-up can layer the selection+prompt UX (e.g. :ClaudeCodeSendWithPrompt via vim.ui.input) on top, with the 2-stage submit and a configurable delay.

Notes

  • :ClaudeCodeSendText sends to the currently-open pane; it does not auto-launch Claude (open it with :ClaudeCode first). This keeps behavior predictable — a deferred send into a just-spawned CLI that isn't input-ready yet would silently drop.

🤖 Generated with Claude Code

…ne (#197)

Add `require("claudecode.terminal").send_to_terminal(text, opts)` and a
`:ClaudeCodeSendText {text}` command that write text into the running Claude
terminal's job channel via `chansend`, as if typed at the prompt. A trailing
carriage return submits by default; `:ClaudeCodeSendText!` (and `opts.submit =
false`) insert without submitting. Multi-line text is sent as a single
bracketed-paste block (line endings normalized) so interior newlines don't fire
premature submits.

Works with the in-editor `native`/`snacks` providers; `external`/`none` run
Claude outside Neovim, so there is no pane to write to and the call warns and
returns false. The send is gated on `nvim_buf_is_valid` and a resolvable job
channel (`b:terminal_job_id` with a `bo.channel` fallback for recovered
terminals), and the `chansend` write is honored (closed channel -> false).

Verified live against the real Claude CLI (2.1.169): single-line insert+submit,
bang insert-only, and multi-line single-submit. 22 new unit tests.

Change-Id: I2f68c38c76cf5b07cf6da1ba4c3b553252c5c0fe
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@claude review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33 ThomasK33 merged commit 254203b into main Jun 9, 2026
2 checks passed
@ThomasK33 ThomasK33 deleted the feat/send-text-to-terminal branch June 9, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add Neovim command to "send text to the currently-open claude code pane"

1 participant