commit 62d20d78b83589833ee41922cde6121b646557a8
parent aa699fd69a325c4f8a025b0ad19d9d7c57412fcf
Author: Martin Ashby <martin@ashbysoft.com>
Date: Sat, 27 Jan 2024 22:50:40 +0000
Step 103
Convert rows to arraylists instead of manually managing arrays as the
kilo tutorial suggests
Diffstat:
M | src/main.zig | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 59 insertions(+), 45 deletions(-)
diff --git a/src/main.zig b/src/main.zig
@@ -75,7 +75,7 @@ const EditorState = struct {
rx: usize = 0,
rowoff: usize = 0,
coloff: usize = 0,
- erow: []ERow = &[_]ERow{},
+ erow: std.ArrayListUnmanaged(ERow) = .{},
filename: ?[]const u8 = null,
statusmsg: ?StatusMsg = null,
@@ -89,24 +89,29 @@ const EditorState = struct {
}
fn deinit(self: *EditorState) void {
self.screen_buf.deinit(self.a);
- for (self.erow) |erow| {
- self.a.free(erow.chars);
- self.a.free(erow.render);
+ for (self.erow.items) |*erow| {
+ erow.deinit(self.a);
}
- self.a.free(self.erow);
+ self.erow.deinit(self.a);
if (self.statusmsg) |*statusmsg| {
self.a.free(statusmsg.msg);
}
-
const wtr = std.io.getStdOut().writer();
wtr.writeAll(self.dbglog.items) catch {};
self.dbglog.deinit();
}
};
+const CharAL = std.ArrayListUnmanaged(u8);
+
const ERow = struct {
- chars: []u8,
- render: []u8,
+ chars: CharAL,
+ render: CharAL,
+
+ pub fn deinit(self: *ERow, a: std.mem.Allocator) void {
+ self.chars.deinit(a);
+ self.render.deinit(a);
+ }
};
fn editorProcessTimeouts(es: *EditorState) !void {
@@ -263,36 +268,31 @@ fn getWindowSize() !Size {
//// Row operations
-fn editorAppendRow(es: *EditorState, line: []u8) !void {
- const numrows = es.erow.len;
- es.erow = try es.a.realloc(es.erow, numrows + 1);
- es.erow[numrows] = .{
+fn editorAppendRow(es: *EditorState, line: CharAL) !void {
+ try es.erow.append(es.a, .{
.chars = line,
- .render = "",
- };
- try editorUpdateRow(es, &es.erow[numrows]);
+ .render = .{},
+ });
+ try editorUpdateRow(es, &es.erow.items[es.erow.items.len - 1]);
}
fn editorUpdateRow(es: *EditorState, erow: *ERow) !void {
- es.a.free(erow.render);
- var al = std.ArrayList(u8).init(es.a);
- defer al.deinit();
- for (erow.chars) |c| {
+ erow.render.clearRetainingCapacity();
+ for (erow.chars.items) |c| {
if (c == '\t') {
- var tabs = tabstop - @mod(al.items.len, tabstop);
+ var tabs = tabstop - @mod(erow.render.items.len, tabstop);
if (tabs == 0) tabs = tabstop;
- try al.appendNTimes(' ', tabs);
+ try erow.render.appendNTimes(es.a, ' ', tabs);
} else {
- try al.append(c);
+ try erow.render.append(es.a, c);
}
}
- erow.render = try al.toOwnedSlice();
}
fn editorRowCxToRx(erow: *ERow, cx: usize) usize {
var rx: usize = 0;
for (0..cx) |j| {
- if (erow.chars[j] == '\t') {
+ if (erow.chars.items[j] == '\t') {
rx += (tabstop - 1) - (@mod(rx, tabstop));
} else {
rx += 1;
@@ -301,6 +301,21 @@ fn editorRowCxToRx(erow: *ERow, cx: usize) usize {
return rx;
}
+fn editorRowInsertChar(es: *EditorState, erow: *ERow, at: usize, c: u8) !void {
+ try erow.chars.insert(es.a, at, c);
+ try editorUpdateRow(es, erow);
+}
+
+//// Editor operations
+
+fn editorInsertChar(es: *EditorState, c: u8) !void {
+ if (es.cy == es.erow.items.len) {
+ try editorAppendRow(es, .{});
+ }
+ try editorRowInsertChar(es, &es.erow.items[es.cy], es.cx, c);
+ es.cx += 1;
+}
+
//// File i/o
fn editorOpen(es: *EditorState, filename: []const u8) !void {
@@ -308,15 +323,14 @@ fn editorOpen(es: *EditorState, filename: []const u8) !void {
defer f.close();
var br = std.io.bufferedReader(f.reader());
var rdr = br.reader();
- var al = std.ArrayList(u8).init(es.a);
- defer al.deinit();
+
lp: while (true) {
- rdr.streamUntilDelimiter(al.writer(), '\n', null) catch |e| switch (e) {
+ var line = std.ArrayListUnmanaged(u8){};
+ errdefer line.deinit(es.a);
+ rdr.streamUntilDelimiter(line.writer(es.a), '\n', null) catch |e| switch (e) {
error.EndOfStream => break :lp,
else => return e,
};
- const line = try al.toOwnedSlice();
- errdefer es.a.free(line);
try editorAppendRow(es, line);
}
es.filename = filename;
@@ -359,8 +373,8 @@ fn editorDrawRows(es: *const EditorState, wtr: anytype) !void {
var lw = truncateWriter(wtr, es.screencols); // Never write more than we have columns
const wtr2 = lw.writer();
const filerow = y + es.rowoff;
- if (filerow >= es.erow.len) {
- if (es.erow.len == 0 and y == es.screenrows / 3) {
+ if (filerow >= es.erow.items.len) {
+ if (es.erow.items.len == 0 and y == es.screenrows / 3) {
const welcome_msg = try std.fmt.allocPrint(es.a, "Kilo editor -- version {s}", .{version}); // TODO don't allocate every time...
defer es.a.free(welcome_msg);
const padding = (es.screencols - welcome_msg.len) / 2;
@@ -372,7 +386,7 @@ fn editorDrawRows(es: *const EditorState, wtr: anytype) !void {
try wtr2.writeAll("~");
}
} else {
- var row = es.erow[filerow].render;
+ var row = es.erow.items[filerow].render.items;
if (row.len < es.coloff) {
row = "";
} else {
@@ -391,13 +405,13 @@ fn editorDrawStatusBar(es: *const EditorState, wtr: anytype) !void {
defer es.a.free(buf);
@memset(buf, ' ');
const fname = es.filename orelse "<no file>";
- _ = std.fmt.bufPrint(buf, "{s} - {} lines", .{fname, es.erow.len}) catch |e| switch (e) {
+ _ = std.fmt.bufPrint(buf, "{s} - {} lines", .{ fname, es.erow.items.len }) catch |e| switch (e) {
error.NoSpaceLeft => {},
else => return e,
};
- const sz = std.fmt.count("{}/{}", .{es.cy+1,es.erow.len});
+ const sz = std.fmt.count("{}/{}", .{ es.cy + 1, es.erow.items.len });
if (buf.len >= sz) {
- _ = std.fmt.bufPrint(buf[buf.len-sz..], "{}/{}", .{es.cy+1,es.erow.len}) catch |e| switch (e) {
+ _ = std.fmt.bufPrint(buf[buf.len - sz ..], "{}/{}", .{ es.cy + 1, es.erow.items.len }) catch |e| switch (e) {
error.NoSpaceLeft => {},
else => return e,
};
@@ -418,8 +432,8 @@ fn editorDrawMessageBar(es: *EditorState, wtr: anytype) !void {
fn editorScroll(es: *EditorState) void {
es.rx = 0;
- if (es.cy < es.erow.len) {
- es.rx = editorRowCxToRx(&es.erow[es.cy], es.cx);
+ if (es.cy < es.erow.items.len) {
+ es.rx = editorRowCxToRx(&es.erow.items[es.cy], es.cx);
}
if (es.cy < es.rowoff) {
@@ -457,7 +471,7 @@ fn editorProcessKeyPress(es: *EditorState) !void {
.char => |ch| {
switch (ch) {
quit.char => return error.Quit,
- else => {},
+ else => try editorInsertChar(es, ch),
}
},
.virt => |v| {
@@ -472,7 +486,7 @@ fn editorProcessKeyPress(es: *EditorState) !void {
fn editorVMove(dir: enum { up, down }, n: usize, es: *EditorState) void {
es.cy = switch (dir) {
.up => std.math.sub(usize, es.cy, n) catch 0,
- .down => std.math.clamp(es.cy + n, 0, es.erow.len - 1),
+ .down => std.math.clamp(es.cy + n, 0, es.erow.items.len - 1),
};
}
@@ -488,19 +502,19 @@ fn editorMoveCursor(key: editorKey, es: *EditorState) void {
if (es.cx_t == 0) {
if (es.cy > 0) {
es.cy -= 1;
- es.cx_t = es.erow[es.cy].chars.len;
+ es.cx_t = es.erow.items[es.cy].chars.items.len;
}
} else {
- if (es.cx_t >= es.erow[es.cy].chars.len) {
- es.cx_t = es.erow[es.cy].chars.len - 1;
+ if (es.cx_t >= es.erow.items[es.cy].chars.items.len) {
+ es.cx_t = es.erow.items[es.cy].chars.items.len - 1;
} else {
es.cx_t -= 1;
}
}
},
.ARROW_RIGHT => {
- if (es.cx_t >= es.erow[es.cy].chars.len) {
- if (es.cy < (es.erow.len - 1)) {
+ if (es.cx_t >= es.erow.items[es.cy].chars.items.len) {
+ if (es.cy < (es.erow.items.len - 1)) {
es.cy += 1;
es.cx_t = 0;
}
@@ -523,7 +537,7 @@ fn editorMoveCursor(key: editorKey, es: *EditorState) void {
else => {},
}
- es.cx = std.math.clamp(es.cx_t, 0, es.erow[es.cy].chars.len);
+ es.cx = std.math.clamp(es.cx_t, 0, es.erow.items[es.cy].chars.items.len);
}
//// Init