@ 261102.1

260729.3 · 57631684d8dcb7bbf2ec9656f26ed1a8c5bcc021

Escape trailing semicolon in tmux command argument

tmux ends a command at an argument whose last character is ';', so a --border-label ending in one was stored truncated. escapeTmuxSeparator only covered a value that was exactly ';'.

fzf --popup --border-label 'foo;' -> @fzf-border-label was 'foo'

reading declarations

src/tmux.go

@@ -46,11 +46,11 @@ func tmuxFloatingPaneInfo() (int, int, bool) { 	return width, height, true } -// A lone ';' argument is a command separator to tmux, aborting the whole-// command at parse time+// tmux ends a command at an argument ending in ';', so a trailing one is+// escaped. Elsewhere it is not special func escapeTmuxSeparator(str string) string {-	if str == ";" {-		return `\;`+	if strings.HasSuffix(str, ";") {+		return str[:len(str)-1] + `\;` 	} 	return str }

src/tmux_test.go

@@ -18,6 +18,7 @@ func TestEscapeTmuxFormat(t *testing.T) { 		{" C# notes #S ", " C## notes ##S "}, 		{";", `\;`}, 		{"; rm", "; rm"},+		{"C#;", `C##\;`}, 	} { 		if actual := escapeTmuxFormat(tc.given); actual != tc.expected { 			t.Errorf("expected %q, got %q", tc.expected, actual)@@ -35,10 +36,15 @@ func TestEscapeTmuxSeparator(t *testing.T) { 		{"#", "#"}, 		{"#{pane_id}", "#{pane_id}"}, 		{"100%", "100%"},+		// tmux drops a trailing ';' and everything after it, so only that+		// one is escaped 		{";", `\;`},+		{"abc;", `abc\;`},+		{";;", `;\;`},+		{`foo\;`, `foo\\;`}, 		{"; rm", "; rm"}, 		{" ; ", " ; "},-		{";;", ";;"},+		{"a;b", "a;b"}, 	} { 		if actual := escapeTmuxSeparator(tc.given); actual != tc.expected { 			t.Errorf("expected %q, got %q", tc.expected, actual)