osc: parse OSC 5522 - Kitty clipboard protocol

This PR only adds support for parsing the OSCs. No support has been
added to DECRQM/DECRPM/DECSET/DECRST for mode 5522.
This commit is contained in:
Jeffrey C. Ollie
2026-02-03 13:30:05 -06:00
parent 51897c0cd5
commit 4eee1ac6a9
4 changed files with 736 additions and 0 deletions

View File

@@ -153,8 +153,12 @@ pub const Command = union(Key) {
/// Kitty text sizing protocol (OSC 66)
kitty_text_sizing: parsers.kitty_text_sizing.OSC,
kitty_clipboard_protocol: KittyClipboardProtocol,
pub const SemanticPrompt = parsers.semantic_prompt.Command;
pub const KittyClipboardProtocol = parsers.kitty_clipboard_protocol.OSC;
pub const Key = LibEnum(
if (build_options.c_abi) .c else .zig,
// NOTE: Order matters, see LibEnum documentation.
@@ -182,6 +186,7 @@ pub const Command = union(Key) {
"conemu_xterm_emulation",
"conemu_comment",
"kitty_text_sizing",
"kitty_clipboard_protocol",
},
);
@@ -325,6 +330,7 @@ pub const Parser = struct {
@"21",
@"22",
@"52",
@"55",
@"66",
@"77",
@"104",
@@ -339,8 +345,10 @@ pub const Parser = struct {
@"118",
@"119",
@"133",
@"552",
@"777",
@"1337",
@"5522",
};
pub fn init(alloc: ?Allocator) Parser {
@@ -402,6 +410,7 @@ pub const Parser = struct {
.semantic_prompt,
.show_desktop_notification,
.kitty_text_sizing,
.kitty_clipboard_protocol,
=> {},
}
@@ -569,6 +578,7 @@ pub const Parser = struct {
.@"5" => switch (c) {
';' => if (self.ensureAllocator()) self.writeToFixed(),
'2' => self.state = .@"52",
'5' => self.state = .@"55",
else => self.state = .invalid,
},
@@ -584,6 +594,11 @@ pub const Parser = struct {
else => self.state = .invalid,
},
.@"55" => switch (c) {
'2' => self.state = .@"552",
else => self.state = .invalid,
},
.@"7" => switch (c) {
';' => self.writeToFixed(),
'7' => self.state = .@"77",
@@ -602,12 +617,23 @@ pub const Parser = struct {
else => self.state = .invalid,
},
.@"552" => switch (c) {
'2' => self.state = .@"5522",
else => self.state = .invalid,
},
.@"1337",
=> switch (c) {
';' => self.writeToFixed(),
else => self.state = .invalid,
},
.@"5522",
=> switch (c) {
';' => self.writeToAllocating(),
else => self.state = .invalid,
},
.@"0",
.@"22",
.@"777",
@@ -676,6 +702,8 @@ pub const Parser = struct {
.@"52" => parsers.clipboard_operation.parse(self, terminator_ch),
.@"55" => null,
.@"6" => null,
.@"66" => parsers.kitty_text_sizing.parse(self, terminator_ch),
@@ -684,9 +712,13 @@ pub const Parser = struct {
.@"133" => parsers.semantic_prompt.parse(self, terminator_ch),
.@"552" => null,
.@"777" => parsers.rxvt_extension.parse(self, terminator_ch),
.@"1337" => parsers.iterm2.parse(self, terminator_ch),
.@"5522" => parsers.kitty_clipboard_protocol.parse(self, terminator_ch),
};
}
};

View File

@@ -6,6 +6,7 @@ pub const clipboard_operation = @import("parsers/clipboard_operation.zig");
pub const color = @import("parsers/color.zig");
pub const hyperlink = @import("parsers/hyperlink.zig");
pub const iterm2 = @import("parsers/iterm2.zig");
pub const kitty_clipboard_protocol = @import("parsers/kitty_clipboard_protocol.zig");
pub const kitty_color = @import("parsers/kitty_color.zig");
pub const kitty_text_sizing = @import("parsers/kitty_text_sizing.zig");
pub const mouse_shape = @import("parsers/mouse_shape.zig");

View File

@@ -0,0 +1,702 @@
//! Kitty's clipboard protocol (OSC 5522)
//! Specification: https://sw.kovidgoyal.net/kitty/clipboard/
//! https://rockorager.dev/misc/bracketed-paste-mime/
const std = @import("std");
const build_options = @import("terminal_options");
const assert = @import("../../../quirks.zig").inlineAssert;
const Parser = @import("../../osc.zig").Parser;
const Command = @import("../../osc.zig").Command;
const Terminator = @import("../../osc.zig").Terminator;
const encoding = @import("../encoding.zig");
const log = std.log.scoped(.kitty_clipboard_protocol);
pub const OSC = struct {
/// The raw metadata that was received. It can be parsed by using the `readOption` method.
metadata: []const u8,
/// The raw payload. It may be Base64 encoded, check the `e` option.
payload: ?[]const u8,
/// The terminator that was used in case we need to send a response.
terminator: Terminator,
/// Decode an option from the metadata.
pub fn readOption(self: OSC, comptime key: Option) ?key.Type() {
return key.read(self.metadata);
}
};
pub const Location = enum {
primary,
pub fn init(str: []const u8) ?Location {
return std.meta.stringToEnum(Location, str);
}
};
pub const Operation = enum {
read,
walias,
wdata,
write,
pub fn init(str: []const u8) ?Operation {
return std.meta.stringToEnum(Operation, str);
}
};
pub const Status = enum {
DATA,
DONE,
EBUSY,
EINVAL,
EIO,
ENOSYS,
EPERM,
OK,
pub fn init(str: []const u8) ?Status {
return std.meta.stringToEnum(Status, str);
}
};
pub const Option = enum {
id,
loc,
mime,
name,
password,
pw,
status,
type,
pub fn Type(comptime key: Option) type {
return switch (key) {
.id => []const u8,
.loc => Location,
.mime => []const u8,
.name => []const u8,
.password => []const u8,
.pw => []const u8,
.status => Status,
.type => Operation,
};
}
/// Read the option value from the raw metadata string.
pub fn read(
comptime key: Option,
metadata: []const u8,
) ?key.Type() {
const value: []const u8 = value: {
var pos: usize = 0;
while (pos < metadata.len) {
// skip any whitespace
while (pos < metadata.len and std.ascii.isWhitespace(metadata[pos])) pos += 1;
// bail if we are out of metadata
if (pos >= metadata.len) return null;
if (!std.mem.startsWith(u8, metadata[pos..], @tagName(key))) {
// this isn't the key we are looking for, skip to the next option, or bail if
// there is no next option
pos = std.mem.indexOfScalarPos(u8, metadata, pos, ':') orelse return null;
pos += 1;
continue;
}
// skip past the key
pos += @tagName(key).len;
// skip any whitespace
while (pos < metadata.len and std.ascii.isWhitespace(metadata[pos])) pos += 1;
// bail if we are out of metadata
if (pos >= metadata.len) return null;
// a valid option has an '='
if (metadata[pos] != '=') return null;
// the end of the value is bounded by a ':' or the end of the metadata
const end = std.mem.indexOfScalarPos(u8, metadata, pos, ':') orelse metadata.len;
const start = pos + 1;
// strip any leading or trailing whitespace
break :value std.mem.trim(u8, metadata[start..end], &std.ascii.whitespace);
}
// the key was not found
return null;
};
// return the parsed value
return switch (key) {
.id => parseIdentifier(value),
.loc => .init(value),
.mime => value,
.name => value,
.password => value,
.pw => value,
.status => .init(value),
.type => .init(value),
};
}
};
/// Characters that are valid in identifiers.
const valid_identifier_characters: []const u8 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_+.";
fn isValidIdentifier(str: []const u8) bool {
if (str.len == 0) return false;
return std.mem.indexOfNone(u8, str, valid_identifier_characters) == null;
}
fn parseIdentifier(str: []const u8) ?[]const u8 {
if (isValidIdentifier(str)) return str;
return null;
}
pub fn parse(parser: *Parser, terminator_ch: ?u8) ?*Command {
assert(parser.state == .@"5522");
const writer = parser.writer orelse {
parser.state = .invalid;
return null;
};
const data = writer.buffered();
const metadata: []const u8, const payload: ?[]const u8 = result: {
const start = std.mem.indexOfScalar(u8, data, ';') orelse break :result .{ data, null };
break :result .{ data[0..start], data[start + 1 .. data.len] };
};
parser.command = .{
.kitty_clipboard_protocol = .{
.metadata = metadata,
.payload = payload,
.terminator = .init(terminator_ch),
},
};
return &parser.command;
}
test "OSC: 5522: empty metadata and missing payload" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("", cmd.kitty_clipboard_protocol.metadata);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.type) == null);
}
test "OSC: 5522: empty metadata and empty payload" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;;";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("", cmd.kitty_clipboard_protocol.metadata);
try testing.expectEqualStrings("", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.type) == null);
}
test "OSC: 5522: non-empty metadata and payload" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read;dGV4dC9wbGFpbg==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("type=read", cmd.kitty_clipboard_protocol.metadata);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type));
}
test "OSC: 5522: empty id" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;id=";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
}
test "OSC: 5522: valid id" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;id=5c076ad9-d36f-4705-847b-d4dbf356cc0d";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("5c076ad9-d36f-4705-847b-d4dbf356cc0d", cmd.kitty_clipboard_protocol.readOption(.id).?);
}
test "OSC: 5522: invalid id" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;id=*42*";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
}
test "OSC: 5522: invalid status" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;status=BOBR";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
}
test "OSC: 5522: valid status" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;status=DONE";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqual(.DONE, cmd.kitty_clipboard_protocol.readOption(.status).?);
}
test "OSC: 5522: invalid location" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;loc=bobr";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
}
test "OSC: 5522: valid location" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;loc=primary";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqual(.primary, cmd.kitty_clipboard_protocol.readOption(.loc).?);
}
test "OSC: 5522: password 1" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;pw=R2hvc3R0eQ==:name=Qk9CUiBLVVJXQQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("R2hvc3R0eQ==", cmd.kitty_clipboard_protocol.readOption(.pw).?);
try testing.expectEqualStrings("Qk9CUiBLVVJXQQ==", cmd.kitty_clipboard_protocol.readOption(.name).?);
}
test "OSC: 5522: password 2" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;password=R2hvc3R0eQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("R2hvc3R0eQ==", cmd.kitty_clipboard_protocol.readOption(.password).?);
}
test "OSC: 5522: example 1" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=OK";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.OK, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 2" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:mime=dGV4dC9wbGFpbg==;R2hvc3R0eQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("R2hvc3R0eQ==", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 3" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=OK";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.OK, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 4" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=write";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.write, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 5" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=wdata:mime=dGV4dC9wbGFpbg==;R2hvc3R0eQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("R2hvc3R0eQ==", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.wdata, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 6" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=wdata";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.wdata, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 7" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=write:status=DONE";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.DONE, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.write, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 8" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=write:status=EPERM";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.EPERM, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.write, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 9" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=walias:mime=dGV4dC9wbGFpbg==;dGV4dC9odG1sIGFwcGxpY2F0aW9uL2pzb24=";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("dGV4dC9odG1sIGFwcGxpY2F0aW9uL2pzb24=", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.walias, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 10" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=OK:password=Qk9CUiBLVVJXQQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expectEqualStrings("Qk9CUiBLVVJXQQ==", cmd.kitty_clipboard_protocol.readOption(.password).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.OK, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 11" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=DATA:mime=dGV4dC9wbGFpbg==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.DATA, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 12" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:mime=dGV4dC9wbGFpbg==:password=Qk9CUiBLVVJXQQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expectEqualStrings("Qk9CUiBLVVJXQQ==", cmd.kitty_clipboard_protocol.readOption(.password).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.status) == null);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 13" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=OK";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.OK, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 14" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=DATA:mime=dGV4dC9wbGFpbg==;Qk9CUiBLVVJXQQ==";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expectEqualStrings("Qk9CUiBLVVJXQQ==", cmd.kitty_clipboard_protocol.payload.?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expectEqualStrings("dGV4dC9wbGFpbg==", cmd.kitty_clipboard_protocol.readOption(.mime).?);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.DATA, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}
test "OSC: 5522: example 15" {
const testing = std.testing;
var p: Parser = .init(testing.allocator);
defer p.deinit();
const input = "5522;type=read:status=OK";
for (input) |ch| p.next(ch);
const cmd = p.end('\x1b').?.*;
try testing.expect(cmd == .kitty_clipboard_protocol);
try testing.expect(cmd.kitty_clipboard_protocol.payload == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.id) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.loc) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.mime) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.name) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.password) == null);
try testing.expect(cmd.kitty_clipboard_protocol.readOption(.pw) == null);
try testing.expectEqual(.OK, cmd.kitty_clipboard_protocol.readOption(.status).?);
try testing.expectEqual(.read, cmd.kitty_clipboard_protocol.readOption(.type).?);
}

View File

@@ -2047,6 +2047,7 @@ pub fn Stream(comptime Handler: type) type {
.conemu_output_environment_variable,
.conemu_run_process,
.kitty_text_sizing,
.kitty_clipboard_protocol,
=> {
log.debug("unimplemented OSC callback: {}", .{cmd});
},