aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd.ha106
-rw-r--r--hatask.ha50
2 files changed, 146 insertions, 10 deletions
diff --git a/cmd.ha b/cmd.ha
new file mode 100644
index 0000000..ff37c79
--- /dev/null
+++ b/cmd.ha
@@ -0,0 +1,106 @@
+use fmt;
+use strings;
+use getopt;
+use os;
+use io;
+use path;
+use os::exec;
+use strconv;
+
+type error = !(io::error | path::error | exec::error);
+
+type func = fn(tasks: []task, args: str...) (void | task | error);
+
+type command = struct {
+ names: []str,
+ func: *func,
+};
+
+const PADDING: size = 30z;
+
+const commands: [_]command = [
+ command {
+ names = ["f", "filter"],
+ func = &filter,
+ },
+ command {
+ names = ["s", "show"],
+ func = &show,
+ },
+ command {
+ names = ["w", "write"],
+ func = &write,
+ },
+];
+
+fn execcommand(name: str, tasks: []task, args: str...) (void | error) = {
+ for (const c .. commands) {
+ for (const n .. c.names) {
+ if (n == name) {
+ c.func(tasks, args...)?;
+ };
+ };
+ };
+};
+
+fn write(tasks: []task, args: str...) (void | task | error) = {
+ const cmdname = "task write";
+ const cmdhelp: []getopt::help = ["write a task", "<name>"];
+ if (len(args) == 0z) {
+ getopt::printhelp(os::stderr, cmdname, cmdhelp)?;
+ return;
+ };
+ const cmd = getopt::parse(args,
+ cmdname: getopt::help,
+ cmdhelp[0],
+ cmdhelp[1],
+ );
+ defer getopt::finish(&cmd);
+
+ if (len(args) != 1z) {
+ getopt::printhelp(os::stderr, cmdname, cmdhelp)?;
+ return;
+ };
+
+ let buf = path::init()?;
+ const p = path::push(&buf, "tasks", args[0])?;
+ const c = exec::cmd("vim", p)?;
+ exec::exec(&c);
+};
+
+fn show(tasks: []task, args: str...) (void | task | error) = {
+ for (const t .. tasks) {
+ for (const s .. args) {
+ if (t.name == s) {
+ fmt::println(t.content)!;
+ };
+ };
+ };
+};
+
+fn printtask(t: task) (void | error) = {
+ const pad = PADDING - len(t.name) + len(strconv::utos(t.priority));
+ fmt::printfln("{}{%}", t.name, t.priority, &fmt::mods {
+ pad = ' ',
+ width = pad, ...
+ })!;
+};
+
+fn filter(tasks: []task, args: str...) (void | task | error) = {
+ const headpad = PADDING - len("name") + len("priority");
+ fmt::printfln("name{%}", "priority", &fmt::mods {
+ pad = ' ',
+ width = headpad,
+ ...
+ })!;
+ for (const t .. tasks) {
+ if (len(args) == 0z) {
+ printtask(t)?;
+ };
+ for (const s .. args) {
+ if (strings::contains(t.name, s)) {
+ printtask(t)?;
+ };
+ };
+ };
+};
diff --git a/hatask.ha b/hatask.ha
index 291f17e..3984165 100644
--- a/hatask.ha
+++ b/hatask.ha
@@ -10,12 +10,14 @@ use strings;
use format::ini;
use strconv;
use encoding::utf8;
+use getopt;
type task = struct {
name: str,
context: (str | void),
tags: ([]str | void),
priority: uint,
+ content: str,
};
def METADATASEP: str = "----";
@@ -35,12 +37,10 @@ fn listtasks(root: str = "tasks", context: str = "*") ([]task | rtaskerror |
const p = path::push(&buf, root, dirent.name)?;
listtasks(p)?;
} else {
- fmt::println(dirent.name)!;
let buf = path::init()?;
const p = path::push(&buf, root, dirent.name)?;
let t = readtask(p)?;
- defer freetask(&t);
- fmt::println(t.name)!;
+ append(tasks, t);
};
};
};
@@ -52,15 +52,19 @@ fn readtask(taskpath: str) (task | rtaskerror) = {
defer io::close(f)!;
const sc = bufio::newscanner(f);
defer bufio::finish(&sc);
+ const content = memio::dynamic();
+ defer io::close(&content)!;
const meta = memio::dynamic();
defer io::close(&meta)!;
+
+ let currentst = &meta;
for (let line => bufio::scan_line(&sc)?) {
line = strings::trim(line);
if (line == METADATASEP) {
- break;
+ currentst = &content;
+ continue;
};
- memio::concat(&meta, line, "\n")?;
- //append(inilines, strings::dup(line));
+ memio::concat(currentst, line, "\n")?;
};
// seek to start of memio buffer
io::seek(&meta, 0, io::whence::SET)?;
@@ -74,18 +78,23 @@ fn readtask(taskpath: str) (task | rtaskerror) = {
for (let entry: ini::entry => ini::next(&sc)?) {
switch (entry.1) {
case "name" =>
- t.name = strings::dup(entry.2);
+ t.name = strings::dup(strings::trim(entry.2));
case "priority" =>
t.priority = strconv::stou(entry.2)?;
case =>
void;
};
};
+ if (t.name == "") {
+ t.name = strings::dup(path::basename(taskpath));
+ };
+ t.content = strings::dup(strings::trim(memio::string(&content)?));
return t;
};
fn freetask(t: *task) void = {
free(t.name);
+ free(t.content);
if (t.context is str) {
free(t.context as str);
};
@@ -94,13 +103,34 @@ fn freetask(t: *task) void = {
};
};
+fn finishall(tasks: []task) void = {
+ for (const task .. tasks) {
+ freetask(&task);
+ };
+};
+
export fn main() void = {
- match (listtasks()) {
+ const cmd = getopt::parse(os::args,
+ "tasklist",
+ "cmd",
+ );
+ defer getopt::finish(&cmd);
+
+ const com: []str = if (len(cmd.args) > 0) {
+ yield cmd.args;
+ } else {
+ yield ["filter"];
+ };
+
+ const tasks = match (listtasks()) {
case let e: fs::error =>
fmt::fatal(fs::strerror(e));
case let e: path::error =>
fmt::fatal(path::strerror(e));
- case =>
- void;
+ case let tasks: []task =>
+ yield tasks;
};
+ defer finishall(tasks);
+
+ execcommand(com[0], tasks, com[1..]...)!;
};