terminal/glyph: clear

This commit is contained in:
Mitchell Hashimoto
2026-06-05 06:34:53 -07:00
parent cc91940993
commit 6f83d8a4f1
2 changed files with 89 additions and 2 deletions

View File

@@ -24,6 +24,9 @@ pub const empty: Glossary = .{ .entries = .empty };
/// Errors that can occur while registering a glossary entry.
pub const RegisterError = Allocator.Error || error{OutOfNamespace};
/// Errors that can occur while clearing glossary entries.
pub const ClearError = error{OutOfNamespace};
/// The set of entries in the glossary keyed by the codepoint.
///
/// The array hash map preserves insertion order and has O(N)
@@ -87,7 +90,7 @@ pub fn delete(
self: *Glossary,
alloc: Allocator,
cp: u21,
) error{OutOfNamespace}!void {
) ClearError!void {
if (!isPrivateUse(cp)) return error.OutOfNamespace;
const kv = self.entries.fetchOrderedRemove(cp) orelse return;
var entry = kv.value;

View File

@@ -32,7 +32,8 @@ pub fn execute(
return switch (req.*) {
.support => .{ .support = .{ .fmt = supported_formats } },
.register => |reg| register(alloc, glossary, reg),
.query, .clear => @panic("TODO"),
.clear => |clr| clear(alloc, glossary, clr),
.query => @panic("TODO"),
};
}
@@ -82,6 +83,25 @@ fn registerFallible(
return cp;
}
fn clear(
alloc: Allocator,
glossary: *Glossary,
clr: Request.Clear,
) ?Response {
if (clr.get(.cp)) |cp| {
glossary.delete(alloc, cp) catch |err| return .{ .clear = .{
.status = .err,
.reason = switch (err) {
error.OutOfNamespace => "out_of_namespace",
},
} };
} else {
glossary.clearAndFree(alloc);
}
return .{ .clear = .{} };
}
fn testParse(alloc: Allocator, data: []const u8) !Request {
var parser = request.CommandParser.init(alloc, 1024 * 1024);
defer parser.deinit();
@@ -172,3 +192,67 @@ test "execute register reports malformed payload" {
}, execute(alloc, &glossary, &req).?);
try testing.expect(!glossary.contains(0xE0A0));
}
test "execute clear removes all glyphs" {
const testing = std.testing;
const alloc = testing.allocator;
var glossary: Glossary = .empty;
defer glossary.deinit(alloc);
var reg1 = try testParse(alloc, "r;cp=e0a0;AAAAAAAAAAAAAA==");
defer reg1.deinit(alloc);
_ = execute(alloc, &glossary, &reg1);
var reg2 = try testParse(alloc, "r;cp=e0a1;AAAAAAAAAAAAAA==");
defer reg2.deinit(alloc);
_ = execute(alloc, &glossary, &reg2);
var req = try testParse(alloc, "c");
defer req.deinit(alloc);
try testing.expectEqual(Response{ .clear = .{} }, execute(alloc, &glossary, &req).?);
try testing.expect(!glossary.contains(0xE0A0));
try testing.expect(!glossary.contains(0xE0A1));
}
test "execute clear removes one glyph" {
const testing = std.testing;
const alloc = testing.allocator;
var glossary: Glossary = .empty;
defer glossary.deinit(alloc);
var reg1 = try testParse(alloc, "r;cp=e0a0;AAAAAAAAAAAAAA==");
defer reg1.deinit(alloc);
_ = execute(alloc, &glossary, &reg1);
var reg2 = try testParse(alloc, "r;cp=e0a1;AAAAAAAAAAAAAA==");
defer reg2.deinit(alloc);
_ = execute(alloc, &glossary, &reg2);
var req = try testParse(alloc, "c;cp=e0a0");
defer req.deinit(alloc);
try testing.expectEqual(Response{ .clear = .{} }, execute(alloc, &glossary, &req).?);
try testing.expect(!glossary.contains(0xE0A0));
try testing.expect(glossary.contains(0xE0A1));
}
test "execute clear rejects non-PUA" {
const testing = std.testing;
const alloc = testing.allocator;
var glossary: Glossary = .empty;
defer glossary.deinit(alloc);
var req = try testParse(alloc, "c;cp=41");
defer req.deinit(alloc);
try testing.expectEqual(Response{
.clear = .{
.status = .err,
.reason = "out_of_namespace",
},
}, execute(alloc, &glossary, &req).?);
}