Add coding symbol rail

This commit is contained in:
slhx agent
2026-06-21 02:21:32 +02:00
parent cfbacb3cd2
commit f793ecd726
6 changed files with 324 additions and 2 deletions
+43
View File
@@ -17,10 +17,16 @@ pub const Selection = struct {
cursor: usize,
};
pub const Pair = struct {
open: []const u8,
close: []const u8,
};
pub const Command = union(enum) {
move_left,
move_right,
insert: []const u8,
insert_pair: Pair,
delete_backward,
};
@@ -62,6 +68,7 @@ pub const Buffer = struct {
.move_left => self.moveLeft(),
.move_right => self.moveRight(),
.insert => |text| try self.insert(text),
.insert_pair => |pair| try self.insertPair(pair),
.delete_backward => self.deleteBackward(),
}
}
@@ -84,6 +91,16 @@ pub const Buffer = struct {
self.selection = null;
}
pub fn insertPair(self: *Buffer, pair: Pair) !void {
if (!std.unicode.utf8ValidateSlice(pair.open) or !std.unicode.utf8ValidateSlice(pair.close)) return error.InvalidUtf8Insertion;
const combined = try std.mem.concat(self.allocator, u8, &.{ pair.open, pair.close });
defer self.allocator.free(combined);
try self.bytes.insertSlice(self.allocator, self.cursor.byte, combined);
self.cursor.byte += pair.open.len;
self.refreshCell();
self.selection = null;
}
pub fn deleteBackward(self: *Buffer) void {
if (self.cursor.byte == 0) return;
const start = previousBoundary(self.bytes.items, self.cursor.byte);
@@ -265,3 +282,29 @@ test "adversarial: dispatch requires an open buffer" {
try std.testing.expectError(error.NoBufferOpen, session.dispatch(.move_right));
try std.testing.expectError(error.NoBufferOpen, session.snapshot());
}
test "regular: pair insertion places cursor between delimiters" {
var buffer = try Buffer.openFromBytes(std.testing.allocator, "call");
defer buffer.deinit();
buffer.moveRight();
buffer.moveRight();
buffer.moveRight();
buffer.moveRight();
try buffer.insertPair(.{ .open = "(", .close = ")" });
const snap = buffer.snapshot();
try std.testing.expectEqualStrings("call()", snap.bytes);
try std.testing.expectEqual(@as(usize, 5), snap.cursor_byte);
try std.testing.expectEqual(@as(usize, 5), snap.cursor_cell);
}
test "adversarial: invalid UTF-8 pair insertion is rejected and existing bytes are preserved" {
var buffer = try Buffer.openFromBytes(std.testing.allocator, "safe");
defer buffer.deinit();
const bad = [_]u8{ 0xc3, 0x28 };
try std.testing.expectError(error.InvalidUtf8Insertion, buffer.insertPair(.{ .open = &bad, .close = ")" }));
try std.testing.expectEqualStrings("safe", buffer.snapshot().bytes);
try std.testing.expectEqual(@as(usize, 0), buffer.snapshot().cursor_byte);
}