diff options
Diffstat (limited to 'src/tty')
| -rw-r--r-- | src/tty/tty.zig | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 1d7ff415..eabbbe22 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -1505,8 +1505,11 @@ const Shell = struct { core.quit = true; return true; }, - .focus_in => {}, - .focus_out => core.update(.pointer_leave), + .focus_in => core.update(.{ .focus = true }), + .focus_out => { + core.update(.pointer_leave); + core.update(.{ .focus = false }); + }, .winsize => |ws| { s.vx.resize(s.gpa, s.tty.writer(), ws) catch {}; if (comptime pardes.pdf_enabled) @@ -2244,6 +2247,44 @@ test "a terminal pane gets function keys as their sequences and lone modifiers n try std.testing.expectEqualStrings("\x1bOR\x1b[15~\x1b[2~\x1bOR\x1b[Ah", written.written()); } +test "the terminal's keys reach a program as its cursor keys' mode and keyboard flags say" { + const gpa = std.testing.allocator; + const core = try pardes.Pardes.init(gpa, .{ .tty_only = true }); + defer core.deinit(); + core.panes[0].?.body.mode = .tty; + while (core.nextEffect()) |_| {} + var written: std.Io.Writer.Allocating = .init(gpa); + defer written.deinit(); + // What the outer terminal sends, what the program asked for, and what + // it should read. + const Case = struct { modes: []const u8, in: []const u8, sent: []const u8 }; + const cases = [_]Case{ + .{ .modes = "", .in = "\x1b[A\x1b[H\x1bOP\x1b[15~", .sent = "\x1b[A\x1b[H\x1bOP\x1b[15~" }, + .{ .modes = "\x1b[?1h", .in = "\x1b[A\x1b[F\x1b[1;5D", .sent = "\x1bOA\x1bOF\x1b[1;5D" }, + .{ .modes = "\x1b[?1l\x1b[>7u", .in = "\x1b[99;5u\x1b[97;3u\x1b[A", .sent = "\x1b[99;5u\x1b[97;3u\x1b[1;1:1A" }, + }; + for (cases) |case| { + core.update(.{ .output = .{ .pane = 0, .bytes = case.modes } }); + while (core.nextEffect()) |_| {} + var parser: vaxis.Parser = .{}; + var bytes = case.in; + while (bytes.len > 0) { + const result = try parser.parse(bytes, gpa); + if (result.n == 0) break; + bytes = bytes[result.n..]; + if (result.event) |event| switch (event) { + .key_press => |key| core.update(vaxis_input.keyEvent(key)), + else => {}, + }; + } + written.clearRetainingCapacity(); + while (core.nextEffect()) |effect| { + if (effect == .write) try written.writer.writeAll(effect.write.bytes.slice()); + } + try std.testing.expectEqualStrings(case.sent, written.written()); + } +} + test "keypad Enter matches Return for editor input terminal writes and paste" { for ([_]u21{ vaxis.Key.enter, vaxis.Key.kp_enter }) |codepoint| { const key: vaxis.Key = .{ .codepoint = codepoint }; @@ -2297,6 +2338,8 @@ fn mouseEvent(m: vaxis.Mouse) ?pardes.Event { .col = @intCast(m.col), .row = @intCast(m.row), .ctrl = m.mods.ctrl, + .shift = m.mods.shift, + .alt = m.mods.alt, } }; } @@ -2708,8 +2751,11 @@ const Attach = struct { switch (event) { .nop, .wake, .fs_ready, .lsp_done, .lsp_status, .pipe_done, .pty_read, .pty_eof, .files_changed => {}, .quit => return .none, - .focus_in => {}, - .focus_out => return a.send(.pointer_leave), + .focus_in => return a.send(.{ .focus = true }), + .focus_out => { + if (a.send(.pointer_leave)) |end| return end; + return a.send(.{ .focus = false }); + }, .winsize => |ws| { a.vx.resize(a.gpa, a.tty.writer(), ws) catch {}; a.dirty = true; |
