From 82756f8b4c6643debc7f3a7b08b215fdb27a11ee Mon Sep 17 00:00:00 2001 From: Jon Parise Date: Mon, 16 Dec 2024 20:08:52 -0500 Subject: [PATCH] terminal: handle consecutive .input's in clearPrompt Our semantic prompts are row-based, so the last prompt marker set on a row "wins". In the case of at least our bash shell integration, this means that consecutive prompt lines will all be marked as .input (OSC 133;B -- end-of-prompt, start of input). Previously, clearPrompt() identified the current prompt's "area" by searching upward from the current row until it encounters a .prompt marker or some command output. In the bash case, .prompt is never the dominant ("last") marker, so clearPrompt() would aggressively clear all immediately preceding consecutive prompts. With this change, we'll stop searching upwards when we encounter some command output, a .prompt marker, _or another .input marker_. That last case prevents clearPrompt() from unintentionally clearing earlier prompt lines. There may be improvements we can make to the way that our bash shell integration emits semantic prompt markers, but I think this logic is generally sound for all cases, and it specifically improves the current bash prompt-clearing experience. --- src/terminal/Screen.zig | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 7d7759130..42bcd54c0 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -1315,8 +1315,13 @@ pub fn clearPrompt(self: *Screen) void { switch (row.semantic_prompt) { // We are at a prompt but we're not at the start of the prompt. // We mark our found value and continue because the prompt - // may be multi-line. - .input => found = p, + // may be multi-line, unless this is the second time we've + // seen an .input marker, in which case we've run into an + // earlier prompt. + .input => { + if (found != null) break; + found = p; + }, // If we find the prompt then we're done. We are also done // if we find any prompt continuation, because the shells @@ -3565,6 +3570,32 @@ test "Screen: clearPrompt continuation" { } } +test "Screen: clearPrompt consecutive prompts" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 0); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL"; + try s.testWriteString(str); + + // Set both rows to be prompts + { + s.cursorAbsolute(0, 1); + s.cursor.page_row.semantic_prompt = .input; + s.cursorAbsolute(0, 2); + s.cursor.page_row.semantic_prompt = .input; + } + + s.clearPrompt(); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + try testing.expectEqualStrings("1ABCD\n2EFGH", contents); + } +} + test "Screen: clearPrompt no prompt" { const testing = std.testing; const alloc = testing.allocator;