Skip to content
/ zerm Public

Basic low level terminal input and interaction written in pure zig with no dependencies

Notifications You must be signed in to change notification settings

Tired-Fox/zerm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zerm

A fast pure zig implementation of a terminal ansi library. It is heavily inspired by the rust crate crossterm

This project is still a work in progress, but already has most of the terminal ansi sequences implemented as batched commands. See main.zig for an example of using the commands.

Installation

zig fetch --save git+https://github.com/Tired-Fox/zerm#{commit|tag|branch}
const zerm = b.dependency("zerm", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("zerm", zerm.module("zerm"));

Example

Styling

const std = @import("std");
const zerm = @import("zerm");

const execute = zerm.execute;
const Style = zerm.style.Style;
const Reset = zerm.style.Reset;

const styling: Style = .{ .fg = .red };
std.debug.print("{s}Hello, world{s}", .{ styling, styling.reset() });

const styling: Style = .{ .fg = .red };
try execute(.stdout, .{ styling, "Hello, world", Reset { .fg = true } });

Event Handling

const std = @import("std");
const zerm = @import("zerm");

const Cursor = zerm.action.Cursor;
const Screen = zerm.action.Screen;
const Capture = zerm.action.Capture;
const getTermSize = zerm.action.getTermSize;

const EventStream = zerm.event.EventStream;

const Style = zerm.style.Style;

const Utf8ConsoleOutput = zerm.Utf8ConsoleOutput;
const execute = zerm.execute;

fn setup() !void {
    try Screen.enableRawMode();
    try execute(.stdout, .{
        Screen.enter_alternate_buffer,
        Cursor { .col = 1, .row = 1, .visibility = .hidden },
    });
}

fn cleanup() !void {
    try Screen.disableRawMode();
    try execute(.stdout, .{
        Cursor { .visibility = .visible },
        Screen.leave_alternate_buffer,
    });
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
    defer if (gpa.deinit() == .leak) { std.debug.print("memory leak detected", .{}); };
    const allo = gpa.allocator();

    var stream = EventStream.init(allo);
    defer stream.deinit();

    // Used to get around issue with zig not being able to print utf-8 unicode
    // by default
    const utf8_ctx = Utf8ConsoleOutput.init();
    defer utf8_ctx.deinit();

    try setup();
    errdefer _ = Screen.disableRawMode() catch { std.log.err("error disabling raw mode", .{}); };
    defer cleanup() catch { std.log.err("error cleaning up terminal", .{}); };

    var term = try zuit.Terminal.init(allo, .stdout);
    defer term.deinit();

    try execute(.stdout, .{ "Press `q` to quit\r\n" });

    while (true) {
        if (try stream.parseEvent()) |event| {
            switch (event) {
                .key => |key| {
                    if (key.matches(&.{ 
                        .{ .code = .char('q') },
                        .{ .code = .char('c'), .ctrl = true },
                        .{ .code = .char('C'), .ctrl = true }
                    })) break;

                    try execute(.stdout, .{ .{ "{any}", .{key} } })
                },
                .resize => |resize| {
                    try term.resize(resize[0], resize[1]);
                    try term.render(&app);
                },
                else => {}
            }
        }
    }
}

About

Basic low level terminal input and interaction written in pure zig with no dependencies

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages