mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-17 04:52:47 +00:00
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:
@@ -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),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
|
||||
702
src/terminal/osc/parsers/kitty_clipboard_protocol.zig
Normal file
702
src/terminal/osc/parsers/kitty_clipboard_protocol.zig
Normal 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).?);
|
||||
}
|
||||
@@ -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});
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user