diff options
-rw-r--r-- | src/main.zig | 16 | ||||
-rw-r--r-- | src/selection.zig | 202 |
2 files changed, 158 insertions, 60 deletions
diff --git a/src/main.zig b/src/main.zig index c2d9d12..f34d878 100644 --- a/src/main.zig +++ b/src/main.zig @@ -49,7 +49,7 @@ const Environment = struct { allocator: Allocator, loop: *Loop(Event), parser: *Parser, - span: *selection.Span, + segment: *selection.Segment, text: []const u8, tty: *Tty, vaxis: *Vaxis, @@ -76,7 +76,7 @@ const Environment = struct { var graphemes = self.vaxis.unicode.graphemeIterator(self.text); while (graphemes.next()) |grapheme| { const style = Style { - .reverse = self.span.contains(grapheme), + .reverse = self.segment.contains(grapheme), }; const bytes = grapheme.bytes(self.text); if (eql(u8, bytes, "\n")) { @@ -111,19 +111,19 @@ const Environment = struct { } pub fn goUp(self: Environment) void { - self.span.goUp(); + self.segment.goUp(); } pub fn goRight(self: Environment) void { - self.span.goRight(self.vaxis.unicode.width_data.graphemes, self.text); + self.segment.goRight(self.vaxis.unicode.width_data.graphemes, self.text); } pub fn goLeft(self: Environment) void { - self.span.goLeft(self.vaxis.unicode.width_data.graphemes, self.text); + self.segment.goLeft(self.vaxis.unicode.width_data.graphemes, self.text); } pub fn goDown(self: Environment) void { - self.span.goDown(self.vaxis.unicode.width_data.graphemes, self.text); + self.segment.goDown(self.vaxis.unicode.width_data.graphemes, self.text); } }; @@ -163,7 +163,7 @@ pub fn main() !void { zsanett.init(); defer zsanett.deinit(); - var span = selection.Span{ + var segment = selection.Segment{ .head = .{ .node = tree.rootNode() }, .tail = .{ .node = tree.rootNode() }, }; @@ -171,7 +171,7 @@ pub fn main() !void { .allocator = allocator, .loop = &loop, .parser = parser, - .span = &span, + .segment = &segment, .text = text, .tty = &tty, .vaxis = &vx, diff --git a/src/selection.zig b/src/selection.zig index 1fb8266..44d537f 100644 --- a/src/selection.zig +++ b/src/selection.zig @@ -26,15 +26,63 @@ fn graphemeBefore(graphemes: Graphemes, text: []const u8, index: u32) Grapheme { // TODO: undo pub const Unit = union(enum) { node: Node, - grapheme: struct { - const GraphemeUnit = @This(); + span: Span, + grapheme: GraphemeUnit, + + // TODO: nesting + const Span = struct { + start: u32, + end: u32, + tree: *const Tree, + + fn parent(unit: Span) Node { + const root_node = unit.tree.rootNode(); + return root_node.descendantForByteRange(unit.start, unit.end).?; + } + }; + + const GraphemeUnit = struct { slice: Grapheme, tree: *const Tree, - fn parent(unit: GraphemeUnit) Node { - const start = unit.slice.offset; - const end = start + unit.slice.len; - return unit.tree.rootNode().descendantForByteRange(start, end).?; + fn startByte(unit: GraphemeUnit) u32 { + return unit.slice.offset; + } + + fn endByte(unit: GraphemeUnit) u32 { + return unit.slice.offset + unit.slice.len; + } + + fn parent(unit: GraphemeUnit) Span { + const start = unit.startByte(); + const end = unit.endByte(); + const root_node = unit.tree.rootNode(); + const parent_node = root_node.descendantForByteRange(start, end).?; + if (parent_node.firstChildForByte(end)) |next_node| { + return if (next_node.prevSibling()) |prev_node| .{ + .start = prev_node.endByte(), + .end = next_node.startByte(), + .tree = unit.tree, + } else .{ + .start = parent_node.startByte(), + .end = next_node.startByte(), + .tree = unit.tree, + }; + } else { + const siblings = parent_node.childCount(); + if (siblings == 0) + return .{ + .start = parent_node.startByte(), + .end = parent_node.endByte(), + .tree = unit.tree, + }; + const prev_node = parent_node.child(siblings - 1).?; + return .{ + .start = prev_node.endByte(), + .end = parent_node.endByte(), + .tree = unit.tree, + }; + } } fn at(unit: GraphemeUnit, graphemes: Graphemes, @@ -52,18 +100,49 @@ pub const Unit = union(enum) { .tree = unit.tree, }; } - }, + }; - pub fn up(unit: Unit) Unit { + fn startByte(unit: Unit) u32 { + return switch (unit) { + .node => |node| node.startByte(), + .span => |span| span.start, + .grapheme => |grapheme| grapheme.startByte(), + }; + } + + fn endByte(unit: Unit) u32 { return switch (unit) { - .node => |node| if (node.parent()) |parent_node| + .node => |node| node.endByte(), + .span => |span| span.end, + .grapheme => |grapheme| grapheme.endByte(), + }; + } + + pub fn up(unit: Unit) Unit { + switch (unit) { + .node => |node| return if (node.parent()) |parent_node| if (parent_node.eql(node)) .up(.{ .node = parent_node }) else .{ .node = parent_node } else unit, - .grapheme => |grapheme| .{ .node = grapheme.parent() }, - }; + .span => |span| { + const parent_node = span.parent(); + return if (parent_node.startByte() == span.start + and parent_node.endByte() == span.end) + .up(.{ .node = parent_node }) + else + .{ .node = parent_node }; + }, + .grapheme => |grapheme| { + const parent_span = grapheme.parent(); + return if (parent_span.start == grapheme.startByte() + and parent_span.end == grapheme.endByte()) + .up(.{ .span = parent_span }) + else + .{ .span = parent_span }; + }, + } } pub fn right(unit: Unit, graphemes: Graphemes, text: []const u8) Unit { @@ -73,26 +152,29 @@ pub const Unit = union(enum) { const next = sibling.startByte(); return switch (order(prev, next)) { .lt => .{ - .grapheme = .{ - .slice = graphemeAt(graphemes, text, prev), + .span = .{ + .start = prev, + .end = next, .tree = node.tree, } }, .eq => .{ .node = sibling }, .gt => unreachable, }; - } else return .up(unit), + }, + .span => |span| { + const parent_node = unit.up().node; + if (parent_node.firstChildForByte(span.end)) |next_node| + return .{ .node = next_node }; + }, .grapheme => |grapheme| { - const start = grapheme.slice.offset + grapheme.slice.len; + const start = grapheme.endByte(); const next_grapheme = grapheme.at(graphemes, text, start); - const parent = next_grapheme.parent(); - return if (parent.eql(grapheme.parent())) .{ - .grapheme = next_grapheme - } else .{ - .node = parent - }; + if (eql(next_grapheme.parent(), grapheme.parent())) + return .{ .grapheme = next_grapheme }; }, } + return .up(unit); } pub fn left(unit: Unit, graphemes: Graphemes, text: []const u8) Unit { @@ -102,26 +184,34 @@ pub const Unit = union(enum) { const next = node.startByte(); return switch (order(prev, next)) { .lt => .{ - .grapheme = .{ - .slice = graphemeBefore(graphemes, text, next), + .span = .{ + .start = prev, + .end = next, .tree = node.tree, } }, .eq => .{ .node = sibling }, .gt => unreachable, }; - } else return .up(unit), + }, + .span => |span| { + const parent_node = span.parent(); + if (parent_node.firstChildForByte(span.end)) |next_node| { + if (next_node.prevSibling()) |prev_node| + return .{ .node = prev_node }; + } else { + const siblings = parent_node.childCount(); + return .{ .node = parent_node.child(siblings - 1).? }; + } + }, .grapheme => |grapheme| { const end = grapheme.slice.offset; const prev_grapheme = grapheme.before(graphemes, text, end); - const parent = prev_grapheme.parent(); - return if (parent.eql(grapheme.parent())) .{ - .grapheme = prev_grapheme - } else .{ - .node = parent - }; + if (eql(prev_grapheme.parent(), grapheme.parent())) + return .{ .grapheme = prev_grapheme }; }, } + return .up(unit); } pub fn down(unit: Unit, graphemes: Graphemes, text: []const u8) Unit { @@ -135,12 +225,16 @@ pub const Unit = union(enum) { .down(.{ .node = child }, graphemes, text) else .{ .node = child } - else .{ - .grapheme = .{ - .slice = graphemeAt(graphemes, text, start), - .tree = node.tree, - } - }; + else .down(.{ + .span = .{ .start = start, .end = end, .tree = node.tree } + }, graphemes, text); + }, + // TODO: history + .span => |span| return .{ + .grapheme = .{ + .slice = graphemeAt(graphemes, text, span.start), + .tree = span.tree, + } }, .grapheme => return unit, } @@ -150,37 +244,41 @@ pub const Unit = union(enum) { return switch (unit) { .node => |node| (node.startByte() <= other.offset and other.offset + other.len <= node.endByte()), + .span => |span| (span.start <= other.offset + and other.offset + other.len <= span.end), .grapheme => |grapheme| eql(grapheme.slice, other), }; } }; -pub const Span = struct { +pub const Segment = struct { head: Unit, tail: Unit, - pub fn contains(span: Span, grapheme: Grapheme) bool { - // TODO: range - return span.head.contains(grapheme); + pub fn contains(segment: Segment, grapheme: Grapheme) bool { + const start = @min(segment.head.startByte(), segment.tail.startByte()); + const end = @min(segment.head.endByte(), segment.tail.endByte()); + return (start <= grapheme.offset + and grapheme.offset + grapheme.len <= end); } - pub fn goUp(span: *Span) void { - span.head = span.head.up(); - span.tail = span.tail.up(); + pub fn goUp(segment: *Segment) void { + segment.head = segment.head.up(); + segment.tail = segment.tail.up(); } - pub fn goRight(span: *Span, graphemes: Graphemes, text: []const u8) void { - span.head = span.head.right(graphemes, text); - span.tail = span.tail.right(graphemes, text); + pub fn goRight(segment: *Segment, graphemes: Graphemes, text: []const u8) void { + segment.head = segment.head.right(graphemes, text); + segment.tail = segment.tail.right(graphemes, text); } - pub fn goLeft(span: *Span, graphemes: Graphemes, text: []const u8) void { - span.head = span.head.left(graphemes, text); - span.tail = span.tail.left(graphemes, text); + pub fn goLeft(segment: *Segment, graphemes: Graphemes, text: []const u8) void { + segment.head = segment.head.left(graphemes, text); + segment.tail = segment.tail.left(graphemes, text); } - pub fn goDown(span: *Span, graphemes: Graphemes, text: []const u8) void { - span.head = span.head.down(graphemes, text); - span.tail = span.tail.down(graphemes, text); + pub fn goDown(segment: *Segment, graphemes: Graphemes, text: []const u8) void { + segment.head = segment.head.down(graphemes, text); + segment.tail = segment.tail.down(graphemes, text); } }; |