From 9a00c2feaac7cbbddc653d59dfcc104e2ea48861 Mon Sep 17 00:00:00 2001 From: "Claudia[bot]" <4437565+Claudia[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2026 23:31:06 +0200 Subject: [PATCH] fix(tmux): drop a leading blank line made of spaces, not only line breaks `" \nfix it\r"` still pasted a blank first line, because the leading strip only matched `\n`. /^\s*\n/ drops everything up to the last leading line break, mirroring the trimEnd() at the other end, and the first real line keeps its indentation. The test row fails with the old pattern. Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com> Co-Authored-By: Claude --- src/tmux-manager.ts | 11 ++++++++--- test/tmux-submit-paste.test.ts | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tmux-manager.ts b/src/tmux-manager.ts index 9e2fd296..6c2cde4d 100644 --- a/src/tmux-manager.ts +++ b/src/tmux-manager.ts @@ -3863,9 +3863,14 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer { try { const hasCarriageReturn = input.includes('\r'); - // Leading and trailing line breaks are dropped, so `"\nfix it\r"` does not paste - // an empty first line (nor `"fix it\n\r"` an empty last one). - const textPart = input.replace(/\r/g, '').replace(/^\n+/, '').trimEnd(); + // Leading and trailing blank lines are dropped, so neither `"\nfix it\r"` nor + // `" \nfix it\r"` pastes an empty first line (nor `"fix it\n\r"` an empty last + // one). The leading match ends at a line break, so the first real line keeps its + // indentation. + const textPart = input + .replace(/\r/g, '') + .replace(/^\s*\n/, '') + .trimEnd(); if (textPart && hasCarriageReturn) { // Send text first, then Enter as a SEPARATE tmux command after a short delay. diff --git a/test/tmux-submit-paste.test.ts b/test/tmux-submit-paste.test.ts index e76cf820..39eb1d55 100644 --- a/test/tmux-submit-paste.test.ts +++ b/test/tmux-submit-paste.test.ts @@ -261,6 +261,11 @@ describe('sendInput line breaks', () => { await multi.sendInput('s1', '\r\n\r\none\ntwo\r'); expect(bufferText(multi.ran[0])).toBe('one\ntwo'); + // A blank first line made of spaces is dropped too; the first real line keeps its indentation. + const spaced = managerWithSession(); + await spaced.sendInput('s1', ' \n\t\n fix it\nnow\r'); + expect(bufferText(spaced.ran[0])).toBe(' fix it\nnow'); + // Without an Enter, what is left is one line, so it is typed like any other. const typed = managerWithSession(); await typed.sendInput('s1', '\n\njust type');