The Buffer type
Description at the top:
//! A Buffer holds the representation of a file, divided in rows.
//! If modified, it is marked as dirty until saved.
Let's add the constants: as usual, they'll stay at the bottom.
Also here we set a constant to @This()
, so that we can refer to our type
inside its own definition.
///////////////////////////////////////////////////////////////////////////////
//
// Constants, variables
//
///////////////////////////////////////////////////////////////////////////////
const Buffer = @This();
const std = @import("std");
const t = @import("types.zig");
/// Initial allocation size for Buffer.rows
const initial_rows_capacity = 40;
Fields
Also in this case, as you can see, no default initializers.
Some members are optional, meaning that they can be null
, and null
will
be their initial value when the Buffer is initialized.
alc: std.mem.Allocator,
// Modified state
dirty: bool,
// Buffer rows
rows: std.ArrayList(t.Row),
// Path of the file
filename: ?[]u8,
// Name of the syntax
syntax: ?[]const u8,
Initialization
All in all, this type is quite simple. It doesn't handle single row
initialization, because rows are created and inserted by the Editor, but it
will deinitialize them. Possibly I'm doing a questionable choice here, maybe
I should let the Buffer initialize the single rows, since it's here that
they're freed at last. Especially if we intend to give a Buffer its own
different allocator (an arena
allocator probably would fit it best). But it's
a small detail, since the Editor can access the Buffer
allocator just fine,
since there are no private fields in Zig.
///////////////////////////////////////////////////////////////////////////////
//
// Init/deinit
//
///////////////////////////////////////////////////////////////////////////////
pub fn init(allocator: std.mem.Allocator) !Buffer {
return Buffer{
.alc = allocator,
.rows = try .initCapacity(allocator, initial_rows_capacity),
.dirty = false,
.filename = null,
.syntax = null,
};
}
pub fn deinit(buf: *Buffer) void {
t.freeOptional(buf.alc, buf.filename);
t.freeOptional(buf.alc, buf.syntax);
for (buf.rows.items) |*row| {
row.deinit(buf.alc);
}
buf.rows.deinit(buf.alc);
}
There is one new function, freeOptional()
, which we didn't define yet.
It's a simple helper, but it doesn't harm to have some helper functions.
I put it in the types
module, right above the bottom section:
///////////////////////////////////////////////////////////////////////////////
//
// Functions
//
///////////////////////////////////////////////////////////////////////////////
/// Free an optional slice if not null.
pub fn freeOptional(allocator: std.mem.Allocator, sl: anytype) void {
if (sl) |slice| {
allocator.free(slice);
}
}