Skip to content

Commit

Permalink
Revamp window size detection
Browse files Browse the repository at this point in the history
Add support for several platforms
Remove the need for explicit linking of libc for Windows
Fix conhost.exe support
  • Loading branch information
Siphonay committed Mar 17, 2024
1 parent f97156b commit 4088404
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 43 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,27 @@ usage: zcellterm <rule>
rule should be a nubmer between 0 and 255.
```

## Currently supported platforms for automatic terminal size
## Supported platforms for automatic terminal size
### Tested
* Linux
* macOS
* Windows
* FreeBSD
### Untested, probably works if you can build for those platforms
* NetBSD
* OpenBSD
* Haiku
* Solaris

Know how to implement size detection for a platform not listed here? Feel free to contribute!

## TODO
* Let user specify size while using term size by default (only using term size atm)
* Implement more platforms (please contribute!)
* Infinite scrolling mode
* Let user choose to have a random starting generation
* Let user start at a specific generation

## Thanks
Thank you @AliceDiNunno for testing out macOS compatibility, as well as Hestia and FelixLeTrain on the [Zig Programming Language Discord server](https://discord.gg/zig) for their feedback
Thank you @AliceDiNunno for testing out macOS compatibility, as well as Hestia and FelixLeTrain on the [Zig Programming Language Discord server](https://discord.gg/zig) for their feedback

I was able to improve the terminal size detection for Windows by taking example on [softprops’ implementation](https://github.com/softprops/zig-termsize)
5 changes: 0 additions & 5 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});

// Link LibC for Windows terminal size support
if (builtin.target.os.tag == .windows) {
exe.linkLibC();
}

// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.name = "zcellterm",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.2",
.version = "0.1.0",

// This field is optional.
// This is currently advisory only; Zig does not yet do anything
Expand Down
54 changes: 22 additions & 32 deletions src/getterminalsize.zig
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
const std = @import("std");
const builtin = @import("builtin");
const os = std.os;
const windows = std.os.windows;
const c = @cImport({
@cInclude("Windows.h");
});

pub const TermSizeError = error{
Unexpected,
Unsupported,
};

pub const TermSize = struct {
col: u16,
row: u16,
};

pub fn getTerminalSize() !TermSize {
pub fn getTerminalSize() TermSizeError!TermSize {
switch (builtin.target.os.tag) {
.linux, .macos => {
.windows => {
var winsize: os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;

if (os.windows.kernel32.GetConsoleScreenBufferInfo(std.io.getStdOut().handle, &winsize) != os.windows.TRUE)
return error.Unexpected;

return TermSize{ // These are stored in a signed type (windows.SHORT) but will never be negative
.col = @intCast(winsize.srWindow.Right - winsize.srWindow.Left + 1),
.row = @intCast(winsize.srWindow.Bottom - winsize.srWindow.Top + 1),
};
},
else => {
if (!@hasDecl(os.system, "T")) {
return error.Unsupported;
}

var winsize: os.system.winsize = undefined;

switch (os.errno(os.system.ioctl(std.io.getStdOut().handle, os.system.T.IOCGWINSZ, @intFromPtr(&winsize)))) {
Expand All @@ -24,31 +40,5 @@ pub fn getTerminalSize() !TermSize {
else => return error.Unexpected,
}
},
.windows => {
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
const stdout_handle = windows.kernel32.GetStdHandle(c.STD_OUTPUT_HANDLE);

if (stdout_handle == c.INVALID_HANDLE_VALUE)
return error.Unexpected;

if (windows.kernel32.GetConsoleScreenBufferInfo(stdout_handle.?, &info) != windows.TRUE)
return error.Unexpected;

return TermSize{ // These are stored in a signed type (windows.SHORT) but will never be negative
.col = @intCast(info.dwSize.X),
.row = @intCast(info.dwSize.Y),
};
},
else => {
std.log.info(
\\Getting terminal size is not available for your platform yet. Defaulting to 80x25.
\\Feel free to contribute by sending a pull request to add it!
\\Setting terminal size manually will be implemented soon.
, .{});
return TermSize{
.col = 80,
.row = 25,
};
},
}
}
18 changes: 16 additions & 2 deletions src/zcellterm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,21 @@ pub fn main() !void {
return error.InvalidArg;
}

const termsize = try getterminalsize.getTerminalSize();
const termsize = getterminalsize.getTerminalSize() catch |err| blk: {
switch (err) {
getterminalsize.TermSizeError.Unsupported => {
std.log.warn("Getting terminal size automatically is not available for platform {s}. Defaulting to 80x25.", .{@tagName(builtin.target.os.tag)});
break :blk getterminalsize.TermSize{
.col = 80,
.row = 25,
};
},
else => {
std.log.err("Unexpected error getting terminal size.", .{});
return err;
},
}
};

var current_gen = try gp_allocator.alloc(u1, termsize.col);
defer gp_allocator.free(current_gen);
Expand All @@ -53,7 +67,7 @@ pub fn main() !void {
current_gen[termsize.col / 2] = 1;

const rule: u8 = std.fmt.parseInt(u8, args[1], 10) catch {
try stderr.print("Please specify a rule between 0 and 255\n", .{});
std.log.err("Please specify a rule between 0 and 255.", .{});
return error.InvalidArg;
};

Expand Down

0 comments on commit 4088404

Please sign in to comment.