mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
terminal: redo trailing state capture in OSC parser (#11873)
Trailing state capture now is encapsulated in a struct `Capture` and all parsers access the data via `p.capture.trailing()` rather than directly from the writer. This is primarily to prep for the OSC parser to be able to capture the entire sequence (not just the trailing part) so we can setup libghostty for fallback handlers so libghostty implementers can have custom OSC behaviors. But, it has the benefit of making our OSC parser much cleaner too. I'm doing some benchmarks now...
This commit is contained in:
@@ -301,12 +301,10 @@ pub const Parser = struct {
|
||||
|
||||
/// Buffer for temporary storage of OSC data
|
||||
buffer: [MAX_BUF]u8,
|
||||
/// Fixed writer for accumulating OSC data
|
||||
fixed: ?std.Io.Writer,
|
||||
/// Allocating writer for accumulating OSC data
|
||||
allocating: ?std.Io.Writer.Allocating,
|
||||
/// Pointer to the active writer for accumulating OSC data
|
||||
writer: ?*std.Io.Writer,
|
||||
|
||||
/// Capture state. If this is set then we're actively capturing the
|
||||
/// bytes coming into the parser.
|
||||
capture: ?Capture,
|
||||
|
||||
/// The command that is the result of parsing.
|
||||
command: Command,
|
||||
@@ -369,9 +367,7 @@ pub const Parser = struct {
|
||||
var result: Parser = .{
|
||||
.alloc = alloc,
|
||||
.state = .start,
|
||||
.fixed = null,
|
||||
.allocating = null,
|
||||
.writer = null,
|
||||
.capture = null,
|
||||
.command = .invalid,
|
||||
|
||||
// Keeping all our undefined values together so we can
|
||||
@@ -394,8 +390,8 @@ pub const Parser = struct {
|
||||
|
||||
/// Reset the parser state.
|
||||
pub fn reset(self: *Parser) void {
|
||||
// If we set up an allocating writer, free up that memory.
|
||||
if (self.allocating) |*allocating| allocating.deinit();
|
||||
// If we're capturing, then stop it.
|
||||
if (self.capture) |*cap| cap.deinit();
|
||||
|
||||
// Handle any cleanup that individual OSCs require.
|
||||
switch (self.command) {
|
||||
@@ -430,9 +426,7 @@ pub const Parser = struct {
|
||||
}
|
||||
|
||||
self.state = .start;
|
||||
self.fixed = null;
|
||||
self.allocating = null;
|
||||
self.writer = null;
|
||||
self.capture = null;
|
||||
self.command = .invalid;
|
||||
|
||||
if (std.valgrind.runningOnValgrind() > 0) {
|
||||
@@ -451,31 +445,91 @@ pub const Parser = struct {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Set up a fixed Writer to collect the rest of the OSC data.
|
||||
inline fn writeToFixed(self: *Parser) void {
|
||||
self.fixed = .fixed(&self.buffer);
|
||||
self.writer = &self.fixed.?;
|
||||
}
|
||||
const Capture = struct {
|
||||
writer: *std.Io.Writer,
|
||||
backing: Backing,
|
||||
|
||||
/// Set up an allocating Writer to collect the rest of the OSC data. If we
|
||||
/// don't have an allocator or setting up the allocator fails, fall back to
|
||||
/// writing to a fixed buffer and hope that it's big enough.
|
||||
inline fn writeToAllocating(self: *Parser) void {
|
||||
const alloc = self.alloc orelse {
|
||||
// We don't have an allocator - fall back to a fixed buffer and hope
|
||||
// that it's big enough.
|
||||
self.writeToFixed();
|
||||
return;
|
||||
const Backing = union(enum) {
|
||||
fixed: std.Io.Writer,
|
||||
allocating: std.Io.Writer.Allocating,
|
||||
};
|
||||
|
||||
self.allocating = std.Io.Writer.Allocating.initCapacity(alloc, 2048) catch {
|
||||
// The allocator failed for some reason, fall back to a fixed buffer
|
||||
// and hope that it's big enough.
|
||||
self.writeToFixed();
|
||||
return;
|
||||
const Mode = enum {
|
||||
fixed,
|
||||
allocating,
|
||||
};
|
||||
|
||||
self.writer = &self.allocating.?.writer;
|
||||
pub inline fn fixed(new: *?Capture, buf: []u8) void {
|
||||
new.* = .{
|
||||
.backing = .{ .fixed = .fixed(buf) },
|
||||
.writer = &new.*.?.backing.fixed,
|
||||
};
|
||||
}
|
||||
|
||||
pub inline fn allocating(
|
||||
new: *?Capture,
|
||||
alloc: Allocator,
|
||||
) error{OutOfMemory}!void {
|
||||
new.* = .{
|
||||
.backing = .{ .allocating = try std.Io.Writer.Allocating.initCapacity(
|
||||
alloc,
|
||||
2048,
|
||||
) },
|
||||
.writer = &new.*.?.backing.allocating.writer,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Capture) void {
|
||||
switch (self.backing) {
|
||||
.fixed => {},
|
||||
.allocating => |*w| w.deinit(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the captured trailing data. This is the data from the
|
||||
/// point that trailing data capture was requested.
|
||||
pub inline fn trailing(self: *Capture) []u8 {
|
||||
return self.writer.buffered();
|
||||
}
|
||||
};
|
||||
|
||||
/// Begin capturing trailing data. All inputs to next from this point
|
||||
/// forward will be captured into the `self.capture.writer` buffer
|
||||
/// which may be backed by either a fixed size or allocating buffer
|
||||
/// depending on mode.
|
||||
///
|
||||
/// Get the trailing data using `capture.trailing()`. Do not access
|
||||
/// the writer directly.
|
||||
inline fn captureTrailing(
|
||||
self: *Parser,
|
||||
comptime mode: Capture.Mode,
|
||||
) void {
|
||||
assert(self.capture == null);
|
||||
switch (mode) {
|
||||
.fixed => Capture.fixed(
|
||||
&self.capture,
|
||||
&self.buffer,
|
||||
),
|
||||
|
||||
.allocating => {
|
||||
const alloc = self.alloc orelse {
|
||||
// We don't have an allocator - fall back to a fixed buffer and hope
|
||||
// that it's big enough.
|
||||
self.captureTrailing(.fixed);
|
||||
return;
|
||||
};
|
||||
|
||||
Capture.allocating(
|
||||
&self.capture,
|
||||
alloc,
|
||||
) catch {
|
||||
// The allocator failed for some reason, fall back to a fixed buffer
|
||||
// and hope that it's big enough.
|
||||
self.captureTrailing(.fixed);
|
||||
return;
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the next character c and advance the parser state.
|
||||
@@ -486,8 +540,8 @@ pub const Parser = struct {
|
||||
|
||||
// If a writer has been initialized, we just accumulate the rest of the
|
||||
// OSC sequence in the writer's buffer and skip the state machine.
|
||||
if (self.writer) |writer| {
|
||||
writer.writeByte(c) catch |err| switch (err) {
|
||||
if (self.capture) |*cap| {
|
||||
cap.writer.writeByte(c) catch |err| switch (err) {
|
||||
// We have overflowed our buffer or had some other error, set the
|
||||
// state to invalid so that we discard any further input.
|
||||
error.WriteFailed => self.state = .invalid,
|
||||
@@ -529,12 +583,12 @@ pub const Parser = struct {
|
||||
},
|
||||
|
||||
.@"3008" => switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"1" => switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
'0' => self.state = .@"10",
|
||||
'1' => self.state = .@"11",
|
||||
'2' => self.state = .@"12",
|
||||
@@ -549,18 +603,18 @@ pub const Parser = struct {
|
||||
},
|
||||
|
||||
.@"10" => switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
'4' => self.state = .@"104",
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"104" => switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"11" => switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
'0' => self.state = .@"110",
|
||||
'1' => self.state = .@"111",
|
||||
'2' => self.state = .@"112",
|
||||
@@ -594,25 +648,25 @@ pub const Parser = struct {
|
||||
.@"118",
|
||||
.@"119",
|
||||
=> switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"13" => switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
'3' => self.state = .@"133",
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"2" => switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
'1' => self.state = .@"21",
|
||||
'2' => self.state = .@"22",
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"5" => switch (c) {
|
||||
';' => if (self.ensureAllocator()) self.writeToFixed(),
|
||||
';' => if (self.ensureAllocator()) self.captureTrailing(.fixed),
|
||||
'2' => self.state = .@"52",
|
||||
'5' => self.state = .@"55",
|
||||
else => self.state = .invalid,
|
||||
@@ -626,7 +680,7 @@ pub const Parser = struct {
|
||||
.@"52",
|
||||
.@"66",
|
||||
=> switch (c) {
|
||||
';' => self.writeToAllocating(),
|
||||
';' => self.captureTrailing(.allocating),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
@@ -636,7 +690,7 @@ pub const Parser = struct {
|
||||
},
|
||||
|
||||
.@"7" => switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
'7' => self.state = .@"77",
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
@@ -648,7 +702,7 @@ pub const Parser = struct {
|
||||
|
||||
.@"133",
|
||||
=> switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
'7' => self.state = .@"1337",
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
@@ -660,13 +714,13 @@ pub const Parser = struct {
|
||||
|
||||
.@"1337",
|
||||
=> switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
.@"5522",
|
||||
=> switch (c) {
|
||||
';' => self.writeToAllocating(),
|
||||
';' => self.captureTrailing(.allocating),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
|
||||
@@ -676,7 +730,7 @@ pub const Parser = struct {
|
||||
.@"8",
|
||||
.@"9",
|
||||
=> switch (c) {
|
||||
';' => self.writeToFixed(),
|
||||
';' => self.captureTrailing(.fixed),
|
||||
else => self.state = .invalid,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ const Command = @import("../../osc.zig").Command;
|
||||
|
||||
/// Parse OSC 1
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
parser.command = .{
|
||||
.change_window_icon = data[0 .. data.len - 1 :0],
|
||||
};
|
||||
|
||||
@@ -5,15 +5,15 @@ const Command = @import("../../osc.zig").Command;
|
||||
|
||||
/// Parse OSC 0 and OSC 2
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
parser.command = .{
|
||||
.change_window_title = data[0 .. data.len - 1 :0],
|
||||
};
|
||||
|
||||
@@ -8,15 +8,15 @@ const Command = @import("../../osc.zig").Command;
|
||||
/// Parse OSC 52
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
assert(parser.state == .@"52");
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
if (data.len == 1) {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
|
||||
@@ -50,8 +50,8 @@ pub fn parse(parser: *Parser, terminator_ch: ?u8) ?*Command {
|
||||
// If we've collected any extra data parse that, otherwise use an empty
|
||||
// string.
|
||||
const data = data: {
|
||||
const writer = parser.writer orelse break :data "";
|
||||
break :data writer.buffered();
|
||||
const cap = if (parser.capture) |*c| c else break :data "";
|
||||
break :data cap.trailing();
|
||||
};
|
||||
// Check and make sure that we're parsing the correct OSCs
|
||||
const op: Operation = switch (parser.state) {
|
||||
|
||||
@@ -201,11 +201,11 @@ pub const Field = enum {
|
||||
/// start=<id>[;<field>=<value>]*
|
||||
/// end=<id>[;<field>=<value>]*
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*OSCCommand {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
if (data.len == 0) {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
|
||||
@@ -7,15 +7,15 @@ const log = std.log.scoped(.osc_hyperlink);
|
||||
|
||||
/// Parse OSC 8 hyperlinks
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
const s = std.mem.indexOfScalar(u8, data, ';') orelse {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
|
||||
@@ -66,15 +66,15 @@ const map: Map = .initComptime(
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
assert(parser.state == .@"1337");
|
||||
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
|
||||
const key_str: [:0]u8, const value_: ?[:0]u8 = kv: {
|
||||
const index = std.mem.indexOfScalar(u8, data, '=') orelse {
|
||||
|
||||
@@ -152,12 +152,12 @@ fn parseIdentifier(str: []const u8) ?[]const u8 {
|
||||
pub fn parse(parser: *Parser, terminator_ch: ?u8) ?*Command {
|
||||
assert(parser.state == .@"5522");
|
||||
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
|
||||
const metadata: []const u8, const payload: ?[]const u8 = result: {
|
||||
const start = std.mem.indexOfScalar(u8, data, ';') orelse break :result .{ data, null };
|
||||
|
||||
@@ -17,7 +17,7 @@ pub fn parse(parser: *Parser, terminator_ch: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
@@ -28,7 +28,7 @@ pub fn parse(parser: *Parser, terminator_ch: ?u8) ?*Command {
|
||||
},
|
||||
};
|
||||
const list = &parser.command.kitty_color_protocol.list;
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
var kv_it = std.mem.splitScalar(u8, data, ';');
|
||||
while (kv_it.next()) |kv| {
|
||||
if (list.items.len >= @as(usize, kitty_color.Kind.max) * 2) {
|
||||
|
||||
@@ -71,17 +71,17 @@ pub const OSC = struct {
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
assert(parser.state == .@"66");
|
||||
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
|
||||
// Write a NUL byte to ensure that `text` is NUL-terminated
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
|
||||
const payload_start = std.mem.indexOfScalar(u8, data, ';') orelse {
|
||||
log.warn("missing semicolon before payload", .{});
|
||||
|
||||
@@ -8,15 +8,15 @@ const Command = @import("../../osc.zig").Command;
|
||||
// Parse OSC 22
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
assert(parser.state == .@"22");
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
parser.command = .{
|
||||
.mouse_shape = .{
|
||||
.value = data[0 .. data.len - 1 :0],
|
||||
|
||||
@@ -5,15 +5,16 @@ const Command = @import("../../osc.zig").Command;
|
||||
|
||||
/// Parse OSC 9, which could be an iTerm2 notification or a ConEmu extension.
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const writer = cap.writer;
|
||||
|
||||
// Check first to see if this is a ConEmu OSC
|
||||
// https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
|
||||
conemu: {
|
||||
var data = writer.buffered();
|
||||
var data = cap.trailing();
|
||||
if (data.len == 0) break :conemu;
|
||||
switch (data[0]) {
|
||||
// Check for OSC 9;1 9;10 9;11 9;12
|
||||
@@ -90,7 +91,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_comment = data[3 .. data.len - 1 :0],
|
||||
};
|
||||
@@ -112,7 +113,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_show_message_box = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
@@ -132,7 +133,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_change_tab_title = .{
|
||||
.value = data[2 .. data.len - 1 :0],
|
||||
@@ -214,7 +215,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_guimacro = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
@@ -228,7 +229,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_run_process = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
@@ -242,7 +243,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.conemu_output_environment_variable = data[2 .. data.len - 1 :0],
|
||||
};
|
||||
@@ -256,7 +257,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
data = writer.buffered();
|
||||
data = cap.trailing();
|
||||
parser.command = .{
|
||||
.report_pwd = .{
|
||||
.value = data[2 .. data.len - 1 :0],
|
||||
@@ -274,7 +275,7 @@ pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
parser.command = .{
|
||||
.show_desktop_notification = .{
|
||||
.title = "",
|
||||
|
||||
@@ -5,15 +5,15 @@ const Command = @import("../../osc.zig").Command;
|
||||
|
||||
/// Parse OSC 7
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
parser.command = .{
|
||||
.report_pwd = .{
|
||||
.value = data[0 .. data.len - 1 :0],
|
||||
|
||||
@@ -7,16 +7,16 @@ const log = std.log.scoped(.osc_rxvt_extension);
|
||||
|
||||
/// Parse OSC 777
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*Command {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
// ensure that we are sentinel terminated
|
||||
writer.writeByte(0) catch {
|
||||
cap.writer.writeByte(0) catch {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
const k = std.mem.indexOfScalar(u8, data, ';') orelse {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
|
||||
@@ -298,11 +298,11 @@ pub const Redraw = enum(u2) {
|
||||
|
||||
/// Parse OSC 133, semantic prompts
|
||||
pub fn parse(parser: *Parser, _: ?u8) ?*OSCCommand {
|
||||
const writer = parser.writer orelse {
|
||||
const cap = if (parser.capture) |*c| c else {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
};
|
||||
const data = writer.buffered();
|
||||
const data = cap.trailing();
|
||||
if (data.len == 0) {
|
||||
parser.state = .invalid;
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user