kiloz

Following through https://viewsourcecode.org/snaptoken/kilo/index.html in Zig
git clone git://code.mfashby.net:/kiloz
Log | Files | Refs | README

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:
Msrc/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