fix: simplify Buffer.del_chars to use only byte offsets
This is a much faster implementation avoids duplicating work done by Buffer.get_range. Buffer.get_range also does not have the bug reported in #83. The test case was also updated to reflect that get_chars now uses bytes, instead of columns. closes #83
This commit is contained in:
parent
5d5b157295
commit
f134fdb747
2 changed files with 40 additions and 43 deletions
|
@ -637,90 +637,87 @@ const Node = union(enum) {
|
|||
return result orelse "";
|
||||
}
|
||||
|
||||
pub fn delete_range(self: *const Node, sel: Selection, allocator: Allocator, size: ?*usize, metrics: Metrics) error{Stop}!Root {
|
||||
var wcwidth: usize = 0;
|
||||
_ = self.get_range(sel, null, size, &wcwidth, metrics) catch return error.Stop;
|
||||
return self.del_chars(sel.begin.row, sel.begin.col, wcwidth, allocator, metrics) catch return error.Stop;
|
||||
pub fn delete_range(self: *const Node, sel: Selection, allocator: Allocator, size_: ?*usize, metrics: Metrics) error{Stop}!Root {
|
||||
var size: usize = 0;
|
||||
defer if (size_) |p| {
|
||||
p.* = size;
|
||||
};
|
||||
_ = self.get_range(sel, null, &size, null, metrics) catch return error.Stop;
|
||||
const pos = try self.get_line_width_to_pos(sel.begin.row, sel.begin.col, metrics);
|
||||
return self.del_chars(sel.begin.row, pos, size, allocator, metrics) catch return error.Stop;
|
||||
}
|
||||
|
||||
pub fn del_chars(self: *const Node, line: usize, col: usize, count: usize, allocator: Allocator, metrics_: Metrics) !Root {
|
||||
pub fn del_chars(self: *const Node, line: usize, pos_: usize, bytes: usize, allocator: Allocator, metrics_: Metrics) !Root {
|
||||
const Ctx = struct {
|
||||
allocator: Allocator,
|
||||
col: usize,
|
||||
abs_col: usize = 0,
|
||||
count: usize,
|
||||
pos: usize,
|
||||
bytes: usize,
|
||||
delete_next_bol: bool = false,
|
||||
fn walker(Ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) WalkerMut {
|
||||
fn walker(Ctx: *anyopaque, leaf: *const Leaf, _: Metrics) WalkerMut {
|
||||
const ctx = @as(*@This(), @ptrCast(@alignCast(Ctx)));
|
||||
var result = WalkerMut.keep_walking;
|
||||
if (ctx.delete_next_bol and ctx.count == 0) {
|
||||
if (ctx.delete_next_bol and ctx.bytes == 0) {
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf, false, leaf.eol) catch |e| return .{ .err = e };
|
||||
result.keep_walking = false;
|
||||
ctx.delete_next_bol = false;
|
||||
return result;
|
||||
}
|
||||
const leaf_wcwidth = leaf.width(ctx.abs_col, metrics);
|
||||
const leaf_bytes = leaf.buf.len;
|
||||
const leaf_bol = leaf.bol and !ctx.delete_next_bol;
|
||||
ctx.delete_next_bol = false;
|
||||
const base_col = ctx.abs_col;
|
||||
ctx.abs_col += leaf_wcwidth;
|
||||
if (ctx.col > leaf_wcwidth) {
|
||||
if (ctx.pos > leaf_bytes) {
|
||||
// next node
|
||||
ctx.col -= leaf_wcwidth;
|
||||
ctx.pos -= leaf_bytes;
|
||||
if (leaf.eol)
|
||||
ctx.col -= 1;
|
||||
ctx.pos -= 1;
|
||||
} else {
|
||||
// this node
|
||||
if (ctx.col == 0) {
|
||||
if (ctx.count > leaf_wcwidth) {
|
||||
ctx.count -= leaf_wcwidth;
|
||||
if (ctx.pos == 0) {
|
||||
if (ctx.bytes > leaf_bytes) {
|
||||
ctx.bytes -= leaf_bytes;
|
||||
result.replace = Leaf.new(ctx.allocator, "", leaf_bol, false) catch |e| return .{ .err = e };
|
||||
if (leaf.eol) {
|
||||
ctx.count -= 1;
|
||||
ctx.bytes -= 1;
|
||||
ctx.delete_next_bol = true;
|
||||
}
|
||||
} else if (ctx.count == leaf_wcwidth) {
|
||||
} else if (ctx.bytes == leaf_bytes) {
|
||||
result.replace = Leaf.new(ctx.allocator, "", leaf_bol, leaf.eol) catch |e| return .{ .err = e };
|
||||
ctx.count = 0;
|
||||
ctx.bytes = 0;
|
||||
} else {
|
||||
const pos = leaf.width_to_pos(ctx.count, base_col, metrics) catch |e| return .{ .err = e };
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf[pos..], leaf_bol, leaf.eol) catch |e| return .{ .err = e };
|
||||
ctx.count = 0;
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf[ctx.bytes..], leaf_bol, leaf.eol) catch |e| return .{ .err = e };
|
||||
ctx.bytes = 0;
|
||||
}
|
||||
} else if (ctx.col == leaf_wcwidth) {
|
||||
} else if (ctx.pos == leaf_bytes) {
|
||||
if (leaf.eol) {
|
||||
ctx.count -= 1;
|
||||
ctx.bytes -= 1;
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf, leaf_bol, false) catch |e| return .{ .err = e };
|
||||
ctx.delete_next_bol = true;
|
||||
}
|
||||
ctx.col -= leaf_wcwidth;
|
||||
ctx.pos -= leaf_bytes;
|
||||
} else {
|
||||
if (ctx.col + ctx.count >= leaf_wcwidth) {
|
||||
ctx.count -= leaf_wcwidth - ctx.col;
|
||||
const pos = leaf.width_to_pos(ctx.col, base_col, metrics) catch |e| return .{ .err = e };
|
||||
const leaf_eol = if (leaf.eol and ctx.count > 0) leaf_eol: {
|
||||
ctx.count -= 1;
|
||||
if (ctx.pos + ctx.bytes >= leaf_bytes) {
|
||||
ctx.bytes -= leaf_bytes - ctx.pos;
|
||||
const leaf_eol = if (leaf.eol and ctx.bytes > 0) leaf_eol: {
|
||||
ctx.bytes -= 1;
|
||||
ctx.delete_next_bol = true;
|
||||
break :leaf_eol false;
|
||||
} else leaf.eol;
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf[0..pos], leaf_bol, leaf_eol) catch |e| return .{ .err = e };
|
||||
ctx.col = 0;
|
||||
result.replace = Leaf.new(ctx.allocator, leaf.buf[0..ctx.pos], leaf_bol, leaf_eol) catch |e| return .{ .err = e };
|
||||
ctx.pos = 0;
|
||||
} else {
|
||||
const pos = leaf.width_to_pos(ctx.col, base_col, metrics) catch |e| return .{ .err = e };
|
||||
const pos_end = leaf.width_to_pos(ctx.col + ctx.count, base_col, metrics) catch |e| return .{ .err = e };
|
||||
const left = Leaf.new(ctx.allocator, leaf.buf[0..pos], leaf_bol, false) catch |e| return .{ .err = e };
|
||||
const right = Leaf.new(ctx.allocator, leaf.buf[pos_end..], false, leaf.eol) catch |e| return .{ .err = e };
|
||||
const left = Leaf.new(ctx.allocator, leaf.buf[0..ctx.pos], leaf_bol, false) catch |e| return .{ .err = e };
|
||||
const right = Leaf.new(ctx.allocator, leaf.buf[ctx.pos + ctx.bytes ..], false, leaf.eol) catch |e| return .{ .err = e };
|
||||
result.replace = Node.new(ctx.allocator, left, right) catch |e| return .{ .err = e };
|
||||
ctx.count = 0;
|
||||
ctx.bytes = 0;
|
||||
}
|
||||
}
|
||||
if (ctx.count == 0 and !ctx.delete_next_bol)
|
||||
if (ctx.bytes == 0 and !ctx.delete_next_bol)
|
||||
result.keep_walking = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
var ctx: Ctx = .{ .allocator = allocator, .col = col, .count = count };
|
||||
var ctx: Ctx = .{ .allocator = allocator, .pos = pos_, .bytes = bytes };
|
||||
const found, const root = try self.walk_from_line_begin(allocator, line, Ctx.walker, &ctx, metrics_);
|
||||
return if (found) (root orelse error.Stop) else error.NotFound;
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ test "del_chars_with_tab_issue83" {
|
|||
defer a.free(line3);
|
||||
defer a.free(line4);
|
||||
break :blk line2.len + 1 +
|
||||
line3.len + 7 + 1 +
|
||||
line3.len + 1 +
|
||||
line4.len + 1;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue