From a9d7e0eb7f3b87fd8c47b2fabd29a1bc53e342fb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 15 Aug 2023 21:41:44 -0700 Subject: [PATCH] terminal: parse kitty query, push, pop keyboard flags --- src/terminal/Screen.zig | 4 ++++ src/terminal/stream.zig | 43 +++++++++++++++++++++++++++++++++++++++++ src/termio/Exec.zig | 28 +++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 42394f7f7..8da118584 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -58,6 +58,7 @@ const utf8proc = @import("utf8proc"); const trace = @import("tracy").trace; const sgr = @import("sgr.zig"); const color = @import("color.zig"); +const kitty = @import("kitty.zig"); const point = @import("point.zig"); const CircBuf = @import("circ_buf.zig").CircBuf; const Selection = @import("Selection.zig"); @@ -861,6 +862,9 @@ saved_cursor: Cursor = .{}, /// The selection for this screen (if any). selection: ?Selection = null, +/// The kitty keyboard settings. +kitty_keyboard: kitty.KeyFlagStack = .{}, + /// Initialize a new screen. pub fn init( alloc: Allocator, diff --git a/src/terminal/stream.zig b/src/terminal/stream.zig index 0ddfbb5bf..a152b1bc9 100644 --- a/src/terminal/stream.zig +++ b/src/terminal/stream.zig @@ -4,6 +4,7 @@ const Parser = @import("Parser.zig"); const ansi = @import("ansi.zig"); const charsets = @import("charsets.zig"); const csi = @import("csi.zig"); +const kitty = @import("kitty.zig"); const modes = @import("modes.zig"); const osc = @import("osc.zig"); const sgr = @import("sgr.zig"); @@ -644,6 +645,48 @@ pub fn Stream(comptime Handler: type) type { ), }, + // Kitty keyboard protocol + 'u' => switch (action.intermediates.len) { + 1 => switch (action.intermediates[0]) { + '?' => if (@hasDecl(T, "queryKittyKeyboard")) { + try self.handler.queryKittyKeyboard(); + }, + + '>' => if (@hasDecl(T, "pushKittyKeyboard")) push: { + const flags: u5 = if (action.params.len == 1) + std.math.cast(u5, action.params[0]) orelse { + log.warn("invalid pushKittyKeyboard command: {}", .{action}); + break :push; + } + else + 0; + + try self.handler.pushKittyKeyboard(@bitCast(flags)); + }, + + '<' => if (@hasDecl(T, "popKittyKeyboard")) { + const number: u16 = if (action.params.len == 1) + action.params[0] + else + 0; + + try self.handler.popKittyKeyboard(number); + }, + + '=' => @panic("TODO! DO NOT MERGE"), + + else => log.warn( + "unknown CSI s with intermediate: {}", + .{action}, + ), + }, + + else => log.warn( + "ignoring unimplemented CSI u: {}", + .{action}, + ), + }, + // ICH - Insert Blanks // TODO: test '@' => if (@hasDecl(T, "insertBlanks")) switch (action.params.len) { diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index d4d858957..91b955753 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -1407,6 +1407,34 @@ const StreamHandler = struct { self.terminal.fullReset(); } + pub fn queryKittyKeyboard(self: *StreamHandler) !void { + // log.debug("querying kitty keyboard mode", .{}); + var data: termio.Message.WriteReq.Small.Array = undefined; + const resp = try std.fmt.bufPrint(&data, "\x1b[?{}u", .{ + self.terminal.screen.kitty_keyboard.current().int(), + }); + + self.messageWriter(.{ + .write_small = .{ + .data = data, + .len = @intCast(resp.len), + }, + }); + } + + pub fn pushKittyKeyboard( + self: *StreamHandler, + flags: terminal.kitty.KeyFlags, + ) !void { + // log.debug("pushing kitty keyboard mode: {}", .{flags}); + self.terminal.screen.kitty_keyboard.push(flags); + } + + pub fn popKittyKeyboard(self: *StreamHandler, n: u16) !void { + // log.debug("popping kitty keyboard mode", .{}); + self.terminal.screen.kitty_keyboard.pop(@intCast(n)); + } + //------------------------------------------------------------------------- // OSC