The ioctl
method
We'll first create two new modules:
types.zig | hub for all the custom types of our editor |
ansi.zig | handles ansi escape sequences |
In src/types.zig
we'll write this:
//! Collection of types used by the editor.
///////////////////////////////////////////////////////////////////////////////
//
// Editor types
//
///////////////////////////////////////////////////////////////////////////////
/// Dimensions of the terminal screen where the editor runs.
pub const Screen = struct {
rows: usize = 0,
cols: usize = 0,
};
In src/ansi.zig
we'll write this:
//! Module that handles ansi terminal sequences.
///////////////////////////////////////////////////////////////////////////////
//
// Functions
//
///////////////////////////////////////////////////////////////////////////////
/// Get the window size.
pub fn getWindowSize() !t.Screen {
// code to come...
}
///////////////////////////////////////////////////////////////////////////////
//
// Constants, variables
//
///////////////////////////////////////////////////////////////////////////////
const std = @import("std");
const linux = @import("linux.zig");
const t = @import("types.zig");
We should fill the getWindowSize()
function.
var screen: t.Screen = undefined;
var wsz: std.posix.winsize = undefined;
if (linux.winsize(&wsz) == -1 or wsz.col == 0) {
// fallback method will be here
} else {
screen = t.Screen{
.rows = wsz.row,
.cols = wsz.col,
};
}
return screen;
Much like in the original C code, we use ioctl()
to request the window size
of the terminal, and this will be stored in the wsz
struct which we pass by
reference.
The ioctl()
function returns -1
on failure, but we consider a failure also
a column value of 0
in the passed wsz
struct.
Note that in the second part of the condition (wsz.col == 0
) wsz
would
already have a value because it's assumed that the ioctl()
call was
successful, since it didn't return -1
.
The winsize()
function
We'll also have to update our src/linux.zig
module to add the winsize()
function that is called in getWindowSize()
:
///////////////////////////////////////////////////////////////////////////////
//
// Functions
//
///////////////////////////////////////////////////////////////////////////////
/// Read the window size into the `wsz` struct.
pub fn winsize(wsz: *posix.winsize) usize {
return linux.ioctl(STDOUT_FILENO, linux.T.IOCGWINSZ, @intFromPtr(wsz));
}
To know why std.os.linux.ioctl
is invoked like that, we should look for it in
the Zig standard library:
pub fn ioctl(fd: fd_t, request: u32, arg: usize) usize {
return syscall3(.ioctl, @as(usize, @bitCast(@as(isize, fd))), request, arg);
}
The function doesn't have any documentation, so we just invoke it like we invoked the one in the original written in C, where the call was:
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) == -1 || wsz.ws_col == 0)
The TIOCGWINSZ
is replaced by the linux.T.IOCGWINSZ
constant, found in
std.os.linux
module of the Zig standard library.
The other difference is the third argument, that is usize
in Zig, so we must
do a pointer cast to integer:
@intFromPtr(wsz)