~gpanders/wk

fe401d31fef068c4dc20f490e4241804508d3e62 — Greg Anders 2 months ago 91f55c5
Add TtyWriter to display colored output to terminal
6 files changed, 100 insertions(+), 11 deletions(-)

M src/cmd/list.zig
M src/cmd/search.zig
M src/cmd/show.zig
M src/cmd/tags.zig
A src/tty.zig
M src/zettel.zig
M src/cmd/list.zig => src/cmd/list.zig +3 -2
@@ 1,6 1,7 @@
const std = @import("std");
const ascii = std.ascii;
const mem = std.mem;
const stdout = std.io.getStdOut().outStream();

const Command = @import("../cmd.zig").Command;
const Zettel = @import("../zettel.zig").Zettel;


@@ 23,11 24,11 @@ pub fn run(allocator: *mem.Allocator, args: ?[]const []const u8) Command.Error!v
                    ascii.indexOfIgnoreCase(zet.fname, pat) != null or
                    ascii.indexOfIgnoreCase(zet.title, pat) != null)
                {
                    zet.print();
                    stdout.print("{} {}\n", .{ zet.id, zet.title }) catch return;
                }
            }
        } else {
            zet.print();
            stdout.print("{} {}\n", .{ zet.id, zet.title }) catch return;
        }
    }
}

M src/cmd/search.zig => src/cmd/search.zig +2 -1
@@ 1,6 1,7 @@
const std = @import("std");
const ascii = std.ascii;
const mem = std.mem;
const stdout = std.io.getStdOut().outStream();

const Command = @import("../cmd.zig").Command;
const Zettel = @import("../zettel.zig").Zettel;


@@ 20,7 21,7 @@ pub fn run(allocator: *mem.Allocator, args: ?[]const []const u8) Command.Error!v
        for (zettels) |zet| {
            for (patterns) |pat| {
                if (ascii.indexOfIgnoreCase(zet.contents, pat)) |_| {
                    zet.print();
                    stdout.print("{} {}\n", .{ zet.id, zet.title }) catch return;
                    break;
                }
            }

M src/cmd/show.zig => src/cmd/show.zig +20 -2
@@ 1,8 1,8 @@
const std = @import("std");
const fs = std.fs;
const mem = std.mem;
const stdout = std.io.getStdOut().outStream();

const TtyWriter = @import("../tty.zig").TtyWriter;
const Command = @import("../cmd.zig").Command;
const Zettel = @import("../zettel.zig").Zettel;
const findZettels = @import("../zettel.zig").findZettels;


@@ 20,7 20,25 @@ pub fn run(allocator: *mem.Allocator, args: ?[]const []const u8) Command.Error!v
    if (args) |_| {
        const zettels = try getZettels(allocator);
        const matches = try findZettels(allocator, zettels, args.?);
        for (matches) |zet| stdout.print("{}", .{try zet.read()}) catch return;
        for (matches) |zet| {
            const writer = TtyWriter.new(std.io.getStdOut());

            writer.setColor(.Blue).print("{}\n", .{zet.fname});
            writer.setColor(.Yellow).print("{}", .{zet.contents[0..3]});

            const metadata_end = blk: {
                if (mem.indexOfPos(u8, zet.contents, 3, "...")) |i| {
                    break :blk i;
                } else if (mem.indexOfPos(u8, zet.contents, 3, "---")) |i| {
                    break :blk i;
                } else unreachable;
            };

            writer.print("{}", .{zet.contents[3..metadata_end]});

            writer.setColor(.Yellow).print("{}", .{zet.contents[metadata_end .. metadata_end + 3]});
            writer.print("{}\n", .{zet.contents[metadata_end + 3 ..]});
        }
    } else {
        return error.MissingRequiredArgument;
    }

M src/cmd/tags.zig => src/cmd/tags.zig +2 -2
@@ 22,7 22,7 @@ pub fn run(allocator: *mem.Allocator, args: ?[]const []const u8) Command.Error!v
            for (zet.tags) |t| {
                for (args.?) |tag| {
                    if (ascii.eqlIgnoreCase(tag, t)) {
                        zet.print();
                        stdout.print("{} {}\n", .{ zet.id, zet.title }) catch return;
                        continue :outer;
                    }
                }


@@ 42,7 42,7 @@ pub fn run(allocator: *mem.Allocator, args: ?[]const []const u8) Command.Error!v

        for (tags.items) |t, i| {
            if (i == 0 or !mem.eql(u8, t, tags.items[i - 1])) {
                stdout.print("{}\n", .{t}) catch continue;
                stdout.print("{}\n", .{t}) catch return;
            }
        }
    }

A src/tty.zig => src/tty.zig +73 -0
@@ 0,0 1,73 @@
const std = @import("std");
const fs = std.fs;
const stdout = std.io.getStdOut();

pub const Color = enum(u8) {
    Black = 0,
    Red = 1,
    Green = 2,
    Yellow = 3,
    Blue = 4,
    Magenta = 5,
    Cyan = 6,
    White = 7,
    BrBlack = 8,
    BrRed = 9,
    BrGreen = 10,
    BrYellow = 11,
    BrBlue = 12,
    BrMagenta = 13,
    BrCyan = 14,
    BrWhite = 15,
};

pub const TtyWriter = struct {
    color: ?Color = null,
    bold: bool = false,
    italic: bool = false,
    file: fs.File,

    const Self = @This();

    pub fn new(file: fs.File) Self {
        return .{ .file = file };
    }

    pub fn setColor(self: Self, color: Color) Self {
        return .{ .color = color, .bold = self.bold, .italic = self.italic, .file = self.file };
    }

    pub fn print(self: Self, comptime format: []const u8, args: var) void {
        if (self.file.isTty()) {
            if (self.color) |_| {
                self.file.outStream().print("\x1b[38;5;{}m", .{@enumToInt(self.color.?)}) catch return;
            }

            if (self.bold) {
                self.file.outStream().print("\x1b[1m", .{}) catch return;
            }

            if (self.italic) {
                self.file.outStream().print("\x1b[3m", .{}) catch return;
            }
        }

        self.file.outStream().print(format, args) catch return;

        if (self.file.isTty()) {
            self.file.outStream().print("\x1b[0m", .{}) catch return;
        }
    }

    pub fn setBold(self: Self) Self {
        return .{ .color = self.color, .bold = true, .italic = self.italic, .file = self.file };
    }

    pub fn setItalic(self: Self) Self {
        return .{ .color = self.color, .bold = self.bold, .italic = true, .file = self.file };
    }

    pub fn reset(self: Self) Self {
        return .{ .color = null, .bold = false, .file = self.file };
    }
};

M src/zettel.zig => src/zettel.zig +0 -4
@@ 69,10 69,6 @@ pub const Zettel = struct {
        return try file.inStream().readAllAlloc(self.allocator, 1 * 1024 * 1024);
    }

    pub fn print(self: Zettel) void {
        stdout.print("{} {}\n", .{ self.id, self.title }) catch return;
    }

    pub fn modified(self: Zettel) !bool {
        var file = try fs.cwd().openFile(self.fname, .{ .read = true });
        defer file.close();