refactor: move buffer module to a subdirectory
This commit is contained in:
parent
b2c12ba337
commit
6bab2e6cda
6 changed files with 1 additions and 1 deletions
1165
src/buffer/Buffer.zig
Normal file
1165
src/buffer/Buffer.zig
Normal file
File diff suppressed because it is too large
Load diff
220
src/buffer/Cursor.zig
Normal file
220
src/buffer/Cursor.zig
Normal file
|
@ -0,0 +1,220 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const Buffer = @import("Buffer.zig");
|
||||
const View = @import("View.zig");
|
||||
const Selection = @import("Selection.zig");
|
||||
|
||||
row: usize = 0,
|
||||
col: usize = 0,
|
||||
target: usize = 0,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub inline fn invalid() Self {
|
||||
return .{
|
||||
.row = std.math.maxInt(u32),
|
||||
.col = std.math.maxInt(u32),
|
||||
.target = std.math.maxInt(u32),
|
||||
};
|
||||
}
|
||||
|
||||
pub inline fn eql(self: Self, other: Self) bool {
|
||||
return self.row == other.row and self.col == other.col;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn clamp_to_buffer(self: *Self, root: Buffer.Root) void {
|
||||
self.row = @min(self.row, root.lines() - 1);
|
||||
self.col = @min(self.col, root.line_width(self.row) catch 0);
|
||||
}
|
||||
|
||||
fn follow_target(self: *Self, root: Buffer.Root) void {
|
||||
self.col = @min(self.target, root.line_width(self.row) catch 0);
|
||||
}
|
||||
|
||||
fn move_right_no_target(self: *Self, root: Buffer.Root) !void {
|
||||
const lines = root.lines();
|
||||
if (lines <= self.row) return error.Stop;
|
||||
if (self.col < root.line_width(self.row) catch 0) {
|
||||
_, const wcwidth, const offset = root.ecg_at(self.row, self.col) catch return error.Stop;
|
||||
self.col += wcwidth - offset;
|
||||
} else if (self.row < lines - 1) {
|
||||
self.col = 0;
|
||||
self.row += 1;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_right(self: *Self, root: Buffer.Root) !void {
|
||||
try self.move_right_no_target(root);
|
||||
self.target = self.col;
|
||||
}
|
||||
|
||||
fn move_left_no_target(self: *Self, root: Buffer.Root) !void {
|
||||
if (self.col == 0) {
|
||||
if (self.row == 0) return error.Stop;
|
||||
self.row -= 1;
|
||||
self.col = root.line_width(self.row) catch 0;
|
||||
} else {
|
||||
_, const wcwidth, _ = root.ecg_at(self.row, self.col - 1) catch return error.Stop;
|
||||
if (self.col > wcwidth) self.col -= wcwidth else self.col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_left(self: *Self, root: Buffer.Root) !void {
|
||||
try self.move_left_no_target(root);
|
||||
self.target = self.col;
|
||||
}
|
||||
|
||||
pub fn move_up(self: *Self, root: Buffer.Root) !void {
|
||||
if (self.row > 0) {
|
||||
self.row -= 1;
|
||||
self.follow_target(root);
|
||||
self.move_left_no_target(root) catch return;
|
||||
try self.move_right_no_target(root);
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_down(self: *Self, root: Buffer.Root) !void {
|
||||
if (self.row < root.lines() - 1) {
|
||||
self.row += 1;
|
||||
self.follow_target(root);
|
||||
self.move_left_no_target(root) catch return;
|
||||
try self.move_right_no_target(root);
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_page_up(self: *Self, root: Buffer.Root, view: *const View) void {
|
||||
self.row = if (self.row > view.rows) self.row - view.rows else 0;
|
||||
self.follow_target(root);
|
||||
self.move_left_no_target(root) catch return;
|
||||
self.move_right_no_target(root) catch return;
|
||||
}
|
||||
|
||||
pub fn move_page_down(self: *Self, root: Buffer.Root, view: *const View) void {
|
||||
if (root.lines() < view.rows) {
|
||||
self.move_buffer_last(root);
|
||||
} else if (self.row < root.lines() - view.rows - 1) {
|
||||
self.row += view.rows;
|
||||
} else self.row = root.lines() - 1;
|
||||
self.follow_target(root);
|
||||
self.move_left_no_target(root) catch return;
|
||||
self.move_right_no_target(root) catch return;
|
||||
}
|
||||
|
||||
pub fn move_to(self: *Self, root: Buffer.Root, row: usize, col: usize) !void {
|
||||
if (row < root.lines()) {
|
||||
self.row = row;
|
||||
self.col = @min(col, root.line_width(self.row) catch return error.Stop);
|
||||
self.target = self.col;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_abs(self: *Self, root: Buffer.Root, v: *View, y: usize, x: usize) !void {
|
||||
self.row = v.row + y;
|
||||
self.col = v.col + x;
|
||||
self.clamp_to_buffer(root);
|
||||
self.target = self.col;
|
||||
}
|
||||
|
||||
pub fn move_begin(self: *Self) void {
|
||||
self.col = 0;
|
||||
self.target = self.col;
|
||||
}
|
||||
|
||||
pub fn move_end(self: *Self, root: Buffer.Root) void {
|
||||
if (self.row < root.lines()) self.col = root.line_width(self.row) catch 0;
|
||||
self.target = std.math.maxInt(u32);
|
||||
}
|
||||
|
||||
pub fn move_buffer_begin(self: *Self) void {
|
||||
self.row = 0;
|
||||
self.col = 0;
|
||||
self.target = 0;
|
||||
}
|
||||
|
||||
pub fn move_buffer_end(self: *Self, root: Buffer.Root) void {
|
||||
self.row = root.lines() - 1;
|
||||
self.move_end(root);
|
||||
if (self.col == 0) self.target = 0;
|
||||
}
|
||||
|
||||
fn move_buffer_first(self: *Self, root: Buffer.Root) void {
|
||||
self.row = 0;
|
||||
self.follow_target(root);
|
||||
}
|
||||
|
||||
fn move_buffer_last(self: *Self, root: Buffer.Root) void {
|
||||
self.row = root.lines() - 1;
|
||||
self.follow_target(root);
|
||||
}
|
||||
|
||||
fn is_at_begin(self: *const Self) bool {
|
||||
return self.col == 0;
|
||||
}
|
||||
|
||||
fn is_at_end(self: *const Self, root: Buffer.Root) bool {
|
||||
return if (self.row < root.lines()) self.col == root.line_width(self.row) catch 0 else true;
|
||||
}
|
||||
|
||||
pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool) bool {
|
||||
return root.test_at(pred, self.row, self.col);
|
||||
}
|
||||
|
||||
pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||
try cbor.writeValue(writer, .{
|
||||
self.row,
|
||||
self.col,
|
||||
self.target,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn extract(self: *Self, iter: *[]const u8) !bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.row),
|
||||
cbor.extract(&self.col),
|
||||
cbor.extract(&self.target),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn nudge_insert(self: *Self, nudge: Selection) void {
|
||||
if (self.row < nudge.begin.row or (self.row == nudge.begin.row and self.col < nudge.begin.col)) return;
|
||||
|
||||
const rows = nudge.end.row - nudge.begin.row;
|
||||
if (self.row == nudge.begin.row) {
|
||||
if (nudge.begin.row < nudge.end.row) {
|
||||
self.row += rows;
|
||||
self.col = self.col - nudge.begin.col + nudge.end.col;
|
||||
} else {
|
||||
self.col += nudge.end.col - nudge.begin.col;
|
||||
}
|
||||
} else {
|
||||
self.row += rows;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nudge_delete(self: *Self, nudge: Selection) bool {
|
||||
if (self.row < nudge.begin.row or (self.row == nudge.begin.row and self.col < nudge.begin.col)) return true;
|
||||
if (self.row == nudge.begin.row) {
|
||||
if (nudge.begin.row < nudge.end.row) {
|
||||
return false;
|
||||
} else {
|
||||
if (self.col < nudge.end.col) {
|
||||
return false;
|
||||
}
|
||||
self.col -= nudge.end.col - nudge.begin.col;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (self.row < nudge.end.row) return false;
|
||||
if (self.row == nudge.end.row) {
|
||||
if (self.col < nudge.end.col) return false;
|
||||
self.row -= nudge.end.row - nudge.begin.row;
|
||||
self.col -= nudge.end.col;
|
||||
return true;
|
||||
}
|
||||
self.row -= nudge.end.row - nudge.begin.row;
|
||||
return true;
|
||||
}
|
61
src/buffer/Selection.zig
Normal file
61
src/buffer/Selection.zig
Normal file
|
@ -0,0 +1,61 @@
|
|||
const std = @import("std");
|
||||
const Buffer = @import("Buffer.zig");
|
||||
const Cursor = @import("Cursor.zig");
|
||||
|
||||
begin: Cursor = Cursor{},
|
||||
end: Cursor = Cursor{},
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub inline fn eql(self: Self, other: Self) bool {
|
||||
return self.begin.eql(other.begin) and self.end.eql(other.end);
|
||||
}
|
||||
|
||||
pub fn from_cursor(cursor: *const Cursor) Self {
|
||||
return .{ .begin = cursor.*, .end = cursor.* };
|
||||
}
|
||||
|
||||
pub fn line_from_cursor(cursor: Cursor, root: Buffer.Root) Self {
|
||||
var begin = cursor;
|
||||
var end = cursor;
|
||||
begin.move_begin();
|
||||
end.move_end(root);
|
||||
end.move_right(root) catch {};
|
||||
return .{ .begin = begin, .end = end };
|
||||
}
|
||||
|
||||
pub fn empty(self: *const Self) bool {
|
||||
return self.begin.eql(self.end);
|
||||
}
|
||||
|
||||
pub fn reverse(self: *Self) void {
|
||||
const tmp = self.begin;
|
||||
self.begin = self.end;
|
||||
self.end = tmp;
|
||||
}
|
||||
|
||||
pub fn normalize(self: *Self) void {
|
||||
if (self.begin.right_of(self.end))
|
||||
self.reverse();
|
||||
}
|
||||
|
||||
pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||
try self.begin.write(writer);
|
||||
try self.end.write(writer);
|
||||
}
|
||||
|
||||
pub fn extract(self: *Self, iter: *[]const u8) !bool {
|
||||
if (!try self.begin.extract(iter)) return false;
|
||||
return self.end.extract(iter);
|
||||
}
|
||||
|
||||
pub fn nudge_insert(self: *Self, nudge: Self) void {
|
||||
self.begin.nudge_insert(nudge);
|
||||
self.end.nudge_insert(nudge);
|
||||
}
|
||||
|
||||
pub fn nudge_delete(self: *Self, nudge: Self) bool {
|
||||
if (!self.begin.nudge_delete(nudge))
|
||||
return false;
|
||||
return self.end.nudge_delete(nudge);
|
||||
}
|
142
src/buffer/View.zig
Normal file
142
src/buffer/View.zig
Normal file
|
@ -0,0 +1,142 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const Buffer = @import("Buffer.zig");
|
||||
const Cursor = @import("Cursor.zig");
|
||||
const Selection = @import("Selection.zig");
|
||||
|
||||
row: usize = 0,
|
||||
col: usize = 0,
|
||||
rows: usize = 0,
|
||||
cols: usize = 0,
|
||||
|
||||
const scroll_cursor_min_border_distance = 5;
|
||||
const scroll_cursor_min_border_distance_mouse = 1;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub inline fn invalid() Self {
|
||||
return .{
|
||||
.row = std.math.maxInt(u32),
|
||||
.col = std.math.maxInt(u32),
|
||||
};
|
||||
}
|
||||
|
||||
inline fn reset(self: *Self) void {
|
||||
self.* = .{};
|
||||
}
|
||||
|
||||
pub inline fn eql(self: Self, other: Self) bool {
|
||||
return self.row == other.row and self.col == other.col and self.rows == other.rows and self.cols == other.cols;
|
||||
}
|
||||
|
||||
pub fn move_left(self: *Self) !void {
|
||||
if (self.col > 0) {
|
||||
self.col -= 1;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_right(self: *Self) !void {
|
||||
self.col += 1;
|
||||
}
|
||||
|
||||
pub fn move_up(self: *Self) !void {
|
||||
if (!self.is_at_top()) {
|
||||
self.row -= 1;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_down(self: *Self, root: Buffer.Root) !void {
|
||||
if (!self.is_at_bottom(root)) {
|
||||
self.row += 1;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
pub fn move_to(self: *Self, root: Buffer.Root, row: usize) !void {
|
||||
if (row < root.lines() - self.rows - 1) {
|
||||
self.row = row;
|
||||
} else return error.Stop;
|
||||
}
|
||||
|
||||
inline fn is_at_top(self: *const Self) bool {
|
||||
return self.row == 0;
|
||||
}
|
||||
|
||||
inline fn is_at_bottom(self: *const Self, root: Buffer.Root) bool {
|
||||
if (root.lines() < self.rows) return true;
|
||||
return self.row >= root.lines() - scroll_cursor_min_border_distance;
|
||||
}
|
||||
|
||||
pub inline fn is_visible(self: *const Self, cursor: *const Cursor) bool {
|
||||
const row_min = self.row;
|
||||
const row_max = row_min + self.rows;
|
||||
const col_min = self.col;
|
||||
const col_max = col_min + self.cols;
|
||||
return row_min <= cursor.row and cursor.row <= row_max and
|
||||
col_min <= cursor.col and cursor.col < col_max;
|
||||
}
|
||||
|
||||
inline fn is_visible_selection(self: *const Self, sel: *const Selection) bool {
|
||||
const row_min = self.row;
|
||||
const row_max = row_min + self.rows;
|
||||
return self.is_visible(sel.begin) or is_visible(sel.end) or
|
||||
(sel.begin.row < row_min and sel.end.row > row_max);
|
||||
}
|
||||
|
||||
inline fn to_cursor_top(self: *const Self) Cursor {
|
||||
return .{ .row = self.row, .col = 0 };
|
||||
}
|
||||
|
||||
inline fn to_cursor_bottom(self: *const Self, root: Buffer.Root) Cursor {
|
||||
const bottom = @min(root.lines(), self.row + self.rows + 1);
|
||||
return .{ .row = bottom, .col = 0 };
|
||||
}
|
||||
|
||||
fn clamp_row(self: *Self, cursor: *const Cursor, abs: bool) void {
|
||||
const min_border_distance: usize = if (abs) scroll_cursor_min_border_distance_mouse else scroll_cursor_min_border_distance;
|
||||
if (cursor.row < min_border_distance) {
|
||||
self.row = 0;
|
||||
return;
|
||||
}
|
||||
if (self.row > 0 and cursor.row >= min_border_distance) {
|
||||
if (cursor.row < self.row + min_border_distance) {
|
||||
self.row = cursor.row - min_border_distance;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cursor.row < self.row) {
|
||||
self.row = 0;
|
||||
} else if (cursor.row > self.row + self.rows - min_border_distance) {
|
||||
self.row = cursor.row + min_border_distance - self.rows;
|
||||
}
|
||||
}
|
||||
|
||||
fn clamp_col(self: *Self, cursor: *const Cursor, _: bool) void {
|
||||
if (cursor.col < self.col) {
|
||||
self.col = cursor.col;
|
||||
} else if (cursor.col > self.col + self.cols - 1) {
|
||||
self.col = cursor.col - self.cols + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clamp(self: *Self, cursor: *const Cursor, abs: bool) void {
|
||||
self.clamp_row(cursor, abs);
|
||||
self.clamp_col(cursor, abs);
|
||||
}
|
||||
|
||||
pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||
try cbor.writeValue(writer, .{
|
||||
self.row,
|
||||
self.col,
|
||||
self.rows,
|
||||
self.cols,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn extract(self: *Self, iter: *[]const u8) !bool {
|
||||
return cbor.matchValue(iter, .{
|
||||
cbor.extract(&self.row),
|
||||
cbor.extract(&self.col),
|
||||
cbor.extract(&self.rows),
|
||||
cbor.extract(&self.cols),
|
||||
});
|
||||
}
|
39
src/buffer/unicode.zig
Normal file
39
src/buffer/unicode.zig
Normal file
|
@ -0,0 +1,39 @@
|
|||
pub fn control_code_to_unicode(code: u8) [:0]const u8 {
|
||||
return switch (code) {
|
||||
'\x00' => "␀",
|
||||
'\x01' => "␁",
|
||||
'\x02' => "␂",
|
||||
'\x03' => "␃",
|
||||
'\x04' => "␄",
|
||||
'\x05' => "␅",
|
||||
'\x06' => "␆",
|
||||
'\x07' => "␇",
|
||||
'\x08' => "␈",
|
||||
'\x09' => "␉",
|
||||
'\x0A' => "␊",
|
||||
'\x0B' => "␋",
|
||||
'\x0C' => "␌",
|
||||
'\x0D' => "␍",
|
||||
'\x0E' => "␎",
|
||||
'\x0F' => "␏",
|
||||
'\x10' => "␐",
|
||||
'\x11' => "␑",
|
||||
'\x12' => "␒",
|
||||
'\x13' => "␓",
|
||||
'\x14' => "␔",
|
||||
'\x15' => "␕",
|
||||
'\x16' => "␖",
|
||||
'\x17' => "␗",
|
||||
'\x18' => "␘",
|
||||
'\x19' => "␙",
|
||||
'\x1A' => "␚",
|
||||
'\x1B' => "␛",
|
||||
'\x1C' => "␜",
|
||||
'\x1D' => "␝",
|
||||
'\x1E' => "␞",
|
||||
'\x1F' => "␟",
|
||||
'\x20' => "␠",
|
||||
'\x7F' => "␡",
|
||||
else => "",
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue