~gpanders/wk

f26a6282b94f8da7f0c3f918ab0cb2b79cecde66 — Greg Anders 8 months ago 04ca0b4
Add help subcommand and improve help output
M src/cmd.zig => src/cmd.zig +26 -2
@@ 1,4 1,5 @@
const std = @import("std");
const stdout = std.io.getStdOut().outStream();

const zettel = @import("zettel.zig");



@@ 19,7 20,7 @@ pub const Command = enum {
    Show,
    Tags,

    pub fn usage(comptime self: Command) []const u8 {
    pub fn usage(self: Command) []const u8 {
        return switch (self) {
            .List => list.usage,
            .New => new.usage,


@@ 31,7 32,7 @@ pub const Command = enum {
        };
    }

    pub fn desc(comptime self: Command) []const u8 {
    pub fn desc(self: Command) []const u8 {
        return switch (self) {
            .List => list.desc,
            .New => new.desc,


@@ 44,7 45,30 @@ pub const Command = enum {
    }
};

pub fn printUsage(cmd: ?Command) void {
    stdout.print("Usage: zet {}\n\n", .{if (cmd != null) cmd.?.usage() else "COMMAND"}) catch return;

    if (cmd) |_| {
        stdout.print("{}\n", .{cmd.?.desc()}) catch return;
    } else {
        stdout.print("Available commands:\n", .{}) catch return;
        inline for (@typeInfo(Command).Enum.fields) |command| {
            stdout.print("    ", .{}) catch return;
            inline for (command.name) |char| stdout.print("{c}", .{std.ascii.toLower(char)}) catch return;
            stdout.print("\n", .{}) catch return;
        }
        stdout.print("\n", .{}) catch return;
        stdout.print("Use \"zet help COMMAND\" for more information about a command.\n", .{}) catch return;
    }
}

pub fn handleCommand(allocator: *std.mem.Allocator, command: []const u8, args: ?[][]const u8) !void {
    if (std.mem.eql(u8, command, "help")) {
        const subcmd = if (args != null) try parseCommand(args.?[0]) else null;
        printUsage(subcmd);
        return;
    }

    const zettels = try zettel.getZettels(allocator);
    defer allocator.free(zettels);


M src/cmd/list.zig => src/cmd/list.zig +1 -1
@@ 4,7 4,7 @@ const stdout = std.io.getStdOut().outStream();
const Zettel = @import("../zettel.zig").Zettel;

pub const usage = "l|list [PATTERN [PATTERN ...]]";
pub const desc = "With no argument, list all notes. Otherwise list notes matching any of the given patterns";
pub const desc = "With no argument, list all notes. Otherwise list notes matching any of the given patterns.";

pub fn run(allocator: *std.mem.Allocator, patterns: ?[][]const u8, zettels: []const Zettel) !void {
    for (zettels) |zet| {

M src/cmd/new.zig => src/cmd/new.zig +1 -1
@@ 6,7 6,7 @@ const Zettel = @import("../zettel.zig").Zettel;
const util = @import("../util.zig");

pub const usage = "n|new <TITLE>";
pub const desc = "Create a new note with the given title";
pub const desc = "Create a new note with the given title.";

pub fn run(allocator: *std.mem.Allocator, title: []const u8) !void {
    const new_zettel = try Zettel.new(allocator, title);

M src/cmd/open.zig => src/cmd/open.zig +1 -1
@@ 4,7 4,7 @@ const stderr = std.io.getStdErr().outStream();
const Zettel = @import("../zettel.zig").Zettel;

pub const usage = "o|open [NOTE [NOTE ...]]";
pub const desc = "Open the given notes in your $EDITOR";
pub const desc = "Open the given notes in your $EDITOR.";

pub fn run(allocator: *std.mem.Allocator, zettels: ?[]const Zettel) !void {
    var args = std.ArrayList([]const u8).init(allocator);

M src/cmd/preview.zig => src/cmd/preview.zig +1 -1
@@ 5,7 5,7 @@ const Zettel = @import("../zettel.zig").Zettel;
const util = @import("../util.zig");

pub const usage = "p|preview <NOTE> [NOTE ...]";
pub const desc = "View notes as HTML";
pub const desc = "View notes as HTML.";

pub fn run(allocator: *std.mem.Allocator, zettels: []const Zettel) !void {
    const pandoc = util.expandPath(allocator, "pandoc") orelse {

M src/cmd/search.zig => src/cmd/search.zig +1 -1
@@ 4,7 4,7 @@ const stdout = std.io.getStdOut().outStream();
const Zettel = @import("../zettel.zig").Zettel;

pub const usage = "s|search <PATTERN> [PATTERN ...]";
pub const desc = "Search for notes whose contents match any of the given patterns";
pub const desc = "Search for notes whose contents match any of the given patterns.";

pub fn run(allocator: *std.mem.Allocator, patterns: [][]const u8, zettels: []const Zettel) !void {
    var matches = std.ArrayList(Zettel).init(allocator);

M src/cmd/show.zig => src/cmd/show.zig +1 -2
@@ 1,11 1,10 @@
const std = @import("std");
const stdout = std.io.getStdOut().outStream();
const stderr = std.io.getStdErr().outStream();

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

pub const usage = "sh|show <NOTE> [NOTE ...]";
pub const desc = "Display contents of notes to stdout";
pub const desc = "Display contents of notes to stdout.";

pub fn run(allocator: *std.mem.Allocator, zettels: []const Zettel) !void {
    for (zettels) |zet| {

M src/cmd/tags.zig => src/cmd/tags.zig +1 -1
@@ 4,7 4,7 @@ const stdout = std.io.getStdOut().outStream();
const Zettel = @import("../zettel.zig").Zettel;

pub const usage = "t|tags [TAG [TAG ...]]";
pub const desc = "With no argument, list all tags found in notes. Otherwise list all notes containing any of the given tags";
pub const desc = "With no argument, list all tags found in notes. Otherwise list all notes containing any of the given tags.";

pub fn run(allocator: *std.mem.Allocator, tags: ?[][]const u8, zettels: []const Zettel) !void {
    if (tags == null) {

M src/main.zig => src/main.zig +6 -17
@@ 4,17 4,6 @@ const stderr = std.io.getStdErr().outStream();

const cmd = @import("cmd.zig");

fn printUsage(exe: []const u8) void {
    stdout.print("Usage: {} COMMAND\n", .{std.fs.path.basename(exe)}) catch return;
    stdout.print("\n", .{}) catch return;
    stdout.print("Available commands:\n", .{}) catch return;
    inline for (@typeInfo(cmd.Command).Enum.fields) |command| {
        comptime var usage = @field(cmd.Command, command.name).usage();
        stdout.print("    {}", .{usage}) catch return;
        stdout.print("{}{}\n", .{ " " ** (36 - usage.len), @field(cmd.Command, command.name).desc() }) catch return;
    }
}

fn zettelDir(allocator: *std.mem.Allocator) ![]const u8 {
    var path: []u8 = undefined;
    if (std.os.getenv("ZETTEL_DIR")) |dir| {


@@ 54,7 43,7 @@ pub fn main() anyerror!void {

    const exe = arglist[0];
    if (arglist.len == 1) {
        printUsage(exe);
        cmd.printUsage(null);
        return;
    }



@@ 69,17 58,17 @@ pub fn main() anyerror!void {

    cmd.handleCommand(allocator, command, args) catch |err| return switch (err) {
        error.UnknownCommand => {
            try stderr.print("Unknown command: {}\n", .{command});
            printUsage(exe);
            try stderr.print("Error: unknown command: {}\n", .{command});
            try stderr.print("Use \"zet help\" for usage.\n", .{});
            std.process.exit(1);
        },
        error.MissingRequiredArgument => {
            try stderr.print("Missing required argument\n", .{});
            printUsage(exe);
            try stderr.print("Error: missing required argument\n\n", .{});
            try stderr.print("Use \"zet help\" for usage.\n", .{});
            std.process.exit(1);
        },
        error.NoAvailableBrowser => {
            try stderr.print("Couldn't find a way to open compiled notes\n", .{});
            try stderr.print("Error: couldn't find a way to open compiled notes\n", .{});
            std.process.exit(1);
        },
        error.NoMatches => {