mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-24 16:11:43 +00:00
osc 99: address review feedback
* Fix typos. * Eliminate metadata parsing code duplication. * Improve documentation. * Ensure assert is comptime only. * Derive valid metadata characters from valid identifier characters.
This commit is contained in:
committed by
Mitchell Hashimoto
parent
9a8e7ae186
commit
aa4ec3508e
@@ -106,9 +106,9 @@ pub const Option = enum {
|
||||
d,
|
||||
/// Is the payload encoded with Base64?
|
||||
e,
|
||||
/// The nname of the application that is sending the notification.
|
||||
/// The name of the application that is sending the notification.
|
||||
f,
|
||||
/// Identifier for icon data.
|
||||
/// Identifier for icon data. Only used when the payload is icon data.
|
||||
g,
|
||||
/// Identifier for the notification.
|
||||
i,
|
||||
@@ -173,45 +173,15 @@ pub const Option = enum {
|
||||
comptime key: Option,
|
||||
metadata: []const u8,
|
||||
) key.Type() {
|
||||
switch (key) {
|
||||
var it: Iterator(key) = switch (key) {
|
||||
inline .t, .n => return .init(metadata),
|
||||
else => {},
|
||||
}
|
||||
|
||||
const value = 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 key.default();
|
||||
if (metadata[pos] != @tagName(key)[0]) {
|
||||
// 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 key.default();
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
// skip past the key
|
||||
pos += 1;
|
||||
// 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 key.default();
|
||||
// a valid option has an '='
|
||||
if (metadata[pos] != '=') return key.default();
|
||||
// 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;
|
||||
// return the value after stripping any leading or trailing whitespace
|
||||
break :value std.mem.trim(u8, metadata[pos + 1 .. end], &std.ascii.whitespace);
|
||||
}
|
||||
// the key was not found
|
||||
return key.default();
|
||||
inline else => .init(metadata),
|
||||
};
|
||||
|
||||
if (!isValidMetadataValue(value)) return key.default();
|
||||
const value = it.next() orelse return key.default();
|
||||
|
||||
// return the parsed value
|
||||
// return the parsed value, the iterator guarantees that it's a valid
|
||||
// metadata value
|
||||
return switch (key) {
|
||||
.a => .init(value),
|
||||
.c => parseBool(value) orelse key.default(),
|
||||
@@ -248,7 +218,7 @@ fn parseBool(str: []const u8) ?bool {
|
||||
};
|
||||
}
|
||||
|
||||
/// This is similar to the packed struct parsed used in the configs. The
|
||||
/// This is similar to the packed struct parser used in the configs. The
|
||||
/// differences are that a literal `true` or `false` value does not turn on/off
|
||||
/// all the values, and the negation prefix is `-` not `no-`.
|
||||
pub fn parsePackedStruct(comptime T: type, str: []const u8) T {
|
||||
@@ -273,7 +243,7 @@ pub fn parsePackedStruct(comptime T: type, str: []const u8) T {
|
||||
};
|
||||
|
||||
inline for (info.fields) |field| {
|
||||
assert(field.type == bool);
|
||||
comptime assert(field.type == bool);
|
||||
if (std.mem.eql(u8, field.name, part)) {
|
||||
@field(result, field.name) = value;
|
||||
continue :loop;
|
||||
@@ -291,7 +261,7 @@ pub fn parsePackedStruct(comptime T: type, str: []const u8) T {
|
||||
/// against the spec but is needed since Base64 encoded values (with padding)
|
||||
/// are valid for some options. Including `?` is technically against the spec
|
||||
/// but is needed since it is a valid value for the `p` option.
|
||||
const valid_metadata_value_characters: []const u8 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/+.,(){}[]*&^%$#@!`~=?";
|
||||
const valid_metadata_value_characters: []const u8 = valid_identifier_characters ++ "/.,(){}[]*&^%$#@!`~=?";
|
||||
|
||||
fn isValidMetadataValue(str: []const u8) bool {
|
||||
return std.mem.indexOfNone(u8, str, valid_metadata_value_characters) == null;
|
||||
@@ -309,7 +279,7 @@ fn parseIdentifier(str: []const u8) ?[]const u8 {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Used when an option can appear multiple times in the metadata
|
||||
/// Used to iterate over matching key/values in the metadata
|
||||
pub fn Iterator(comptime key: Option) type {
|
||||
return struct {
|
||||
metadata: []const u8,
|
||||
@@ -322,7 +292,10 @@ pub fn Iterator(comptime key: Option) type {
|
||||
};
|
||||
}
|
||||
|
||||
/// Return the value of the next matching key. The value is guaranteed
|
||||
/// to be `null` or a valid metadata value.
|
||||
pub fn next(self: *Iterator(key)) ?[]const u8 {
|
||||
// bail if we are out of metadata
|
||||
if (self.pos >= self.metadata.len) return null;
|
||||
while (self.pos < self.metadata.len) {
|
||||
// skip any whitespace
|
||||
|
||||
Reference in New Issue
Block a user