M README.md => README.md +21 -39
@@ 14,7 14,9 @@ running the following from the project root:
make PREFIX=$PREFIX install
-If you use macOS you can use
+If `PREFIX` is not specified, `zet` will be installed under `zig-cache/bin/`.
+
+If you use macOS and Homebrew you can use
brew install gpanders/tap/zet
@@ 25,55 27,35 @@ Notes are stored in the directory represented by the environment variable
`$ZETTEL_DIR`. If `$ZETTEL_DIR` is unset, it defaults to
`$HOME/.local/share/zet/`.
-In the following commands, `NOTE` is a note ID, title, or the file name of an
-existing note with or without the extension.
-
-List all notes in your Zettelkasten:
-
- zet list
+Notes are created with
-Create a new note:
+ zet new TITLE
- zet new 'TITLE'
-
-The file name of the note will be the given title prepended with a unique ID
-and a `.md` suffix. The title can contain spaces, but be sure to wrap it in
-quotes so your shell doesn't split it.
+The file name of the new note will be the given title prepended with a unique
+ID and a `.md` extension. The title can contain spaces, but be sure to wrap it
+in quotes so your shell doesn't split it.
If you keep your notes in a git repository, `zet new` will automatically commit
your new note with the title as the commit message. There is (currently) no way
to disable this behavior.
-Open a note in your `$EDITOR` (defaults to `vi` if `$EDITOR` is unset):
-
- zet open [NOTE]
-
-With no argument, `zet open` will open your `$EDITOR` in the directory
-containing your notes.
+To list all of your existing notes, use
-Display a note's contents to stdout:
-
- zet show NOTE
-
-Search through note contents and file names and report matches:
-
- zet search PATTERN
-
-List all note tags:
-
- zet tags
+ zet list
-List all notes matching a certain tag:
+This will print the title of each existing note along with its ID.
- zet tags TAG
+For a full list of available commands, use `zet help`. For more information on
+a specific command, use `zet help COMMAND`.
-Add or update backlinks:
+For commands that take arguments, the argument can be a note ID, title, or file
+name (with or without the extension) of an existing note. The output of any
+`zet` command can be used with other commands, allowing commands to be
+composed. For example, to open all notes containing the tag "foo", use
- zet backlinks [NOTE]
+ zet open "$(zet tag foo)"
-The argument to the `backlinks` command is optional. If no argument is given,
-`zet` will update backlinks in all notes; otherwise, only backlinks to the
-given note(s) will be updated.
+Note that the surrounding quotes are necessary to prevent the shell from word
+splitting the output of the `zet tag foo` command.
-Note that `zet new` will automatically update backlinks after creating a new
-note.
+Most commands can be abbreviated. Use `zet help CMD` for more information.
M src/cmd/list.zig => src/cmd/list.zig +2 -3
@@ 1,5 1,4 @@
const std = @import("std");
-const stdout = std.io.getStdOut().outStream();
const Zettel = @import("../zettel.zig").Zettel;
@@ 14,11 13,11 @@ pub fn run(allocator: *std.mem.Allocator, patterns: ?[][]const u8, zettels: []co
std.ascii.indexOfIgnoreCase(zet.fname, pat) != null or
std.ascii.indexOfIgnoreCase(zet.title, pat) != null)
{
- try stdout.print("{} {}\n", .{ zet.id, zet.title });
+ try zet.print();
}
}
} else {
- try stdout.print("{} {}\n", .{ zet.id, zet.title });
+ try zet.print();
}
}
}
M src/cmd/search.zig => src/cmd/search.zig +1 -2
@@ 1,5 1,4 @@
const std = @import("std");
-const stdout = std.io.getStdOut().outStream();
const Zettel = @import("../zettel.zig").Zettel;
@@ 37,6 36,6 @@ pub fn run(allocator: *std.mem.Allocator, patterns: [][]const u8, zettels: []con
}
for (matches.items) |match, i| {
- try stdout.print("{} {}\n", .{ match.id, match.title });
+ try match.print();
}
}
M src/cmd/tags.zig => src/cmd/tags.zig +12 -12
@@ 7,7 7,18 @@ 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 fn run(allocator: *std.mem.Allocator, tags: ?[][]const u8, zettels: []const Zettel) !void {
- if (tags == null) {
+ if (tags) |_| {
+ outer: for (zettels) |zet| {
+ for (zet.tags) |t| {
+ for (tags.?) |tag| {
+ if (std.ascii.eqlIgnoreCase(tag, t)) {
+ try zet.print();
+ continue :outer;
+ }
+ }
+ }
+ }
+ } else {
// List tags
var existing_tags = std.ArrayList([]const u8).init(allocator);
defer existing_tags.deinit();
@@ 27,16 38,5 @@ pub fn run(allocator: *std.mem.Allocator, tags: ?[][]const u8, zettels: []const
try stdout.print("{}\n", .{t});
}
}
- } else {
- outer: for (zettels) |zet| {
- for (zet.tags) |t| {
- for (tags.?) |tag| {
- if (std.ascii.eqlIgnoreCase(tag, t)) {
- try stdout.print("{} {}\n", .{ zet.id, zet.title });
- continue :outer;
- }
- }
- }
- }
}
}
M src/main.zig => src/main.zig +16 -1
@@ 32,7 32,22 @@ pub fn main() anyerror!void {
try std.process.changeCurDir(dir);
const command = arglist[1];
- const args: ?[][]const u8 = if (arglist.len > 2) arglist[2..] else null;
+ var args: ?[][]const u8 = if (arglist.len > 2) arglist[2..] else null;
+
+ // If first arg is a newline delimited string, split it into separate
+ // lines. This can happen when the result of one zet command is used as the
+ // argument to another zet command
+ if (args != null and std.mem.indexOf(u8, args.?[0], "\n") != null) {
+ var lines = std.ArrayList([]const u8).init(allocator);
+ defer lines.deinit();
+
+ var it = std.mem.split(args.?[0], "\n");
+ while (it.next()) |line| {
+ try lines.append(line);
+ }
+
+ args = lines.toOwnedSlice();
+ }
cmd.handleCommand(allocator, command, args) catch |err| return switch (err) {
error.UnknownCommand => {
M src/zettel.zig => src/zettel.zig +5 -0
@@ 1,4 1,5 @@
const std = @import("std");
+const stdout = std.io.getStdOut().outStream();
const stderr = std.io.getStdErr().outStream();
const c = @cImport(@cInclude("time.h"));
@@ 57,6 58,10 @@ pub const Zettel = struct {
self.allocator.free(self.title);
if (self.tags.len > 0) self.allocator.free(self.tags);
}
+
+ pub fn print(self: Zettel) !void {
+ try stdout.print("{} {}\n", .{ self.id, self.title });
+ }
};
pub fn getZettels(allocator: *std.mem.Allocator) !std.ArrayList(Zettel) {