refactor(Buffer): rename Metrix to Metrics
Metrix was a bit too silly
This commit is contained in:
		
							parent
							
								
									633cc5a1c1
								
							
						
					
					
						commit
						f06a7b3d6a
					
				
					 7 changed files with 211 additions and 211 deletions
				
			
		|  | @ -16,7 +16,7 @@ pub const View = @import("View.zig"); | ||||||
| pub const Selection = @import("Selection.zig"); | pub const Selection = @import("Selection.zig"); | ||||||
| pub const MetaWriter = std.ArrayList(u8).Writer; | pub const MetaWriter = std.ArrayList(u8).Writer; | ||||||
| 
 | 
 | ||||||
| pub const Metrix = struct { | pub const Metrics = struct { | ||||||
|     ctx: *const anyopaque, |     ctx: *const anyopaque, | ||||||
|     egc_length: egc_length_func, |     egc_length: egc_length_func, | ||||||
|     egc_chunk_width: egc_chunk_width_func, |     egc_chunk_width: egc_chunk_width_func, | ||||||
|  | @ -58,7 +58,7 @@ pub const WalkerMut = struct { | ||||||
|     pub const stop = WalkerMut{ .keep_walking = false }; |     pub const stop = WalkerMut{ .keep_walking = false }; | ||||||
|     pub const found = WalkerMut{ .found = true }; |     pub const found = WalkerMut{ .found = true }; | ||||||
| 
 | 
 | ||||||
|     const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) WalkerMut; |     const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) WalkerMut; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub const Walker = struct { | pub const Walker = struct { | ||||||
|  | @ -70,7 +70,7 @@ pub const Walker = struct { | ||||||
|     pub const stop = Walker{ .keep_walking = false }; |     pub const stop = Walker{ .keep_walking = false }; | ||||||
|     pub const found = Walker{ .found = true }; |     pub const found = Walker{ .found = true }; | ||||||
| 
 | 
 | ||||||
|     const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) Walker; |     const F = *const fn (ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub const Weights = struct { | pub const Weights = struct { | ||||||
|  | @ -152,7 +152,7 @@ pub const Leaf = struct { | ||||||
|         return self.buf.len == 0 and !self.bol and !self.eol; |         return self.buf.len == 0 and !self.bol and !self.eol; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn pos_to_width(self: *const Leaf, pos: *usize, abs_col_: usize, mtrx: Metrix) usize { |     fn pos_to_width(self: *const Leaf, pos: *usize, abs_col_: usize, metrics: Metrics) usize { | ||||||
|         var col: usize = 0; |         var col: usize = 0; | ||||||
|         var abs_col = abs_col_; |         var abs_col = abs_col_; | ||||||
|         var cols: c_int = 0; |         var cols: c_int = 0; | ||||||
|  | @ -163,7 +163,7 @@ pub const Leaf = struct { | ||||||
|                 buf = buf[1..]; |                 buf = buf[1..]; | ||||||
|                 pos.* -= 1; |                 pos.* -= 1; | ||||||
|             } else { |             } else { | ||||||
|                 const bytes = mtrx.egc_length(mtrx.ctx, buf, &cols, abs_col); |                 const bytes = metrics.egc_length(metrics.ctx, buf, &cols, abs_col); | ||||||
|                 buf = buf[bytes..]; |                 buf = buf[bytes..]; | ||||||
|                 pos.* -= bytes; |                 pos.* -= bytes; | ||||||
|             } |             } | ||||||
|  | @ -173,12 +173,12 @@ pub const Leaf = struct { | ||||||
|         return col; |         return col; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn width(self: *const Leaf, abs_col: usize, mtrx: Metrix) usize { |     fn width(self: *const Leaf, abs_col: usize, metrics: Metrics) usize { | ||||||
|         var pos: usize = std.math.maxInt(usize); |         var pos: usize = std.math.maxInt(usize); | ||||||
|         return self.pos_to_width(&pos, abs_col, mtrx); |         return self.pos_to_width(&pos, abs_col, metrics); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline fn width_to_pos(self: *const Leaf, col_: usize, abs_col_: usize, mtrx: Metrix) !usize { |     inline fn width_to_pos(self: *const Leaf, col_: usize, abs_col_: usize, metrics: Metrics) !usize { | ||||||
|         var abs_col = abs_col_; |         var abs_col = abs_col_; | ||||||
|         var col = col_; |         var col = col_; | ||||||
|         var cols: c_int = 0; |         var cols: c_int = 0; | ||||||
|  | @ -186,7 +186,7 @@ pub const Leaf = struct { | ||||||
|         return while (buf.len > 0) { |         return while (buf.len > 0) { | ||||||
|             if (col == 0) |             if (col == 0) | ||||||
|                 break @intFromPtr(buf.ptr) - @intFromPtr(self.buf.ptr); |                 break @intFromPtr(buf.ptr) - @intFromPtr(self.buf.ptr); | ||||||
|             const bytes = mtrx.egc_length(mtrx.ctx, buf, &cols, abs_col); |             const bytes = metrics.egc_length(metrics.ctx, buf, &cols, abs_col); | ||||||
|             buf = buf[bytes..]; |             buf = buf[bytes..]; | ||||||
|             if (col < cols) |             if (col < cols) | ||||||
|                 break @intFromPtr(buf.ptr) - @intFromPtr(self.buf.ptr); |                 break @intFromPtr(buf.ptr) - @intFromPtr(self.buf.ptr); | ||||||
|  | @ -195,20 +195,20 @@ pub const Leaf = struct { | ||||||
|         } else error.BufferUnderrun; |         } else error.BufferUnderrun; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline fn dump(self: *const Leaf, l: *ArrayList(u8), abs_col: usize, mtrx: Metrix) !void { |     inline fn dump(self: *const Leaf, l: *ArrayList(u8), abs_col: usize, metrics: Metrics) !void { | ||||||
|         var buf: [16]u8 = undefined; |         var buf: [16]u8 = undefined; | ||||||
|         const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{self.width(abs_col, mtrx)}); |         const wcwidth = try std.fmt.bufPrint(&buf, "{d}", .{self.width(abs_col, metrics)}); | ||||||
|         if (self.bol) |         if (self.bol) | ||||||
|             try l.appendSlice("BOL "); |             try l.appendSlice("BOL "); | ||||||
|         try l.appendSlice(wcwidth); |         try l.appendSlice(wcwidth); | ||||||
|         try l.append('"'); |         try l.append('"'); | ||||||
|         try debug_render_chunk(self.buf, l, mtrx); |         try debug_render_chunk(self.buf, l, metrics); | ||||||
|         try l.appendSlice("\" "); |         try l.appendSlice("\" "); | ||||||
|         if (self.eol) |         if (self.eol) | ||||||
|             try l.appendSlice("EOL "); |             try l.appendSlice("EOL "); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn debug_render_chunk(chunk: []const u8, l: *ArrayList(u8), mtrx: Metrix) !void { |     fn debug_render_chunk(chunk: []const u8, l: *ArrayList(u8), metrics: Metrics) !void { | ||||||
|         var cols: c_int = 0; |         var cols: c_int = 0; | ||||||
|         var buf = chunk; |         var buf = chunk; | ||||||
|         while (buf.len > 0) { |         while (buf.len > 0) { | ||||||
|  | @ -219,7 +219,7 @@ pub const Leaf = struct { | ||||||
|                     buf = buf[1..]; |                     buf = buf[1..]; | ||||||
|                 }, |                 }, | ||||||
|                 else => { |                 else => { | ||||||
|                     const bytes = mtrx.egc_length(mtrx.ctx, buf, &cols, 0); |                     const bytes = metrics.egc_length(metrics.ctx, buf, &cols, 0); | ||||||
|                     var buf_: [4096]u8 = undefined; |                     var buf_: [4096]u8 = undefined; | ||||||
|                     try l.appendSlice(try std.fmt.bufPrint(&buf_, "{s}", .{std.fmt.fmtSliceEscapeLower(buf[0..bytes])})); |                     try l.appendSlice(try std.fmt.bufPrint(&buf_, "{s}", .{std.fmt.fmtSliceEscapeLower(buf[0..bytes])})); | ||||||
|                     buf = buf[bytes..]; |                     buf = buf[bytes..]; | ||||||
|  | @ -321,27 +321,27 @@ const Node = union(enum) { | ||||||
|         return leaves.toOwnedSlice(); |         return leaves.toOwnedSlice(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn walk_const(self: *const Node, f: Walker.F, ctx: *anyopaque, mtrx: Metrix) Walker { |     fn walk_const(self: *const Node, f: Walker.F, ctx: *anyopaque, metrics: Metrics) Walker { | ||||||
|         switch (self.*) { |         switch (self.*) { | ||||||
|             .node => |*node| { |             .node => |*node| { | ||||||
|                 const left = node.left.walk_const(f, ctx, mtrx); |                 const left = node.left.walk_const(f, ctx, metrics); | ||||||
|                 if (!left.keep_walking) { |                 if (!left.keep_walking) { | ||||||
|                     var result = Walker{}; |                     var result = Walker{}; | ||||||
|                     result.err = left.err; |                     result.err = left.err; | ||||||
|                     result.found = left.found; |                     result.found = left.found; | ||||||
|                     return result; |                     return result; | ||||||
|                 } |                 } | ||||||
|                 const right = node.right.walk_const(f, ctx, mtrx); |                 const right = node.right.walk_const(f, ctx, metrics); | ||||||
|                 return node.merge_results_const(left, right); |                 return node.merge_results_const(left, right); | ||||||
|             }, |             }, | ||||||
|             .leaf => |*l| return f(ctx, l, mtrx), |             .leaf => |*l| return f(ctx, l, metrics), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn walk(self: *const Node, a: Allocator, f: WalkerMut.F, ctx: *anyopaque, mtrx: Metrix) WalkerMut { |     fn walk(self: *const Node, a: Allocator, f: WalkerMut.F, ctx: *anyopaque, metrics: Metrics) WalkerMut { | ||||||
|         switch (self.*) { |         switch (self.*) { | ||||||
|             .node => |*node| { |             .node => |*node| { | ||||||
|                 const left = node.left.walk(a, f, ctx, mtrx); |                 const left = node.left.walk(a, f, ctx, metrics); | ||||||
|                 if (!left.keep_walking) { |                 if (!left.keep_walking) { | ||||||
|                     var result = WalkerMut{}; |                     var result = WalkerMut{}; | ||||||
|                     result.err = left.err; |                     result.err = left.err; | ||||||
|  | @ -351,26 +351,26 @@ const Node = union(enum) { | ||||||
|                     } |                     } | ||||||
|                     return result; |                     return result; | ||||||
|                 } |                 } | ||||||
|                 const right = node.right.walk(a, f, ctx, mtrx); |                 const right = node.right.walk(a, f, ctx, metrics); | ||||||
|                 return node.merge_results(a, left, right); |                 return node.merge_results(a, left, right); | ||||||
|             }, |             }, | ||||||
|             .leaf => |*l| return f(ctx, l, mtrx), |             .leaf => |*l| return f(ctx, l, metrics), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn walk_from_line_begin_const_internal(self: *const Node, line: usize, f: Walker.F, ctx: *anyopaque, mtrx: Metrix) Walker { |     fn walk_from_line_begin_const_internal(self: *const Node, line: usize, f: Walker.F, ctx: *anyopaque, metrics: Metrics) Walker { | ||||||
|         switch (self.*) { |         switch (self.*) { | ||||||
|             .node => |*node| { |             .node => |*node| { | ||||||
|                 const left_bols = node.weights.bols; |                 const left_bols = node.weights.bols; | ||||||
|                 if (line >= left_bols) |                 if (line >= left_bols) | ||||||
|                     return node.right.walk_from_line_begin_const_internal(line - left_bols, f, ctx, mtrx); |                     return node.right.walk_from_line_begin_const_internal(line - left_bols, f, ctx, metrics); | ||||||
|                 const left_result = node.left.walk_from_line_begin_const_internal(line, f, ctx, mtrx); |                 const left_result = node.left.walk_from_line_begin_const_internal(line, f, ctx, metrics); | ||||||
|                 const right_result = if (left_result.found and left_result.keep_walking) node.right.walk_const(f, ctx, mtrx) else Walker{}; |                 const right_result = if (left_result.found and left_result.keep_walking) node.right.walk_const(f, ctx, metrics) else Walker{}; | ||||||
|                 return node.merge_results_const(left_result, right_result); |                 return node.merge_results_const(left_result, right_result); | ||||||
|             }, |             }, | ||||||
|             .leaf => |*l| { |             .leaf => |*l| { | ||||||
|                 if (line == 0) { |                 if (line == 0) { | ||||||
|                     var result = f(ctx, l, mtrx); |                     var result = f(ctx, l, metrics); | ||||||
|                     if (result.err) |_| return result; |                     if (result.err) |_| return result; | ||||||
|                     result.found = true; |                     result.found = true; | ||||||
|                     return result; |                     return result; | ||||||
|  | @ -380,18 +380,18 @@ const Node = union(enum) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn walk_from_line_begin_const(self: *const Node, line: usize, f: Walker.F, ctx: *anyopaque, mtrx: Metrix) !bool { |     pub fn walk_from_line_begin_const(self: *const Node, line: usize, f: Walker.F, ctx: *anyopaque, metrics: Metrics) !bool { | ||||||
|         const result = self.walk_from_line_begin_const_internal(line, f, ctx, mtrx); |         const result = self.walk_from_line_begin_const_internal(line, f, ctx, metrics); | ||||||
|         if (result.err) |e| return e; |         if (result.err) |e| return e; | ||||||
|         return result.found; |         return result.found; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn walk_from_line_begin_internal(self: *const Node, a: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, mtrx: Metrix) WalkerMut { |     fn walk_from_line_begin_internal(self: *const Node, a: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, metrics: Metrics) WalkerMut { | ||||||
|         switch (self.*) { |         switch (self.*) { | ||||||
|             .node => |*node| { |             .node => |*node| { | ||||||
|                 const left_bols = node.weights.bols; |                 const left_bols = node.weights.bols; | ||||||
|                 if (line >= left_bols) { |                 if (line >= left_bols) { | ||||||
|                     const right_result = node.right.walk_from_line_begin_internal(a, line - left_bols, f, ctx, mtrx); |                     const right_result = node.right.walk_from_line_begin_internal(a, line - left_bols, f, ctx, metrics); | ||||||
|                     if (right_result.replace) |p| { |                     if (right_result.replace) |p| { | ||||||
|                         var result = WalkerMut{}; |                         var result = WalkerMut{}; | ||||||
|                         result.err = right_result.err; |                         result.err = right_result.err; | ||||||
|  | @ -406,13 +406,13 @@ const Node = union(enum) { | ||||||
|                         return right_result; |                         return right_result; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 const left_result = node.left.walk_from_line_begin_internal(a, line, f, ctx, mtrx); |                 const left_result = node.left.walk_from_line_begin_internal(a, line, f, ctx, metrics); | ||||||
|                 const right_result = if (left_result.found and left_result.keep_walking) node.right.walk(a, f, ctx, mtrx) else WalkerMut{}; |                 const right_result = if (left_result.found and left_result.keep_walking) node.right.walk(a, f, ctx, metrics) else WalkerMut{}; | ||||||
|                 return node.merge_results(a, left_result, right_result); |                 return node.merge_results(a, left_result, right_result); | ||||||
|             }, |             }, | ||||||
|             .leaf => |*l| { |             .leaf => |*l| { | ||||||
|                 if (line == 0) { |                 if (line == 0) { | ||||||
|                     var result = f(ctx, l, mtrx); |                     var result = f(ctx, l, metrics); | ||||||
|                     if (result.err) |_| { |                     if (result.err) |_| { | ||||||
|                         result.replace = null; |                         result.replace = null; | ||||||
|                         return result; |                         return result; | ||||||
|  | @ -425,8 +425,8 @@ const Node = union(enum) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn walk_from_line_begin(self: *const Node, a: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, mtrx: Metrix) !struct { bool, ?Root } { |     pub fn walk_from_line_begin(self: *const Node, a: Allocator, line: usize, f: WalkerMut.F, ctx: *anyopaque, metrics: Metrics) !struct { bool, ?Root } { | ||||||
|         const result = self.walk_from_line_begin_internal(a, line, f, ctx, mtrx); |         const result = self.walk_from_line_begin_internal(a, line, f, ctx, metrics); | ||||||
|         if (result.err) |e| return e; |         if (result.err) |e| return e; | ||||||
|         return .{ result.found, result.replace }; |         return .{ result.found, result.replace }; | ||||||
|     } |     } | ||||||
|  | @ -466,27 +466,27 @@ const Node = union(enum) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const EgcF = *const fn (ctx: *anyopaque, egc: []const u8, wcwidth: usize, mtrx: Metrix) Walker; |     const EgcF = *const fn (ctx: *anyopaque, egc: []const u8, wcwidth: usize, metrics: Metrics) Walker; | ||||||
| 
 | 
 | ||||||
|     pub fn walk_egc_forward(self: *const Node, line: usize, walker_f: EgcF, walker_ctx: *anyopaque, mtrx_: Metrix) !void { |     pub fn walk_egc_forward(self: *const Node, line: usize, walker_f: EgcF, walker_ctx: *anyopaque, metrics_: Metrics) !void { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             walker_f: EgcF, |             walker_f: EgcF, | ||||||
|             walker_ctx: @TypeOf(walker_ctx), |             walker_ctx: @TypeOf(walker_ctx), | ||||||
|             abs_col: usize = 0, |             abs_col: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, leaf: *const Self.Leaf, mtrx: Metrix) Walker { |             fn walker(ctx_: *anyopaque, leaf: *const Self.Leaf, metrics: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 var buf: []const u8 = leaf.buf; |                 var buf: []const u8 = leaf.buf; | ||||||
|                 while (buf.len > 0) { |                 while (buf.len > 0) { | ||||||
|                     var cols: c_int = undefined; |                     var cols: c_int = undefined; | ||||||
|                     const bytes = mtrx.egc_length(mtrx.ctx, buf, &cols, ctx.abs_col); |                     const bytes = metrics.egc_length(metrics.ctx, buf, &cols, ctx.abs_col); | ||||||
|                     const ret = ctx.walker_f(ctx.walker_ctx, buf[0..bytes], @intCast(cols), mtrx); |                     const ret = ctx.walker_f(ctx.walker_ctx, buf[0..bytes], @intCast(cols), metrics); | ||||||
|                     if (ret.err) |e| return .{ .err = e }; |                     if (ret.err) |e| return .{ .err = e }; | ||||||
|                     buf = buf[bytes..]; |                     buf = buf[bytes..]; | ||||||
|                     ctx.abs_col += @intCast(cols); |                     ctx.abs_col += @intCast(cols); | ||||||
|                     if (!ret.keep_walking) return Walker.stop; |                     if (!ret.keep_walking) return Walker.stop; | ||||||
|                 } |                 } | ||||||
|                 if (leaf.eol) { |                 if (leaf.eol) { | ||||||
|                     const ret = ctx.walker_f(ctx.walker_ctx, "\n", 1, mtrx); |                     const ret = ctx.walker_f(ctx.walker_ctx, "\n", 1, metrics); | ||||||
|                     if (ret.err) |e| return .{ .err = e }; |                     if (ret.err) |e| return .{ .err = e }; | ||||||
|                     if (!ret.keep_walking) return Walker.stop; |                     if (!ret.keep_walking) return Walker.stop; | ||||||
|                     ctx.abs_col = 0; |                     ctx.abs_col = 0; | ||||||
|  | @ -495,16 +495,16 @@ const Node = union(enum) { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: Ctx = .{ .walker_f = walker_f, .walker_ctx = walker_ctx }; |         var ctx: Ctx = .{ .walker_f = walker_f, .walker_ctx = walker_ctx }; | ||||||
|         const found = try self.walk_from_line_begin_const(line, Ctx.walker, &ctx, mtrx_); |         const found = try self.walk_from_line_begin_const(line, Ctx.walker, &ctx, metrics_); | ||||||
|         if (!found) return error.NotFound; |         if (!found) return error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn ecg_at(self: *const Node, line: usize, col: usize, mtrx: Metrix) error{NotFound}!struct { []const u8, usize, usize } { |     pub fn ecg_at(self: *const Node, line: usize, col: usize, metrics: Metrics) error{NotFound}!struct { []const u8, usize, usize } { | ||||||
|         const ctx_ = struct { |         const ctx_ = struct { | ||||||
|             col: usize, |             col: usize, | ||||||
|             at: ?[]const u8 = null, |             at: ?[]const u8 = null, | ||||||
|             wcwidth: usize = 0, |             wcwidth: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrix) Walker { |             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 ctx.at = egc; |                 ctx.at = egc; | ||||||
|                 ctx.wcwidth = wcwidth; |                 ctx.wcwidth = wcwidth; | ||||||
|  | @ -515,20 +515,20 @@ const Node = union(enum) { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: ctx_ = .{ .col = col }; |         var ctx: ctx_ = .{ .col = col }; | ||||||
|         self.walk_egc_forward(line, ctx_.walker, &ctx, mtrx) catch return .{ "?", 1, 0 }; |         self.walk_egc_forward(line, ctx_.walker, &ctx, metrics) catch return .{ "?", 1, 0 }; | ||||||
|         return if (ctx.at) |at| .{ at, ctx.wcwidth, ctx.col } else error.NotFound; |         return if (ctx.at) |at| .{ at, ctx.wcwidth, ctx.col } else error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn test_at(self: *const Node, pred: *const fn (c: []const u8) bool, line: usize, col: usize, mtrx: Metrix) bool { |     pub fn test_at(self: *const Node, pred: *const fn (c: []const u8) bool, line: usize, col: usize, metrics: Metrics) bool { | ||||||
|         const ecg, _, _ = self.ecg_at(line, col, mtrx) catch return false; |         const ecg, _, _ = self.ecg_at(line, col, metrics) catch return false; | ||||||
|         return pred(ecg); |         return pred(ecg); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), mtrx: Metrix) error{ Stop, NoSpaceLeft }!void { |     pub fn get_line_width_map(self: *const Node, line: usize, map: *ArrayList(usize), metrics: Metrics) error{ Stop, NoSpaceLeft }!void { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             map: *ArrayList(usize), |             map: *ArrayList(usize), | ||||||
|             wcwidth: usize = 0, |             wcwidth: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrix) Walker { |             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 var n = egc.len; |                 var n = egc.len; | ||||||
|                 while (n > 0) : (n -= 1) { |                 while (n > 0) : (n -= 1) { | ||||||
|  | @ -540,20 +540,20 @@ const Node = union(enum) { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: Ctx = .{ .map = map }; |         var ctx: Ctx = .{ .map = map }; | ||||||
|         self.walk_egc_forward(line, Ctx.walker, &ctx, mtrx) catch |e| return switch (e) { |         self.walk_egc_forward(line, Ctx.walker, &ctx, metrics) catch |e| return switch (e) { | ||||||
|             error.NoSpaceLeft => error.NoSpaceLeft, |             error.NoSpaceLeft => error.NoSpaceLeft, | ||||||
|             else => error.Stop, |             else => error.Stop, | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_range(self: *const Node, sel: Selection, copy_buf: ?[]u8, size: ?*usize, wcwidth_: ?*usize, mtrx_: Metrix) error{ Stop, NoSpaceLeft }!?[]u8 { |     pub fn get_range(self: *const Node, sel: Selection, copy_buf: ?[]u8, size: ?*usize, wcwidth_: ?*usize, metrics_: Metrics) error{ Stop, NoSpaceLeft }!?[]u8 { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             col: usize = 0, |             col: usize = 0, | ||||||
|             sel: Selection, |             sel: Selection, | ||||||
|             out: ?[]u8, |             out: ?[]u8, | ||||||
|             bytes: usize = 0, |             bytes: usize = 0, | ||||||
|             wcwidth: usize = 0, |             wcwidth: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrix) Walker { |             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 if (ctx.col < ctx.sel.begin.col) { |                 if (ctx.col < ctx.sel.begin.col) { | ||||||
|                     ctx.col += wcwidth; |                     ctx.col += wcwidth; | ||||||
|  | @ -586,7 +586,7 @@ const Node = union(enum) { | ||||||
|         ctx.sel.normalize(); |         ctx.sel.normalize(); | ||||||
|         if (ctx.sel.begin.eql(ctx.sel.end)) |         if (ctx.sel.begin.eql(ctx.sel.end)) | ||||||
|             return error.Stop; |             return error.Stop; | ||||||
|         self.walk_egc_forward(ctx.sel.begin.row, Ctx.walker, &ctx, mtrx_) catch |e| return switch (e) { |         self.walk_egc_forward(ctx.sel.begin.row, Ctx.walker, &ctx, metrics_) catch |e| return switch (e) { | ||||||
|             error.NoSpaceLeft => error.NoSpaceLeft, |             error.NoSpaceLeft => error.NoSpaceLeft, | ||||||
|             else => error.Stop, |             else => error.Stop, | ||||||
|         }; |         }; | ||||||
|  | @ -595,20 +595,20 @@ const Node = union(enum) { | ||||||
|         return if (copy_buf) |buf_| buf_[0..ctx.bytes] else null; |         return if (copy_buf) |buf_| buf_[0..ctx.bytes] else null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn delete_range(self: *const Node, sel: Selection, a: Allocator, size: ?*usize, mtrx: Metrix) error{Stop}!Root { |     pub fn delete_range(self: *const Node, sel: Selection, a: Allocator, size: ?*usize, metrics: Metrics) error{Stop}!Root { | ||||||
|         var wcwidth: usize = 0; |         var wcwidth: usize = 0; | ||||||
|         _ = self.get_range(sel, null, size, &wcwidth, mtrx) catch return error.Stop; |         _ = self.get_range(sel, null, size, &wcwidth, metrics) catch return error.Stop; | ||||||
|         return self.del_chars(sel.begin.row, sel.begin.col, wcwidth, a, mtrx) catch return error.Stop; |         return self.del_chars(sel.begin.row, sel.begin.col, wcwidth, a, metrics) catch return error.Stop; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn del_chars(self: *const Node, line: usize, col: usize, count: usize, a: Allocator, mtrx_: Metrix) !Root { |     pub fn del_chars(self: *const Node, line: usize, col: usize, count: usize, a: Allocator, metrics_: Metrics) !Root { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             a: Allocator, |             a: Allocator, | ||||||
|             col: usize, |             col: usize, | ||||||
|             abs_col: usize = 0, |             abs_col: usize = 0, | ||||||
|             count: usize, |             count: usize, | ||||||
|             delete_next_bol: bool = false, |             delete_next_bol: bool = false, | ||||||
|             fn walker(Ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) WalkerMut { |             fn walker(Ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) WalkerMut { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(Ctx))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(Ctx))); | ||||||
|                 var result = WalkerMut.keep_walking; |                 var result = WalkerMut.keep_walking; | ||||||
|                 if (ctx.delete_next_bol and ctx.count == 0) { |                 if (ctx.delete_next_bol and ctx.count == 0) { | ||||||
|  | @ -617,7 +617,7 @@ const Node = union(enum) { | ||||||
|                     ctx.delete_next_bol = false; |                     ctx.delete_next_bol = false; | ||||||
|                     return result; |                     return result; | ||||||
|                 } |                 } | ||||||
|                 const leaf_wcwidth = leaf.width(ctx.abs_col, mtrx); |                 const leaf_wcwidth = leaf.width(ctx.abs_col, metrics); | ||||||
|                 const leaf_bol = leaf.bol and !ctx.delete_next_bol; |                 const leaf_bol = leaf.bol and !ctx.delete_next_bol; | ||||||
|                 ctx.delete_next_bol = false; |                 ctx.delete_next_bol = false; | ||||||
|                 const base_col = ctx.abs_col; |                 const base_col = ctx.abs_col; | ||||||
|  | @ -641,7 +641,7 @@ const Node = union(enum) { | ||||||
|                             result.replace = Leaf.new(ctx.a, "", leaf_bol, leaf.eol) catch |e| return .{ .err = e }; |                             result.replace = Leaf.new(ctx.a, "", leaf_bol, leaf.eol) catch |e| return .{ .err = e }; | ||||||
|                             ctx.count = 0; |                             ctx.count = 0; | ||||||
|                         } else { |                         } else { | ||||||
|                             const pos = leaf.width_to_pos(ctx.count, base_col, mtrx) catch |e| return .{ .err = e }; |                             const pos = leaf.width_to_pos(ctx.count, base_col, metrics) catch |e| return .{ .err = e }; | ||||||
|                             result.replace = Leaf.new(ctx.a, leaf.buf[pos..], leaf_bol, leaf.eol) catch |e| return .{ .err = e }; |                             result.replace = Leaf.new(ctx.a, leaf.buf[pos..], leaf_bol, leaf.eol) catch |e| return .{ .err = e }; | ||||||
|                             ctx.count = 0; |                             ctx.count = 0; | ||||||
|                         } |                         } | ||||||
|  | @ -655,7 +655,7 @@ const Node = union(enum) { | ||||||
|                     } else { |                     } else { | ||||||
|                         if (ctx.col + ctx.count >= leaf_wcwidth) { |                         if (ctx.col + ctx.count >= leaf_wcwidth) { | ||||||
|                             ctx.count -= leaf_wcwidth - ctx.col; |                             ctx.count -= leaf_wcwidth - ctx.col; | ||||||
|                             const pos = leaf.width_to_pos(ctx.col, base_col, mtrx) catch |e| return .{ .err = e }; |                             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: { |                             const leaf_eol = if (leaf.eol and ctx.count > 0) leaf_eol: { | ||||||
|                                 ctx.count -= 1; |                                 ctx.count -= 1; | ||||||
|                                 ctx.delete_next_bol = true; |                                 ctx.delete_next_bol = true; | ||||||
|  | @ -664,8 +664,8 @@ const Node = union(enum) { | ||||||
|                             result.replace = Leaf.new(ctx.a, leaf.buf[0..pos], leaf_bol, leaf_eol) catch |e| return .{ .err = e }; |                             result.replace = Leaf.new(ctx.a, leaf.buf[0..pos], leaf_bol, leaf_eol) catch |e| return .{ .err = e }; | ||||||
|                             ctx.col = 0; |                             ctx.col = 0; | ||||||
|                         } else { |                         } else { | ||||||
|                             const pos = leaf.width_to_pos(ctx.col, base_col, mtrx) catch |e| return .{ .err = e }; |                             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, mtrx) 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.a, leaf.buf[0..pos], leaf_bol, false) catch |e| return .{ .err = e }; |                             const left = Leaf.new(ctx.a, leaf.buf[0..pos], leaf_bol, false) catch |e| return .{ .err = e }; | ||||||
|                             const right = Leaf.new(ctx.a, leaf.buf[pos_end..], false, leaf.eol) catch |e| return .{ .err = e }; |                             const right = Leaf.new(ctx.a, leaf.buf[pos_end..], false, leaf.eol) catch |e| return .{ .err = e }; | ||||||
|                             result.replace = Node.new(ctx.a, left, right) catch |e| return .{ .err = e }; |                             result.replace = Node.new(ctx.a, left, right) catch |e| return .{ .err = e }; | ||||||
|  | @ -679,7 +679,7 @@ const Node = union(enum) { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: Ctx = .{ .a = a, .col = col, .count = count }; |         var ctx: Ctx = .{ .a = a, .col = col, .count = count }; | ||||||
|         const found, const root = try self.walk_from_line_begin(a, line, Ctx.walker, &ctx, mtrx_); |         const found, const root = try self.walk_from_line_begin(a, line, Ctx.walker, &ctx, metrics_); | ||||||
|         return if (found) (if (root) |r| r else error.Stop) else error.NotFound; |         return if (found) (if (root) |r| r else error.Stop) else error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -695,46 +695,46 @@ const Node = union(enum) { | ||||||
|         return Node.new(a, try merge_in_place(leaves[0..mid], a), try merge_in_place(leaves[mid..], a)); |         return Node.new(a, try merge_in_place(leaves[0..mid], a), try merge_in_place(leaves[mid..], a)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_line(self: *const Node, line: usize, result: *ArrayList(u8), mtrx: Metrix) !void { |     pub fn get_line(self: *const Node, line: usize, result: *ArrayList(u8), metrics: Metrics) !void { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             line: *ArrayList(u8), |             line: *ArrayList(u8), | ||||||
|             fn walker(ctx_: *anyopaque, leaf: *const Leaf, _: Metrix) Walker { |             fn walker(ctx_: *anyopaque, leaf: *const Leaf, _: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 ctx.line.appendSlice(leaf.buf) catch |e| return .{ .err = e }; |                 ctx.line.appendSlice(leaf.buf) catch |e| return .{ .err = e }; | ||||||
|                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; |                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: Ctx = .{ .line = result }; |         var ctx: Ctx = .{ .line = result }; | ||||||
|         const found = self.walk_from_line_begin_const(line, Ctx.walker, &ctx, mtrx) catch false; |         const found = self.walk_from_line_begin_const(line, Ctx.walker, &ctx, metrics) catch false; | ||||||
|         return if (!found) error.NotFound; |         return if (!found) error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn line_width(self: *const Node, line: usize, mtrx_: Metrix) !usize { |     pub fn line_width(self: *const Node, line: usize, metrics_: Metrics) !usize { | ||||||
|         const do = struct { |         const do = struct { | ||||||
|             result: usize = 0, |             result: usize = 0, | ||||||
|             fn walker(ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) Walker { |             fn walker(ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker { | ||||||
|                 const do = @as(*@This(), @ptrCast(@alignCast(ctx))); |                 const do = @as(*@This(), @ptrCast(@alignCast(ctx))); | ||||||
|                 do.result += leaf.width(do.result, mtrx); |                 do.result += leaf.width(do.result, metrics); | ||||||
|                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; |                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: do = .{}; |         var ctx: do = .{}; | ||||||
|         const found = self.walk_from_line_begin_const(line, do.walker, &ctx, mtrx_) catch true; |         const found = self.walk_from_line_begin_const(line, do.walker, &ctx, metrics_) catch true; | ||||||
|         return if (found) ctx.result else error.NotFound; |         return if (found) ctx.result else error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn pos_to_width(self: *const Node, line: usize, pos: usize, mtrx_: Metrix) !usize { |     pub fn pos_to_width(self: *const Node, line: usize, pos: usize, metrics_: Metrics) !usize { | ||||||
|         const do = struct { |         const do = struct { | ||||||
|             result: usize = 0, |             result: usize = 0, | ||||||
|             pos: usize, |             pos: usize, | ||||||
|             fn walker(ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) Walker { |             fn walker(ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker { | ||||||
|                 const do = @as(*@This(), @ptrCast(@alignCast(ctx))); |                 const do = @as(*@This(), @ptrCast(@alignCast(ctx))); | ||||||
|                 do.result += leaf.pos_to_width(&do.pos, do.result, mtrx); |                 do.result += leaf.pos_to_width(&do.pos, do.result, metrics); | ||||||
|                 return if (!(leaf.eol or do.pos == 0)) Walker.keep_walking else Walker.stop; |                 return if (!(leaf.eol or do.pos == 0)) Walker.keep_walking else Walker.stop; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: do = .{ .pos = pos }; |         var ctx: do = .{ .pos = pos }; | ||||||
|         const found = self.walk_from_line_begin_const(line, do.walker, &ctx, mtrx_) catch true; |         const found = self.walk_from_line_begin_const(line, do.walker, &ctx, metrics_) catch true; | ||||||
|         return if (found) ctx.result else error.NotFound; |         return if (found) ctx.result else error.NotFound; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -744,7 +744,7 @@ const Node = union(enum) { | ||||||
|         col_: usize, |         col_: usize, | ||||||
|         s: []const u8, |         s: []const u8, | ||||||
|         a: Allocator, |         a: Allocator, | ||||||
|         mtrx_: Metrix, |         metrics_: Metrics, | ||||||
|     ) !struct { usize, usize, Root } { |     ) !struct { usize, usize, Root } { | ||||||
|         var self = self_; |         var self = self_; | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|  | @ -754,9 +754,9 @@ const Node = union(enum) { | ||||||
|             s: []const u8, |             s: []const u8, | ||||||
|             eol: bool, |             eol: bool, | ||||||
| 
 | 
 | ||||||
|             fn walker(ctx: *anyopaque, leaf: *const Leaf, mtrx: Metrix) WalkerMut { |             fn walker(ctx: *anyopaque, leaf: *const Leaf, metrics: Metrics) WalkerMut { | ||||||
|                 const Ctx = @as(*@This(), @ptrCast(@alignCast(ctx))); |                 const Ctx = @as(*@This(), @ptrCast(@alignCast(ctx))); | ||||||
|                 const leaf_wcwidth = leaf.width(Ctx.abs_col, mtrx); |                 const leaf_wcwidth = leaf.width(Ctx.abs_col, metrics); | ||||||
|                 const base_col = Ctx.abs_col; |                 const base_col = Ctx.abs_col; | ||||||
|                 Ctx.abs_col += leaf_wcwidth; |                 Ctx.abs_col += leaf_wcwidth; | ||||||
| 
 | 
 | ||||||
|  | @ -788,7 +788,7 @@ const Node = union(enum) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (leaf_wcwidth > Ctx.col) { |                 if (leaf_wcwidth > Ctx.col) { | ||||||
|                     const pos = leaf.width_to_pos(Ctx.col, base_col, mtrx) catch |e| return .{ .err = e }; |                     const pos = leaf.width_to_pos(Ctx.col, base_col, metrics) catch |e| return .{ .err = e }; | ||||||
|                     if (Ctx.eol and Ctx.s.len == 0) { |                     if (Ctx.eol and Ctx.s.len == 0) { | ||||||
|                         const left = Leaf.new(Ctx.a, leaf.buf[0..pos], leaf.bol, Ctx.eol) catch |e| return .{ .err = e }; |                         const left = Leaf.new(Ctx.a, leaf.buf[0..pos], leaf.bol, Ctx.eol) catch |e| return .{ .err = e }; | ||||||
|                         const right = Leaf.new(Ctx.a, leaf.buf[pos..], Ctx.eol, leaf.eol) catch |e| return .{ .err = e }; |                         const right = Leaf.new(Ctx.a, leaf.buf[pos..], Ctx.eol, leaf.eol) catch |e| return .{ .err = e }; | ||||||
|  | @ -825,14 +825,14 @@ const Node = union(enum) { | ||||||
|                 need_eol = false; |                 need_eol = false; | ||||||
|             } |             } | ||||||
|             var ctx: Ctx = .{ .a = a, .col = col, .s = chunk, .eol = need_eol }; |             var ctx: Ctx = .{ .a = a, .col = col, .s = chunk, .eol = need_eol }; | ||||||
|             const found, const replace = try self.walk_from_line_begin(a, line, Ctx.walker, &ctx, mtrx_); |             const found, const replace = try self.walk_from_line_begin(a, line, Ctx.walker, &ctx, metrics_); | ||||||
|             if (!found) return error.NotFound; |             if (!found) return error.NotFound; | ||||||
|             if (replace) |root| self = root; |             if (replace) |root| self = root; | ||||||
|             if (need_eol) { |             if (need_eol) { | ||||||
|                 line += 1; |                 line += 1; | ||||||
|                 col = 0; |                 col = 0; | ||||||
|             } else { |             } else { | ||||||
|                 col += mtrx_.egc_chunk_width(mtrx_.ctx, chunk, col); |                 col += metrics_.egc_chunk_width(metrics_.ctx, chunk, col); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return .{ line, col, self }; |         return .{ line, col, self }; | ||||||
|  | @ -925,19 +925,19 @@ const Node = union(enum) { | ||||||
|         return self.store(ctx.writer()); |         return self.store(ctx.writer()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn debug_render_chunks(self: *const Node, line: usize, output: *ArrayList(u8), mtrx_: Metrix) !void { |     pub fn debug_render_chunks(self: *const Node, line: usize, output: *ArrayList(u8), metrics_: Metrics) !void { | ||||||
|         const ctx_ = struct { |         const ctx_ = struct { | ||||||
|             l: *ArrayList(u8), |             l: *ArrayList(u8), | ||||||
|             wcwidth: usize = 0, |             wcwidth: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, leaf: *const Leaf, mtrx: Metrix) Walker { |             fn walker(ctx_: *anyopaque, leaf: *const Leaf, metrics: Metrics) Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 leaf.dump(ctx.l, ctx.wcwidth, mtrx) catch |e| return .{ .err = e }; |                 leaf.dump(ctx.l, ctx.wcwidth, metrics) catch |e| return .{ .err = e }; | ||||||
|                 ctx.wcwidth += leaf.width(ctx.wcwidth, mtrx); |                 ctx.wcwidth += leaf.width(ctx.wcwidth, metrics); | ||||||
|                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; |                 return if (!leaf.eol) Walker.keep_walking else Walker.stop; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: ctx_ = .{ .l = output }; |         var ctx: ctx_ = .{ .l = output }; | ||||||
|         const found = self.walk_from_line_begin_const(line, ctx_.walker, &ctx, mtrx_) catch true; |         const found = self.walk_from_line_begin_const(line, ctx_.walker, &ctx, metrics_) catch true; | ||||||
|         if (!found) return error.NotFound; |         if (!found) return error.NotFound; | ||||||
| 
 | 
 | ||||||
|         var buf: [16]u8 = undefined; |         var buf: [16]u8 = undefined; | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ const cbor = @import("cbor"); | ||||||
| const Buffer = @import("Buffer.zig"); | const Buffer = @import("Buffer.zig"); | ||||||
| const View = @import("View.zig"); | const View = @import("View.zig"); | ||||||
| const Selection = @import("Selection.zig"); | const Selection = @import("Selection.zig"); | ||||||
| const Metrix = Buffer.Metrix; | const Metrics = Buffer.Metrics; | ||||||
| 
 | 
 | ||||||
| row: usize = 0, | row: usize = 0, | ||||||
| col: usize = 0, | col: usize = 0, | ||||||
|  | @ -27,20 +27,20 @@ pub inline fn right_of(self: Self, other: Self) bool { | ||||||
|     return if (self.row > other.row) true else if (self.row == other.row and self.col > other.col) true else false; |     return if (self.row > other.row) true else if (self.row == other.row and self.col > other.col) true else false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn clamp_to_buffer(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | pub fn clamp_to_buffer(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     self.row = @min(self.row, root.lines() - 1); |     self.row = @min(self.row, root.lines() - 1); | ||||||
|     self.col = @min(self.col, root.line_width(self.row, mtrx) catch 0); |     self.col = @min(self.col, root.line_width(self.row, metrics) catch 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn follow_target(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | fn follow_target(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     self.col = @min(self.target, root.line_width(self.row, mtrx) catch 0); |     self.col = @min(self.target, root.line_width(self.row, metrics) catch 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn move_right_no_target(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | fn move_right_no_target(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     const lines = root.lines(); |     const lines = root.lines(); | ||||||
|     if (lines <= self.row) return error.Stop; |     if (lines <= self.row) return error.Stop; | ||||||
|     if (self.col < root.line_width(self.row, mtrx) catch 0) { |     if (self.col < root.line_width(self.row, metrics) catch 0) { | ||||||
|         _, const wcwidth, const offset = root.ecg_at(self.row, self.col, mtrx) catch return error.Stop; |         _, const wcwidth, const offset = root.ecg_at(self.row, self.col, metrics) catch return error.Stop; | ||||||
|         self.col += wcwidth - offset; |         self.col += wcwidth - offset; | ||||||
|     } else if (self.row < lines - 1) { |     } else if (self.row < lines - 1) { | ||||||
|         self.col = 0; |         self.col = 0; | ||||||
|  | @ -48,73 +48,73 @@ fn move_right_no_target(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | ||||||
|     } else return error.Stop; |     } else return error.Stop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_right(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | pub fn move_right(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     try self.move_right_no_target(root, mtrx); |     try self.move_right_no_target(root, metrics); | ||||||
|     self.target = self.col; |     self.target = self.col; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn move_left_no_target(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | fn move_left_no_target(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     if (self.col == 0) { |     if (self.col == 0) { | ||||||
|         if (self.row == 0) return error.Stop; |         if (self.row == 0) return error.Stop; | ||||||
|         self.row -= 1; |         self.row -= 1; | ||||||
|         self.col = root.line_width(self.row, mtrx) catch 0; |         self.col = root.line_width(self.row, metrics) catch 0; | ||||||
|     } else { |     } else { | ||||||
|         _, const wcwidth, _ = root.ecg_at(self.row, self.col - 1, mtrx) catch return error.Stop; |         _, const wcwidth, _ = root.ecg_at(self.row, self.col - 1, metrics) catch return error.Stop; | ||||||
|         if (self.col > wcwidth) self.col -= wcwidth else self.col = 0; |         if (self.col > wcwidth) self.col -= wcwidth else self.col = 0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_left(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | pub fn move_left(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     try self.move_left_no_target(root, mtrx); |     try self.move_left_no_target(root, metrics); | ||||||
|     self.target = self.col; |     self.target = self.col; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_up(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | pub fn move_up(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     if (self.row > 0) { |     if (self.row > 0) { | ||||||
|         self.row -= 1; |         self.row -= 1; | ||||||
|         self.follow_target(root, mtrx); |         self.follow_target(root, metrics); | ||||||
|         self.move_left_no_target(root, mtrx) catch return; |         self.move_left_no_target(root, metrics) catch return; | ||||||
|         try self.move_right_no_target(root, mtrx); |         try self.move_right_no_target(root, metrics); | ||||||
|     } else return error.Stop; |     } else return error.Stop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_down(self: *Self, root: Buffer.Root, mtrx: Metrix) !void { | pub fn move_down(self: *Self, root: Buffer.Root, metrics: Metrics) !void { | ||||||
|     if (self.row < root.lines() - 1) { |     if (self.row < root.lines() - 1) { | ||||||
|         self.row += 1; |         self.row += 1; | ||||||
|         self.follow_target(root, mtrx); |         self.follow_target(root, metrics); | ||||||
|         self.move_left_no_target(root, mtrx) catch return; |         self.move_left_no_target(root, metrics) catch return; | ||||||
|         try self.move_right_no_target(root, mtrx); |         try self.move_right_no_target(root, metrics); | ||||||
|     } else return error.Stop; |     } else return error.Stop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_page_up(self: *Self, root: Buffer.Root, view: *const View, mtrx: Metrix) void { | pub fn move_page_up(self: *Self, root: Buffer.Root, view: *const View, metrics: Metrics) void { | ||||||
|     self.row = if (self.row > view.rows) self.row - view.rows else 0; |     self.row = if (self.row > view.rows) self.row - view.rows else 0; | ||||||
|     self.follow_target(root, mtrx); |     self.follow_target(root, metrics); | ||||||
|     self.move_left_no_target(root, mtrx) catch return; |     self.move_left_no_target(root, metrics) catch return; | ||||||
|     self.move_right_no_target(root, mtrx) catch return; |     self.move_right_no_target(root, metrics) catch return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_page_down(self: *Self, root: Buffer.Root, view: *const View, mtrx: Metrix) void { | pub fn move_page_down(self: *Self, root: Buffer.Root, view: *const View, metrics: Metrics) void { | ||||||
|     if (root.lines() > self.row + view.rows) { |     if (root.lines() > self.row + view.rows) { | ||||||
|         self.row += view.rows; |         self.row += view.rows; | ||||||
|     } else self.move_buffer_last(root, mtrx); |     } else self.move_buffer_last(root, metrics); | ||||||
|     self.follow_target(root, mtrx); |     self.follow_target(root, metrics); | ||||||
|     self.move_left_no_target(root, mtrx) catch return; |     self.move_left_no_target(root, metrics) catch return; | ||||||
|     self.move_right_no_target(root, mtrx) catch return; |     self.move_right_no_target(root, metrics) catch return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_to(self: *Self, root: Buffer.Root, row: usize, col: usize, mtrx: Metrix) !void { | pub fn move_to(self: *Self, root: Buffer.Root, row: usize, col: usize, metrics: Metrics) !void { | ||||||
|     if (row < root.lines()) { |     if (row < root.lines()) { | ||||||
|         self.row = row; |         self.row = row; | ||||||
|         self.col = @min(col, root.line_width(self.row, mtrx) catch return error.Stop); |         self.col = @min(col, root.line_width(self.row, metrics) catch return error.Stop); | ||||||
|         self.target = self.col; |         self.target = self.col; | ||||||
|     } else return error.Stop; |     } else return error.Stop; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_abs(self: *Self, root: Buffer.Root, v: *View, y: usize, x: usize, mtrx: Metrix) !void { | pub fn move_abs(self: *Self, root: Buffer.Root, v: *View, y: usize, x: usize, metrics: Metrics) !void { | ||||||
|     self.row = v.row + y; |     self.row = v.row + y; | ||||||
|     self.col = v.col + x; |     self.col = v.col + x; | ||||||
|     self.clamp_to_buffer(root, mtrx); |     self.clamp_to_buffer(root, metrics); | ||||||
|     self.target = self.col; |     self.target = self.col; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -123,8 +123,8 @@ pub fn move_begin(self: *Self) void { | ||||||
|     self.target = self.col; |     self.target = self.col; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_end(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | pub fn move_end(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     if (self.row < root.lines()) self.col = root.line_width(self.row, mtrx) catch 0; |     if (self.row < root.lines()) self.col = root.line_width(self.row, metrics) catch 0; | ||||||
|     self.target = std.math.maxInt(u32); |     self.target = std.math.maxInt(u32); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -134,32 +134,32 @@ pub fn move_buffer_begin(self: *Self) void { | ||||||
|     self.target = 0; |     self.target = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn move_buffer_end(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | pub fn move_buffer_end(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     self.row = root.lines() - 1; |     self.row = root.lines() - 1; | ||||||
|     self.move_end(root, mtrx); |     self.move_end(root, metrics); | ||||||
|     if (self.col == 0) self.target = 0; |     if (self.col == 0) self.target = 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn move_buffer_first(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | fn move_buffer_first(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     self.row = 0; |     self.row = 0; | ||||||
|     self.follow_target(root, mtrx); |     self.follow_target(root, metrics); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn move_buffer_last(self: *Self, root: Buffer.Root, mtrx: Metrix) void { | fn move_buffer_last(self: *Self, root: Buffer.Root, metrics: Metrics) void { | ||||||
|     self.row = root.lines() - 1; |     self.row = root.lines() - 1; | ||||||
|     self.follow_target(root, mtrx); |     self.follow_target(root, metrics); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn is_at_begin(self: *const Self) bool { | fn is_at_begin(self: *const Self) bool { | ||||||
|     return self.col == 0; |     return self.col == 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn is_at_end(self: *const Self, root: Buffer.Root, mtrx: Metrix) bool { | fn is_at_end(self: *const Self, root: Buffer.Root, metrics: Metrics) bool { | ||||||
|     return if (self.row < root.lines()) self.col == root.line_width(self.row, mtrx) catch 0 else true; |     return if (self.row < root.lines()) self.col == root.line_width(self.row, metrics) catch 0 else true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, mtrx: Metrix) bool { | pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool { | ||||||
|     return root.test_at(pred, self.row, self.col, mtrx); |     return root.test_at(pred, self.row, self.col, metrics); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void { | pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void { | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ pub fn from_cursor(cursor: *const Cursor) Self { | ||||||
|     return .{ .begin = cursor.*, .end = cursor.* }; |     return .{ .begin = cursor.*, .end = cursor.* }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn line_from_cursor(cursor: Cursor, root: Buffer.Root, mtrx: Buffer.Metrix) Self { | pub fn line_from_cursor(cursor: Cursor, root: Buffer.Root, mtrx: Buffer.Metrics) Self { | ||||||
|     var begin = cursor; |     var begin = cursor; | ||||||
|     var end = cursor; |     var end = cursor; | ||||||
|     begin.move_begin(); |     begin.move_begin(); | ||||||
|  |  | ||||||
|  | @ -365,7 +365,7 @@ pub fn egc_chunk_width(self: *const Plane, chunk_: []const u8, abs_col_: usize) | ||||||
|     return colcount; |     return colcount; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn metrix(self: *const Plane) Buffer.Metrix { | pub fn metrics(self: *const Plane) Buffer.Metrics { | ||||||
|     return .{ |     return .{ | ||||||
|         .ctx = self, |         .ctx = self, | ||||||
|         .egc_length = struct { |         .egc_length = struct { | ||||||
|  |  | ||||||
|  | @ -109,8 +109,8 @@ pub const CurSel = struct { | ||||||
|         sel.normalize(); |         sel.normalize(); | ||||||
|         sel.begin.move_begin(); |         sel.begin.move_begin(); | ||||||
|         if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) { |         if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) { | ||||||
|             sel.end.move_end(root, plane.metrix()); |             sel.end.move_end(root, plane.metrics()); | ||||||
|             sel.end.move_right(root, plane.metrix()) catch {}; |             sel.end.move_right(root, plane.metrics()) catch {}; | ||||||
|         } |         } | ||||||
|         return sel; |         return sel; | ||||||
|     } |     } | ||||||
|  | @ -560,7 +560,7 @@ pub const Editor = struct { | ||||||
|     fn find_first_non_ws(root: Buffer.Root, row: usize, plane: Plane) usize { |     fn find_first_non_ws(root: Buffer.Root, row: usize, plane: Plane) usize { | ||||||
|         const Ctx = struct { |         const Ctx = struct { | ||||||
|             col: usize = 0, |             col: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Buffer.Metrix) Buffer.Walker { |             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Buffer.Metrics) Buffer.Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 if (egc[0] == ' ' or egc[0] == '\t') { |                 if (egc[0] == ' ' or egc[0] == '\t') { | ||||||
|                     ctx.col += wcwidth; |                     ctx.col += wcwidth; | ||||||
|  | @ -570,7 +570,7 @@ pub const Editor = struct { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         var ctx: Ctx = .{}; |         var ctx: Ctx = .{}; | ||||||
|         root.walk_egc_forward(row, Ctx.walker, &ctx, plane.metrix()) catch return 0; |         root.walk_egc_forward(row, Ctx.walker, &ctx, plane.metrics()) catch return 0; | ||||||
|         return ctx.col; |         return ctx.col; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -590,7 +590,7 @@ pub const Editor = struct { | ||||||
|             sel: Selection, |             sel: Selection, | ||||||
|             writer: Writer, |             writer: Writer, | ||||||
|             wcwidth: usize = 0, |             wcwidth: usize = 0, | ||||||
|             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Buffer.Metrix) Buffer.Walker { |             fn walker(ctx_: *anyopaque, egc: []const u8, wcwidth: usize, _: Buffer.Metrics) Buffer.Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 if (ctx.col < ctx.sel.begin.col) { |                 if (ctx.col < ctx.sel.begin.col) { | ||||||
|                     ctx.col += wcwidth; |                     ctx.col += wcwidth; | ||||||
|  | @ -617,7 +617,7 @@ pub const Editor = struct { | ||||||
|         ctx.sel.normalize(); |         ctx.sel.normalize(); | ||||||
|         if (sel.begin.eql(sel.end)) |         if (sel.begin.eql(sel.end)) | ||||||
|             return; |             return; | ||||||
|         root.walk_egc_forward(sel.begin.row, Ctx.walker, &ctx, plane_.metrix()) catch |e| return map_error(e, @errorReturnTrace()); |         root.walk_egc_forward(sel.begin.row, Ctx.walker, &ctx, plane_.metrics()) catch |e| return map_error(e, @errorReturnTrace()); | ||||||
|         if (wcwidth_) |p| p.* = ctx.wcwidth; |         if (wcwidth_) |p| p.* = ctx.wcwidth; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -657,7 +657,7 @@ pub const Editor = struct { | ||||||
|             theme: *const Widget.Theme, |             theme: *const Widget.Theme, | ||||||
|             hl_row: ?usize, |             hl_row: ?usize, | ||||||
| 
 | 
 | ||||||
|             fn walker(ctx_: *anyopaque, leaf: *const Buffer.Leaf, _: Buffer.Metrix) Buffer.Walker { |             fn walker(ctx_: *anyopaque, leaf: *const Buffer.Leaf, _: Buffer.Metrics) Buffer.Walker { | ||||||
|                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); |                 const ctx = @as(*@This(), @ptrCast(@alignCast(ctx_))); | ||||||
|                 const self_ = ctx.self; |                 const self_ = ctx.self; | ||||||
|                 const view = self_.view; |                 const view = self_.view; | ||||||
|  | @ -750,7 +750,7 @@ pub const Editor = struct { | ||||||
|             if (hl_row) |_| |             if (hl_row) |_| | ||||||
|                 self.render_line_highlight(&self.get_primary().cursor, theme) catch {}; |                 self.render_line_highlight(&self.get_primary().cursor, theme) catch {}; | ||||||
|             self.plane.home(); |             self.plane.home(); | ||||||
|             _ = root.walk_from_line_begin_const(self.view.row, ctx.walker, &ctx_, self.plane.metrix()) catch {}; |             _ = root.walk_from_line_begin_const(self.view.row, ctx.walker, &ctx_, self.plane.metrics()) catch {}; | ||||||
|         } |         } | ||||||
|         self.render_syntax(theme, cache, root) catch {}; |         self.render_syntax(theme, cache, root) catch {}; | ||||||
|         self.render_diagnostics(theme, hl_row) catch {}; |         self.render_diagnostics(theme, hl_row) catch {}; | ||||||
|  | @ -1440,7 +1440,7 @@ pub const Editor = struct { | ||||||
|         if (self.syntax) |syn| { |         if (self.syntax) |syn| { | ||||||
|             const root = self.buf_root() catch return; |             const root = self.buf_root() catch return; | ||||||
|             var start_byte: usize = 0; |             var start_byte: usize = 0; | ||||||
|             _ = root.get_range(.{ .begin = .{}, .end = nudge.begin }, null, &start_byte, null, self.plane.metrix()) catch return; |             _ = root.get_range(.{ .begin = .{}, .end = nudge.begin }, null, &start_byte, null, self.plane.metrics()) catch return; | ||||||
|             syn.edit(.{ |             syn.edit(.{ | ||||||
|                 .start_byte = @intCast(start_byte), |                 .start_byte = @intCast(start_byte), | ||||||
|                 .old_end_byte = @intCast(start_byte), |                 .old_end_byte = @intCast(start_byte), | ||||||
|  | @ -1472,7 +1472,7 @@ pub const Editor = struct { | ||||||
|         cursel.cursor = sel.begin; |         cursel.cursor = sel.begin; | ||||||
|         cursel.selection = null; |         cursel.selection = null; | ||||||
|         var size: usize = 0; |         var size: usize = 0; | ||||||
|         const root_ = try root.delete_range(sel, a, &size, self.plane.metrix()); |         const root_ = try root.delete_range(sel, a, &size, self.plane.metrics()); | ||||||
|         self.nudge_delete(sel, cursel, size); |         self.nudge_delete(sel, cursel, size); | ||||||
|         return root_; |         return root_; | ||||||
|     } |     } | ||||||
|  | @ -1539,11 +1539,11 @@ pub const Editor = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         return cursor.test_at(root, is_word_char, plane.metrix()); |         return cursor.test_at(root, is_word_char, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_non_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_non_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         return cursor.test_at(root, is_not_word_char, plane.metrix()); |         return cursor.test_at(root, is_not_word_char, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_word_boundary_left(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_word_boundary_left(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|  | @ -1552,7 +1552,7 @@ pub const Editor = struct { | ||||||
|         if (is_non_word_char_at_cursor(root, cursor, plane)) |         if (is_non_word_char_at_cursor(root, cursor, plane)) | ||||||
|             return false; |             return false; | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_left(root, plane.metrix()) catch return true; |         next.move_left(root, plane.metrics()) catch return true; | ||||||
|         if (is_non_word_char_at_cursor(root, &next, plane)) |         if (is_non_word_char_at_cursor(root, &next, plane)) | ||||||
|             return true; |             return true; | ||||||
|         return false; |         return false; | ||||||
|  | @ -1564,33 +1564,33 @@ pub const Editor = struct { | ||||||
|         if (is_word_char_at_cursor(root, cursor, plane)) |         if (is_word_char_at_cursor(root, cursor, plane)) | ||||||
|             return false; |             return false; | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_left(root, plane.metrix()) catch return true; |         next.move_left(root, plane.metrics()) catch return true; | ||||||
|         if (is_word_char_at_cursor(root, &next, plane)) |         if (is_word_char_at_cursor(root, &next, plane)) | ||||||
|             return true; |             return true; | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         const line_width = root.line_width(cursor.row, plane.metrix()) catch return true; |         const line_width = root.line_width(cursor.row, plane.metrics()) catch return true; | ||||||
|         if (cursor.col >= line_width) |         if (cursor.col >= line_width) | ||||||
|             return true; |             return true; | ||||||
|         if (is_non_word_char_at_cursor(root, cursor, plane)) |         if (is_non_word_char_at_cursor(root, cursor, plane)) | ||||||
|             return false; |             return false; | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_right(root, plane.metrix()) catch return true; |         next.move_right(root, plane.metrics()) catch return true; | ||||||
|         if (is_non_word_char_at_cursor(root, &next, plane)) |         if (is_non_word_char_at_cursor(root, &next, plane)) | ||||||
|             return true; |             return true; | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_non_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_non_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         const line_width = root.line_width(cursor.row, plane.metrix()) catch return true; |         const line_width = root.line_width(cursor.row, plane.metrics()) catch return true; | ||||||
|         if (cursor.col >= line_width) |         if (cursor.col >= line_width) | ||||||
|             return true; |             return true; | ||||||
|         if (is_word_char_at_cursor(root, cursor, plane)) |         if (is_word_char_at_cursor(root, cursor, plane)) | ||||||
|             return false; |             return false; | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_right(root, plane.metrix()) catch return true; |         next.move_right(root, plane.metrics()) catch return true; | ||||||
|         if (is_word_char_at_cursor(root, &next, plane)) |         if (is_word_char_at_cursor(root, &next, plane)) | ||||||
|             return true; |             return true; | ||||||
|         return false; |         return false; | ||||||
|  | @ -1603,14 +1603,14 @@ pub const Editor = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_eol_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_eol_right(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         const line_width = root.line_width(cursor.row, plane.metrix()) catch return true; |         const line_width = root.line_width(cursor.row, plane.metrics()) catch return true; | ||||||
|         if (cursor.col >= line_width) |         if (cursor.col >= line_width) | ||||||
|             return true; |             return true; | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { |     fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, plane: Plane) bool { | ||||||
|         const line_width = root.line_width(cursor.row, plane.metrix()) catch return true; |         const line_width = root.line_width(cursor.row, plane.metrics()) catch return true; | ||||||
|         if (line_width == 0) return true; |         if (line_width == 0) return true; | ||||||
|         if (cursor.col >= line_width - 1) |         if (cursor.col >= line_width - 1) | ||||||
|             return true; |             return true; | ||||||
|  | @ -1618,7 +1618,7 @@ pub const Editor = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { |     fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { | ||||||
|         try cursor.move_left(root, plane.metrix()); |         try cursor.move_left(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_left_until(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, plane: Plane) void { |     fn move_cursor_left_until(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, plane: Plane) void { | ||||||
|  | @ -1637,11 +1637,11 @@ pub const Editor = struct { | ||||||
| 
 | 
 | ||||||
|     fn smart_move_cursor_begin(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { |     fn smart_move_cursor_begin(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { | ||||||
|         const first = find_first_non_ws(root, cursor.row, plane); |         const first = find_first_non_ws(root, cursor.row, plane); | ||||||
|         return if (cursor.col == first) cursor.move_begin() else cursor.move_to(root, cursor.row, first, plane.metrix()); |         return if (cursor.col == first) cursor.move_begin() else cursor.move_to(root, cursor.row, first, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_right(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { |     fn move_cursor_right(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { | ||||||
|         try cursor.move_right(root, plane.metrix()); |         try cursor.move_right(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_right_until(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, plane: Plane) void { |     fn move_cursor_right_until(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, plane: Plane) void { | ||||||
|  | @ -1655,15 +1655,15 @@ pub const Editor = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_end(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { |     fn move_cursor_end(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { | ||||||
|         cursor.move_end(root, plane.metrix()); |         cursor.move_end(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { |     fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { | ||||||
|         try cursor.move_up(root, plane.metrix()); |         try cursor.move_up(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { |     fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { | ||||||
|         try cursor.move_down(root, plane.metrix()); |         try cursor.move_down(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Plane) !void { |     fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Plane) !void { | ||||||
|  | @ -1671,15 +1671,15 @@ pub const Editor = struct { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_buffer_end(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { |     fn move_cursor_buffer_end(root: Buffer.Root, cursor: *Cursor, plane: Plane) !void { | ||||||
|         cursor.move_buffer_end(root, plane.metrix()); |         cursor.move_buffer_end(root, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, plane: Plane) !void { |     fn move_cursor_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, plane: Plane) !void { | ||||||
|         cursor.move_page_up(root, view, plane.metrix()); |         cursor.move_page_up(root, view, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn move_cursor_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, plane: Plane) !void { |     fn move_cursor_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, plane: Plane) !void { | ||||||
|         cursor.move_page_down(root, view, plane.metrix()); |         cursor.move_page_down(root, view, plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn primary_click(self: *Self, y: c_int, x: c_int) !void { |     pub fn primary_click(self: *Self, y: c_int, x: c_int) !void { | ||||||
|  | @ -1692,7 +1692,7 @@ pub const Editor = struct { | ||||||
|         self.selection_mode = .char; |         self.selection_mode = .char; | ||||||
|         try self.send_editor_jump_source(); |         try self.send_editor_jump_source(); | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrix()) catch return; |         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrics()) catch return; | ||||||
|         self.clamp_mouse(); |         self.clamp_mouse(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|         if (self.jump_mode) try self.goto_definition(.{}); |         if (self.jump_mode) try self.goto_definition(.{}); | ||||||
|  | @ -1703,7 +1703,7 @@ pub const Editor = struct { | ||||||
|         primary.selection = null; |         primary.selection = null; | ||||||
|         self.selection_mode = .word; |         self.selection_mode = .word; | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrix()) catch return; |         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrics()) catch return; | ||||||
|         _ = try self.select_word_at_cursor(primary); |         _ = try self.select_word_at_cursor(primary); | ||||||
|         self.clamp_mouse(); |         self.clamp_mouse(); | ||||||
|     } |     } | ||||||
|  | @ -1713,7 +1713,7 @@ pub const Editor = struct { | ||||||
|         primary.selection = null; |         primary.selection = null; | ||||||
|         self.selection_mode = .line; |         self.selection_mode = .line; | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrix()) catch return; |         primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.plane.metrics()) catch return; | ||||||
|         try self.select_line_at_cursor(primary); |         try self.select_line_at_cursor(primary); | ||||||
|         self.clamp_mouse(); |         self.clamp_mouse(); | ||||||
|     } |     } | ||||||
|  | @ -1724,7 +1724,7 @@ pub const Editor = struct { | ||||||
|         const primary = self.get_primary(); |         const primary = self.get_primary(); | ||||||
|         const sel = primary.enable_selection(); |         const sel = primary.enable_selection(); | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.plane.metrix()) catch return; |         sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.plane.metrics()) catch return; | ||||||
|         switch (self.selection_mode) { |         switch (self.selection_mode) { | ||||||
|             .char => {}, |             .char => {}, | ||||||
|             .word => if (sel.begin.right_of(sel.end)) |             .word => if (sel.begin.right_of(sel.end)) | ||||||
|  | @ -1882,9 +1882,9 @@ pub const Editor = struct { | ||||||
| 
 | 
 | ||||||
|     fn copy_selection(root: Buffer.Root, sel: Selection, text_a: Allocator, plane: Plane) ![]const u8 { |     fn copy_selection(root: Buffer.Root, sel: Selection, text_a: Allocator, plane: Plane) ![]const u8 { | ||||||
|         var size: usize = 0; |         var size: usize = 0; | ||||||
|         _ = try root.get_range(sel, null, &size, null, plane.metrix()); |         _ = try root.get_range(sel, null, &size, null, plane.metrics()); | ||||||
|         const buf__ = try text_a.alloc(u8, size); |         const buf__ = try text_a.alloc(u8, size); | ||||||
|         return (try root.get_range(sel, buf__, null, null, plane.metrix())).?; |         return (try root.get_range(sel, buf__, null, null, plane.metrics())).?; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_selection(self: *const Self, sel: Selection, text_a: Allocator) ![]const u8 { |     pub fn get_selection(self: *const Self, sel: Selection, text_a: Allocator) ![]const u8 { | ||||||
|  | @ -1921,7 +1921,7 @@ pub const Editor = struct { | ||||||
|         var root_ = if (cursel.selection) |_| try self.delete_selection(root, cursel, a) else root; |         var root_ = if (cursel.selection) |_| try self.delete_selection(root, cursel, a) else root; | ||||||
|         const cursor = &cursel.cursor; |         const cursor = &cursel.cursor; | ||||||
|         const begin = cursel.cursor; |         const begin = cursel.cursor; | ||||||
|         cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, a, self.plane.metrix()); |         cursor.row, cursor.col, root_ = try root_.insert_chars(cursor.row, cursor.col, s, a, self.plane.metrics()); | ||||||
|         cursor.target = cursor.col; |         cursor.target = cursor.col; | ||||||
|         self.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len); |         self.nudge_insert(.{ .begin = begin, .end = cursor.* }, cursel, s.len); | ||||||
|         return root_; |         return root_; | ||||||
|  | @ -2126,7 +2126,7 @@ pub const Editor = struct { | ||||||
|     fn move_cursor_word_left_space(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { |     fn move_cursor_word_left_space(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { | ||||||
|         try move_cursor_left(root, cursor, plane); |         try move_cursor_left(root, cursor, plane); | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_left(root, plane.metrix()) catch |         next.move_left(root, plane.metrics()) catch | ||||||
|             return move_cursor_left_until(root, cursor, is_word_boundary_left, plane); |             return move_cursor_left_until(root, cursor, is_word_boundary_left, plane); | ||||||
|         if (is_non_word_char_at_cursor(root, cursor, plane) and is_non_word_char_at_cursor(root, &next, plane)) |         if (is_non_word_char_at_cursor(root, cursor, plane) and is_non_word_char_at_cursor(root, &next, plane)) | ||||||
|             move_cursor_left_until(root, cursor, is_non_word_boundary_left, plane) |             move_cursor_left_until(root, cursor, is_non_word_boundary_left, plane) | ||||||
|  | @ -2146,7 +2146,7 @@ pub const Editor = struct { | ||||||
| 
 | 
 | ||||||
|     pub fn move_cursor_word_right_space(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { |     pub fn move_cursor_word_right_space(root: Buffer.Root, cursor: *Cursor, plane: Plane) error{Stop}!void { | ||||||
|         var next = cursor.*; |         var next = cursor.*; | ||||||
|         next.move_right(root, plane.metrix()) catch { |         next.move_right(root, plane.metrics()) catch { | ||||||
|             move_cursor_right_until(root, cursor, is_word_boundary_right, plane); |             move_cursor_right_until(root, cursor, is_word_boundary_right, plane); | ||||||
|             try move_cursor_right(root, cursor, plane); |             try move_cursor_right(root, cursor, plane); | ||||||
|             return; |             return; | ||||||
|  | @ -2182,7 +2182,7 @@ pub const Editor = struct { | ||||||
|             return error.Stop; |             return error.Stop; | ||||||
|         try move_cursor_left(root, cursor, plane); |         try move_cursor_left(root, cursor, plane); | ||||||
|         while (true) { |         while (true) { | ||||||
|             const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, plane.metrix()) catch return error.Stop; |             const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, plane.metrics()) catch return error.Stop; | ||||||
|             if (std.mem.eql(u8, curr_egc, egc)) |             if (std.mem.eql(u8, curr_egc, egc)) | ||||||
|                 return; |                 return; | ||||||
|             if (is_eol_left(root, cursor, plane)) |             if (is_eol_left(root, cursor, plane)) | ||||||
|  | @ -2197,7 +2197,7 @@ pub const Editor = struct { | ||||||
|             return error.Stop; |             return error.Stop; | ||||||
|         try move_cursor_right(root, cursor, plane); |         try move_cursor_right(root, cursor, plane); | ||||||
|         while (true) { |         while (true) { | ||||||
|             const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, plane.metrix()) catch return error.Stop; |             const curr_egc, _, _ = root.ecg_at(cursor.row, cursor.col, plane.metrics()) catch return error.Stop; | ||||||
|             if (std.mem.eql(u8, curr_egc, egc)) |             if (std.mem.eql(u8, curr_egc, egc)) | ||||||
|                 return; |                 return; | ||||||
|             if (is_eol_right(root, cursor, plane)) |             if (is_eol_right(root, cursor, plane)) | ||||||
|  | @ -2258,7 +2258,7 @@ pub const Editor = struct { | ||||||
|             const root = self.buf_root() catch return; |             const root = self.buf_root() catch return; | ||||||
|             primary.selection = match.to_selection(); |             primary.selection = match.to_selection(); | ||||||
|             match.has_selection = true; |             match.has_selection = true; | ||||||
|             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrix()) catch return; |             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrics()) catch return; | ||||||
|         } |         } | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|  | @ -2273,7 +2273,7 @@ pub const Editor = struct { | ||||||
|             const root = self.buf_root() catch return; |             const root = self.buf_root() catch return; | ||||||
|             primary.selection = match.to_selection(); |             primary.selection = match.to_selection(); | ||||||
|             match.has_selection = true; |             match.has_selection = true; | ||||||
|             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrix()) catch return; |             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrics()) catch return; | ||||||
|         } |         } | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|  | @ -2292,7 +2292,7 @@ pub const Editor = struct { | ||||||
|                     .col = 0, |                     .col = 0, | ||||||
|                 }, |                 }, | ||||||
|             }; |             }; | ||||||
|             new_cursel.*.?.cursor.move_end(root, self.plane.metrix()); |             new_cursel.*.?.cursor.move_end(root, self.plane.metrics()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -2314,13 +2314,13 @@ pub const Editor = struct { | ||||||
|         const cut_text = copy_selection(root, sel.*, sfa.get(), self.plane) catch return error.Stop; |         const cut_text = copy_selection(root, sel.*, sfa.get(), self.plane) catch return error.Stop; | ||||||
|         defer a.free(cut_text); |         defer a.free(cut_text); | ||||||
|         root = try self.delete_selection(root, cursel, a); |         root = try self.delete_selection(root, cursel, a); | ||||||
|         try cursel.cursor.move_up(root, self.plane.metrix()); |         try cursel.cursor.move_up(root, self.plane.metrics()); | ||||||
|         root = self.insert(root, cursel, cut_text, a) catch return error.Stop; |         root = self.insert(root, cursel, cut_text, a) catch return error.Stop; | ||||||
|         cursel.* = saved; |         cursel.* = saved; | ||||||
|         try cursel.cursor.move_up(root, self.plane.metrix()); |         try cursel.cursor.move_up(root, self.plane.metrics()); | ||||||
|         if (cursel.selection) |*sel_| { |         if (cursel.selection) |*sel_| { | ||||||
|             try sel_.begin.move_up(root, self.plane.metrix()); |             try sel_.begin.move_up(root, self.plane.metrics()); | ||||||
|             try sel_.end.move_up(root, self.plane.metrix()); |             try sel_.end.move_up(root, self.plane.metrics()); | ||||||
|         } |         } | ||||||
|         return root; |         return root; | ||||||
|     } |     } | ||||||
|  | @ -2340,13 +2340,13 @@ pub const Editor = struct { | ||||||
|         const cut_text = copy_selection(root, sel.*, sfa.get(), self.plane) catch return error.Stop; |         const cut_text = copy_selection(root, sel.*, sfa.get(), self.plane) catch return error.Stop; | ||||||
|         defer a.free(cut_text); |         defer a.free(cut_text); | ||||||
|         root = try self.delete_selection(root, cursel, a); |         root = try self.delete_selection(root, cursel, a); | ||||||
|         try cursel.cursor.move_down(root, self.plane.metrix()); |         try cursel.cursor.move_down(root, self.plane.metrics()); | ||||||
|         root = self.insert(root, cursel, cut_text, a) catch return error.Stop; |         root = self.insert(root, cursel, cut_text, a) catch return error.Stop; | ||||||
|         cursel.* = saved; |         cursel.* = saved; | ||||||
|         try cursel.cursor.move_down(root, self.plane.metrix()); |         try cursel.cursor.move_down(root, self.plane.metrics()); | ||||||
|         if (cursel.selection) |*sel_| { |         if (cursel.selection) |*sel_| { | ||||||
|             try sel_.begin.move_down(root, self.plane.metrix()); |             try sel_.begin.move_down(root, self.plane.metrics()); | ||||||
|             try sel_.end.move_down(root, self.plane.metrix()); |             try sel_.end.move_down(root, self.plane.metrics()); | ||||||
|         } |         } | ||||||
|         return root; |         return root; | ||||||
|     } |     } | ||||||
|  | @ -2360,7 +2360,7 @@ pub const Editor = struct { | ||||||
| 
 | 
 | ||||||
|     fn dupe_cursel_up(self: *Self, root_: Buffer.Root, cursel: *CurSel, a: Allocator) error{Stop}!Buffer.Root { |     fn dupe_cursel_up(self: *Self, root_: Buffer.Root, cursel: *CurSel, a: Allocator) error{Stop}!Buffer.Root { | ||||||
|         var root = root_; |         var root = root_; | ||||||
|         const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.plane.metrix()); |         const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.plane.metrics()); | ||||||
|         cursel.selection = null; |         cursel.selection = null; | ||||||
|         var sfa = std.heap.stackFallback(4096, self.a); |         var sfa = std.heap.stackFallback(4096, self.a); | ||||||
|         const text = copy_selection(root, sel, sfa.get(), self.plane) catch return error.Stop; |         const text = copy_selection(root, sel, sfa.get(), self.plane) catch return error.Stop; | ||||||
|  | @ -2381,7 +2381,7 @@ pub const Editor = struct { | ||||||
| 
 | 
 | ||||||
|     fn dupe_cursel_down(self: *Self, root_: Buffer.Root, cursel: *CurSel, a: Allocator) error{Stop}!Buffer.Root { |     fn dupe_cursel_down(self: *Self, root_: Buffer.Root, cursel: *CurSel, a: Allocator) error{Stop}!Buffer.Root { | ||||||
|         var root = root_; |         var root = root_; | ||||||
|         const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.plane.metrix()); |         const sel: Selection = if (cursel.selection) |sel_| sel_ else Selection.line_from_cursor(cursel.cursor, root, self.plane.metrics()); | ||||||
|         cursel.selection = null; |         cursel.selection = null; | ||||||
|         var sfa = std.heap.stackFallback(4096, self.a); |         var sfa = std.heap.stackFallback(4096, self.a); | ||||||
|         const text = copy_selection(root, sel, sfa.get(), self.plane) catch return error.Stop; |         const text = copy_selection(root, sel, sfa.get(), self.plane) catch return error.Stop; | ||||||
|  | @ -2464,7 +2464,7 @@ pub const Editor = struct { | ||||||
|         var newroot = root; |         var newroot = root; | ||||||
|         defer { |         defer { | ||||||
|             cursel.* = saved; |             cursel.* = saved; | ||||||
|             cursel.cursor.clamp_to_buffer(newroot, self.plane.metrix()); |             cursel.cursor.clamp_to_buffer(newroot, self.plane.metrics()); | ||||||
|         } |         } | ||||||
|         cursel.selection = null; |         cursel.selection = null; | ||||||
|         cursel.cursor = cursor; |         cursel.cursor = cursor; | ||||||
|  | @ -2474,8 +2474,8 @@ pub const Editor = struct { | ||||||
|         const cols = if (off == 0) 4 else off; |         const cols = if (off == 0) 4 else off; | ||||||
|         const sel = cursel.enable_selection(); |         const sel = cursel.enable_selection(); | ||||||
|         sel.begin.move_begin(); |         sel.begin.move_begin(); | ||||||
|         try sel.end.move_to(root, sel.end.row, cols, self.plane.metrix()); |         try sel.end.move_to(root, sel.end.row, cols, self.plane.metrics()); | ||||||
|         if (cursel.cursor.col < cols) try cursel.cursor.move_to(root, cursel.cursor.row, cols, self.plane.metrix()); |         if (cursel.cursor.col < cols) try cursel.cursor.move_to(root, cursel.cursor.row, cols, self.plane.metrics()); | ||||||
|         newroot = try self.delete_selection(root, cursel, a); |         newroot = try self.delete_selection(root, cursel, a); | ||||||
|         return newroot; |         return newroot; | ||||||
|     } |     } | ||||||
|  | @ -2589,7 +2589,7 @@ pub const Editor = struct { | ||||||
|         try self.send_editor_jump_source(); |         try self.send_editor_jump_source(); | ||||||
|         self.cancel_all_selections(); |         self.cancel_all_selections(); | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         self.get_primary().cursor.move_buffer_end(root, self.plane.metrix()); |         self.get_primary().cursor.move_buffer_end(root, self.plane.metrics()); | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|     } |     } | ||||||
|  | @ -2928,7 +2928,7 @@ pub const Editor = struct { | ||||||
|         const primary = self.get_primary(); |         const primary = self.get_primary(); | ||||||
|         var tree = std.ArrayList(u8).init(self.a); |         var tree = std.ArrayList(u8).init(self.a); | ||||||
|         defer tree.deinit(); |         defer tree.deinit(); | ||||||
|         root.debug_render_chunks(primary.cursor.row, &tree, self.plane.metrix()) catch |e| |         root.debug_render_chunks(primary.cursor.row, &tree, self.plane.metrics()) catch |e| | ||||||
|             return self.logger.print("line {d}: {any}", .{ primary.cursor.row, e }); |             return self.logger.print("line {d}: {any}", .{ primary.cursor.row, e }); | ||||||
|         self.logger.print("line {d}:{s}", .{ primary.cursor.row, std.fmt.fmtSliceEscapeLower(tree.items) }); |         self.logger.print("line {d}:{s}", .{ primary.cursor.row, std.fmt.fmtSliceEscapeLower(tree.items) }); | ||||||
|     } |     } | ||||||
|  | @ -3184,8 +3184,8 @@ pub const Editor = struct { | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         const begin_line = begin_line_ - 1; |         const begin_line = begin_line_ - 1; | ||||||
|         const end_line = end_line_ - 1; |         const end_line = end_line_ - 1; | ||||||
|         const begin_pos = root.pos_to_width(begin_line, begin_pos_, self.plane.metrix()) catch return; |         const begin_pos = root.pos_to_width(begin_line, begin_pos_, self.plane.metrics()) catch return; | ||||||
|         const end_pos = root.pos_to_width(end_line, end_pos_, self.plane.metrix()) catch return; |         const end_pos = root.pos_to_width(end_line, end_pos_, self.plane.metrics()) catch return; | ||||||
|         var match: Match = .{ .begin = .{ .row = begin_line, .col = begin_pos }, .end = .{ .row = end_line, .col = end_pos } }; |         var match: Match = .{ .begin = .{ .row = begin_line, .col = begin_pos }, .end = .{ .row = end_line, .col = end_pos } }; | ||||||
|         if (match.end.eql(self.get_primary().cursor)) |         if (match.end.eql(self.get_primary().cursor)) | ||||||
|             match.has_selection = true; |             match.has_selection = true; | ||||||
|  | @ -3241,7 +3241,7 @@ pub const Editor = struct { | ||||||
|         if (self.scan_prev_match(cursor)) |match| return match; |         if (self.scan_prev_match(cursor)) |match| return match; | ||||||
|         const root = self.buf_root() catch return null; |         const root = self.buf_root() catch return null; | ||||||
|         var cursor_ = cursor; |         var cursor_ = cursor; | ||||||
|         cursor_.move_buffer_end(root, self.plane.metrix()); |         cursor_.move_buffer_end(root, self.plane.metrics()); | ||||||
|         return self.scan_prev_match(cursor_); |         return self.scan_prev_match(cursor_); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -3253,7 +3253,7 @@ pub const Editor = struct { | ||||||
|                 match_.has_selection = false; |                 match_.has_selection = false; | ||||||
|             }; |             }; | ||||||
|             primary.selection = match.to_selection(); |             primary.selection = match.to_selection(); | ||||||
|             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrix()) catch return; |             primary.cursor.move_to(root, match.end.row, match.end.col, self.plane.metrics()) catch return; | ||||||
|             self.clamp(); |             self.clamp(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -3280,7 +3280,7 @@ pub const Editor = struct { | ||||||
|             }; |             }; | ||||||
|             primary.selection = match.to_selection(); |             primary.selection = match.to_selection(); | ||||||
|             primary.selection.?.reverse(); |             primary.selection.?.reverse(); | ||||||
|             primary.cursor.move_to(root, match.begin.row, match.begin.col, self.plane.metrix()) catch return; |             primary.cursor.move_to(root, match.begin.row, match.begin.col, self.plane.metrics()) catch return; | ||||||
|             self.clamp(); |             self.clamp(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -3327,7 +3327,7 @@ pub const Editor = struct { | ||||||
|         const primary = self.get_primary(); |         const primary = self.get_primary(); | ||||||
|         try self.send_editor_jump_source(); |         try self.send_editor_jump_source(); | ||||||
|         self.cancel_all_selections(); |         self.cancel_all_selections(); | ||||||
|         try primary.cursor.move_to(root, diag.sel.begin.row, diag.sel.begin.col, self.plane.metrix()); |         try primary.cursor.move_to(root, diag.sel.begin.row, diag.sel.begin.col, self.plane.metrics()); | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|     } |     } | ||||||
|  | @ -3352,7 +3352,7 @@ pub const Editor = struct { | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         self.cancel_all_selections(); |         self.cancel_all_selections(); | ||||||
|         const primary = self.get_primary(); |         const primary = self.get_primary(); | ||||||
|         try primary.cursor.move_to(root, @intCast(if (line < 1) 0 else line - 1), primary.cursor.col, self.plane.metrix()); |         try primary.cursor.move_to(root, @intCast(if (line < 1) 0 else line - 1), primary.cursor.col, self.plane.metrics()); | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|         try self.send_editor_jump_destination(); |         try self.send_editor_jump_destination(); | ||||||
|     } |     } | ||||||
|  | @ -3363,7 +3363,7 @@ pub const Editor = struct { | ||||||
|             return error.InvalidArgument; |             return error.InvalidArgument; | ||||||
|         const root = self.buf_root() catch return; |         const root = self.buf_root() catch return; | ||||||
|         const primary = self.get_primary(); |         const primary = self.get_primary(); | ||||||
|         try primary.cursor.move_to(root, primary.cursor.row, @intCast(if (column < 1) 0 else column - 1), self.plane.metrix()); |         try primary.cursor.move_to(root, primary.cursor.row, @intCast(if (column < 1) 0 else column - 1), self.plane.metrics()); | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -3396,7 +3396,7 @@ pub const Editor = struct { | ||||||
|             root, |             root, | ||||||
|             @intCast(if (line < 1) 0 else line - 1), |             @intCast(if (line < 1) 0 else line - 1), | ||||||
|             @intCast(if (column < 1) 0 else column - 1), |             @intCast(if (column < 1) 0 else column - 1), | ||||||
|             self.plane.metrix(), |             self.plane.metrics(), | ||||||
|         ); |         ); | ||||||
|         if (have_sel) primary.selection = sel; |         if (have_sel) primary.selection = sel; | ||||||
|         if (self.view.is_visible(&primary.cursor)) |         if (self.view.is_visible(&primary.cursor)) | ||||||
|  | @ -3538,7 +3538,7 @@ pub const Editor = struct { | ||||||
|         try self.write_range(state.before_root, sel, buffer.writer(), tp.exit_error, null, self.plane); |         try self.write_range(state.before_root, sel, buffer.writer(), tp.exit_error, null, self.plane); | ||||||
|         try buffer.flush(); |         try buffer.flush(); | ||||||
|         self.logger.print("filter: sent", .{}); |         self.logger.print("filter: sent", .{}); | ||||||
|         state.work_root = try state.work_root.delete_range(sel, buf_a_, null, self.plane.metrix()); |         state.work_root = try state.work_root.delete_range(sel, buf_a_, null, self.plane.metrics()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn filter_stdout(self: *Self, bytes: []const u8) !void { |     fn filter_stdout(self: *Self, bytes: []const u8) !void { | ||||||
|  | @ -3549,7 +3549,7 @@ pub const Editor = struct { | ||||||
|             try buf.appendSlice(bytes); |             try buf.appendSlice(bytes); | ||||||
|         } else { |         } else { | ||||||
|             const cursor = &state.pos.cursor; |             const cursor = &state.pos.cursor; | ||||||
|             cursor.row, cursor.col, state.work_root = try state.work_root.insert_chars(cursor.row, cursor.col, bytes, buf_a_, self.plane.metrix()); |             cursor.row, cursor.col, state.work_root = try state.work_root.insert_chars(cursor.row, cursor.col, bytes, buf_a_, self.plane.metrics()); | ||||||
|             state.bytes += bytes.len; |             state.bytes += bytes.len; | ||||||
|             state.chunks += 1; |             state.chunks += 1; | ||||||
|         } |         } | ||||||
|  | @ -3582,7 +3582,7 @@ pub const Editor = struct { | ||||||
|             primary.cursor = sel.end; |             primary.cursor = sel.end; | ||||||
|         } |         } | ||||||
|         try self.update_buf(state.work_root); |         try self.update_buf(state.work_root); | ||||||
|         primary.cursor.clamp_to_buffer(state.work_root, self.plane.metrix()); |         primary.cursor.clamp_to_buffer(state.work_root, self.plane.metrics()); | ||||||
|         self.logger.print("filter: done (bytes:{d} chunks:{d})", .{ state.bytes, state.chunks }); |         self.logger.print("filter: done (bytes:{d} chunks:{d})", .{ state.bytes, state.chunks }); | ||||||
|         self.reset_syntax(); |         self.reset_syntax(); | ||||||
|         self.clamp(); |         self.clamp(); | ||||||
|  | @ -3879,10 +3879,10 @@ pub const PosToWidthCache = struct { | ||||||
|             self.cache.clearRetainingCapacity(); |             self.cache.clearRetainingCapacity(); | ||||||
|             self.cached_line = start.row; |             self.cached_line = start.row; | ||||||
|             self.cached_root = root; |             self.cached_root = root; | ||||||
|             root.get_line_width_map(self.cached_line, &self.cache, plane.metrix()) catch return null; |             root.get_line_width_map(self.cached_line, &self.cache, plane.metrics()) catch return null; | ||||||
|         } |         } | ||||||
|         const start_col = if (start.column < self.cache.items.len) self.cache.items[start.column] else start.column; |         const start_col = if (start.column < self.cache.items.len) self.cache.items[start.column] else start.column; | ||||||
|         const end_col = if (end.row == start.row and end.column < self.cache.items.len) self.cache.items[end.column] else root.pos_to_width(end.row, end.column, plane.metrix()) catch end.column; |         const end_col = if (end.row == start.row and end.column < self.cache.items.len) self.cache.items[end.column] else root.pos_to_width(end.row, end.column, plane.metrics()) catch end.column; | ||||||
|         return .{ .begin = .{ .row = start.row, .col = start_col }, .end = .{ .row = end.row, .col = end_col } }; |         return .{ .begin = .{ .row = start.row, .col = start_col }, .end = .{ .row = end.row, .col = end_col } }; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ fn inspect_location(self: *Self, row: usize, col: usize) void { | ||||||
| 
 | 
 | ||||||
| fn get_buffer_text(self: *Self, buf: []u8, sel: Buffer.Selection) ?[]const u8 { | fn get_buffer_text(self: *Self, buf: []u8, sel: Buffer.Selection) ?[]const u8 { | ||||||
|     const root = self.editor.get_current_root() orelse return null; |     const root = self.editor.get_current_root() orelse return null; | ||||||
|     return root.get_range(sel, buf, null, null, self.plane.metrix()) catch return null; |     return root.get_range(sel, buf, null, null, self.plane.metrics()) catch return null; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn dump_highlight(self: *Self, range: syntax.Range, scope: []const u8, id: u32, _: usize, ast_node: *const syntax.Node) error{Stop}!void { | fn dump_highlight(self: *Self, range: syntax.Range, scope: []const u8, id: u32, _: usize, ast_node: *const syntax.Node) error{Stop}!void { | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ const Buffer = @import("Buffer"); | ||||||
| const ArrayList = std.ArrayList; | const ArrayList = std.ArrayList; | ||||||
| const a = std.testing.allocator; | const a = std.testing.allocator; | ||||||
| 
 | 
 | ||||||
| fn metrics() Buffer.Metrix { | fn metrics() Buffer.Metrics { | ||||||
|     return .{ |     return .{ | ||||||
|         .ctx = undefined, |         .ctx = undefined, | ||||||
|         .egc_length = struct { |         .egc_length = struct { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue