From cdf81b610d9fcd922ad2598fb12cc0d62cbd542d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 3 Sep 2023 14:00:56 -0700 Subject: [PATCH] terminal: mark prompt continuation lines, end prompt clear at first prompt --- src/terminal/Screen.zig | 7 ++++--- src/terminal/Terminal.zig | 17 +++++++++++++---- src/terminal/stream.zig | 13 +++++++------ src/termio/Exec.zig | 5 +++++ 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 532bb352e..98b6edc4a 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -155,13 +155,14 @@ pub const RowHeader = struct { /// This is a prompt line, meaning it only contains the shell prompt. /// For poorly behaving shells, this may also be the input. prompt = 1, + prompt_continuation = 2, /// This line contains the input area. We don't currently track /// where this actually is in the line, so we just assume it is somewhere. - input = 2, + input = 3, /// This line is the start of command output. - command = 3, + command = 4, }; }; @@ -1762,7 +1763,7 @@ fn jumpPrompt(self: *Screen, delta: isize) bool { while (y >= 0 and y <= max_y and delta_rem > 0) : (y += step) { const row = self.getRow(.{ .screen = @intCast(y) }); switch (row.getSemanticPrompt()) { - .prompt, .input => delta_rem -= 1, + .prompt, .prompt_continuation, .input => delta_rem -= 1, .command, .unknown => {}, } } diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 025167d74..bd32dbb83 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -40,6 +40,7 @@ pub const ScreenType = enum { /// See: https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md pub const SemanticPrompt = enum { prompt, + prompt_continuation, input, command, }; @@ -361,12 +362,18 @@ fn clearPromptForResize(self: *Terminal) void { const real_y = self.screen.cursor.y - y; const row = self.screen.getRow(.{ .active = real_y }); switch (row.getSemanticPrompt()) { - // If we're at a prompt or input area, then we are at a 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. - .prompt, - .input, - => found = real_y, + .input => found = real_y, + + // If we find the prompt then we're done. We are also done + // if we find any prompt continuation, because the shells + // that send this currently (zsh) cannot redraw every line. + .prompt, .prompt_continuation => { + found = real_y; + break; + }, // If we have command output, then we're most certainly not // at a prompt. Break out of the loop. @@ -1535,6 +1542,7 @@ pub fn markSemanticPrompt(self: *Terminal, p: SemanticPrompt) void { const row = self.screen.getRow(.{ .active = self.screen.cursor.y }); row.setSemanticPrompt(switch (p) { .prompt => .prompt, + .prompt_continuation => .prompt_continuation, .input => .input, .command => .command, }); @@ -1557,6 +1565,7 @@ pub fn cursorIsAtPrompt(self: *Terminal) bool { switch (row.getSemanticPrompt()) { // If we're at a prompt or input area, then we are at a prompt. .prompt, + .prompt_continuation, .input, => return true, diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 57dc801b7..c922df8f4 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -53,10 +53,10 @@ pub fn Stream(comptime Handler: type) type { // log.debug("char: {c}", .{c}); const actions = self.parser.next(c); for (actions) |action_opt| { - // if (action_opt) |action| { - // if (action != .print) - // log.info("action: {}", .{action}); - // } + if (action_opt) |action| { + if (action != .print and action == .osc_dispatch) + log.info("action: {}", .{action}); + } switch (action_opt orelse continue) { .print => |p| if (@hasDecl(T, "print")) try self.handler.print(p), .execute => |code| try self.execute(code), @@ -802,8 +802,9 @@ pub fn Stream(comptime Handler: type) type { }, .prompt_start => |v| { - if (@hasDecl(T, "promptStart")) { - try self.handler.promptStart(v.aid, v.redraw); + if (@hasDecl(T, "promptStart")) switch (v.kind) { + .primary, .right => try self.handler.promptStart(v.aid, v.redraw), + .continuation => try self.handler.promptContinuation(v.aid), } else log.warn("unimplemented OSC callback: {}", .{cmd}); }, diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 021e58fe8..175e7fa0d 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1623,6 +1623,11 @@ const StreamHandler = struct { self.terminal.flags.shell_redraws_prompt = redraw; } + pub fn promptContinuation(self: *StreamHandler, aid: ?[]const u8) !void { + _ = aid; + self.terminal.markSemanticPrompt(.prompt_continuation); + } + pub fn promptEnd(self: *StreamHandler) !void { self.terminal.markSemanticPrompt(.input); }