TUI editor and editor backend written in Zig
at main 118 lines 3.4 kB view raw
1const std = @import("std"); 2 3/// A `Pos` represents a position in the text editor. `Pos` is a 2-dimensional position based on 4/// `row` and `col`. 5pub const Pos = @This(); 6 7row: usize, 8col: usize, 9 10pub const init: Pos = .{ .row = 0, .col = 0 }; 11 12/// Returns true if both positions are the same. 13pub fn eql(self: Pos, other: Pos) bool { 14 return self.row == other.row and self.col == other.col; 15} 16 17/// Returns `true` if this `Pos` comes before the `other` `Pos`. 18pub fn comesBefore(self: Pos, other: Pos) bool { 19 if (self.row < other.row) return true; 20 if (self.row > other.row) return false; 21 return self.col < other.col; 22} 23 24/// Returns `true` if this `Pos` comes after the `other` `Pos`. 25pub fn comesAfter(self: Pos, other: Pos) bool { 26 if (self.row > other.row) return true; 27 if (self.row < other.row) return false; 28 return self.col > other.col; 29} 30 31/// Comparison function used for sorting. 32pub fn lessThan(_: void, lhs: Pos, rhs: Pos) bool { 33 return lhs.comesBefore(rhs); 34} 35 36pub fn getVisualColumnForText(self: Pos, text: []const u8) usize { 37 const text_len = len: { 38 if (std.mem.endsWith(u8, text, "\n")) break :len text.len -| 1; 39 break :len text.len; 40 }; 41 42 return @min(self.col, text_len); 43} 44 45test eql { 46 const a: Pos = .{ .row = 0, .col = 3 }; 47 const b: Pos = .{ .row = 0, .col = 3 }; 48 49 try std.testing.expect(a.eql(b)); 50 try std.testing.expect(a.eql(a)); 51 try std.testing.expect(b.eql(b)); 52 53 const c: Pos = .{ .row = 4, .col = 0 }; 54 55 try std.testing.expect(!c.eql(a)); 56 try std.testing.expect(!c.eql(b)); 57 try std.testing.expect(c.eql(c)); 58 59 const d: Pos = .{ .row = 1, .col = 5 }; 60 61 try std.testing.expect(!d.eql(a)); 62 try std.testing.expect(!d.eql(b)); 63 try std.testing.expect(!d.eql(c)); 64 try std.testing.expect(d.eql(d)); 65} 66 67test comesBefore { 68 const a: Pos = .{ .row = 0, .col = 3 }; 69 const b: Pos = .{ .row = 0, .col = 3 }; 70 71 try std.testing.expect(!a.comesBefore(b)); 72 try std.testing.expect(!b.comesBefore(a)); 73 74 const c: Pos = .{ .row = 4, .col = 0 }; 75 76 try std.testing.expect(!c.comesBefore(a)); 77 try std.testing.expect(a.comesBefore(c)); 78 79 const d: Pos = .{ .row = 1, .col = 5 }; 80 81 try std.testing.expect(d.comesBefore(c)); 82 try std.testing.expect(!c.comesBefore(d)); 83} 84 85test comesAfter { 86 const a: Pos = .{ .row = 0, .col = 3 }; 87 const b: Pos = .{ .row = 0, .col = 3 }; 88 89 try std.testing.expect(!a.comesAfter(b)); 90 try std.testing.expect(!b.comesAfter(a)); 91 92 const c: Pos = .{ .row = 4, .col = 0 }; 93 94 try std.testing.expect(c.comesAfter(a)); 95 try std.testing.expect(!a.comesAfter(c)); 96 97 const d: Pos = .{ .row = 1, .col = 5 }; 98 99 try std.testing.expect(!d.comesAfter(c)); 100 try std.testing.expect(c.comesAfter(d)); 101} 102 103test getVisualColumnForText { 104 const pos: Pos = .{ .row = 0, .col = 3 }; 105 106 try std.testing.expect(pos.getVisualColumnForText("0123") == 3); 107 try std.testing.expect(pos.getVisualColumnForText("012") == 3); 108 try std.testing.expect(pos.getVisualColumnForText("012\n") == 3); 109 110 try std.testing.expect(pos.getVisualColumnForText("") == 0); 111 try std.testing.expect(pos.getVisualColumnForText("\n") == 0); 112 try std.testing.expect(pos.getVisualColumnForText("0\n") == 1); 113 try std.testing.expect(pos.getVisualColumnForText("01\n") == 2); 114} 115 116test "refAllDecls" { 117 std.testing.refAllDecls(@This()); 118}