aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd.ha151
-rw-r--r--hatask.ha38
2 files changed, 137 insertions, 52 deletions
diff --git a/cmd.ha b/cmd.ha
index ff37c79..dd267b3 100644
--- a/cmd.ha
+++ b/cmd.ha
@@ -6,101 +6,162 @@ use io;
use path;
use os::exec;
use strconv;
+use ascii;
-type error = !(io::error | path::error | exec::error);
+type error = !(!str | io::error | path::error | exec::error | strconv::error);
-type func = fn(tasks: []task, args: str...) (void | task | error);
+type func = fn(tasks: []task, args: arguments) (void | task | error);
type command = struct {
names: []str,
+ help: []getopt::help,
func: *func,
};
+type arguments = *getopt::command;
+
const PADDING: size = 30z;
const commands: [_]command = [
command {
names = ["f", "filter"],
+ help = ["<name>"],
func = &filter,
},
command {
names = ["s", "show"],
+ help = ["<id>"],
func = &show,
},
command {
names = ["w", "write"],
+ help = ["<id>"],
func = &write,
},
];
-fn execcommand(name: str, tasks: []task, args: str...) (void | error) = {
+fn execcommand(name: str, tasks: []task, args: arguments) (void | error) = {
for (const c .. commands) {
for (const n .. c.names) {
if (n == name) {
- c.func(tasks, args...)?;
+ 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);
-
+fn write(tasks: []task, a: arguments) (void | task | error) = {
+ const args = a.args;
if (len(args) != 1z) {
- getopt::printhelp(os::stderr, cmdname, cmdhelp)?;
+ getopt::printhelp(os::stderr, "write", a.help)?;
return;
};
- let buf = path::init()?;
- const p = path::push(&buf, "tasks", args[0])?;
- const c = exec::cmd("vim", p)?;
+ const id = strconv::stoz(args[0])?;
+ const t = if (len(tasks) > id) {
+ yield tasks[id];
+ } else {
+ return "No such task";
+ };
+ const c = exec::cmd("vim", t.path)?;
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 show(tasks: []task, a: arguments) (void | task | error) = {
+ const args = a.args;
+ const id = strconv::stoz(args[0])?;
+ const t = if (len(tasks) > id) {
+ yield tasks[id];
+ } else {
+ return "No such task";
};
+ 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 printtask(t: task, id: size) (void | error) = {
+ let name = strings::dup(t.name);
+ defer free(name);
+ if (len(t.name) > PADDING - 4) {
+ name = strings::concat(strings::sub(t.name, 0z, PADDING - 4),
+ "...");
+ };
+ const pad = PADDING - len(name) + len(strconv::utos(t.priority));
+ const namepad = 10 - len(strconv::ztos(id)) + len(name);
+ fmt::printfln("{}{%}{%}", id, name, &fmt::mods {
+ pad = ' ',
+ width = namepad,
+ ...
+ },
+ t.priority, &fmt::mods {
+ pad = ' ',
+ width = pad,
+ ...
+ },
+ )!;
};
-fn filter(tasks: []task, args: str...) (void | task | error) = {
+fn filter(tasks: []task, a: arguments) (void | task | error) = {
const headpad = PADDING - len("name") + len("priority");
- fmt::printfln("name{%}", "priority", &fmt::mods {
- pad = ' ',
- width = headpad,
- ...
- })!;
- for (const t .. tasks) {
+ const namepad = 10 - len("id") + len("name");
+ fmt::printfln("id{%}{%}",
+ "name", &fmt::mods {
+ pad = ' ',
+ width = namepad,
+ ...
+ },"priority", &fmt::mods {
+ pad = ' ',
+ width = headpad,
+ ...
+ },
+ )!;
+ const args = a.args;
+ for (let i = 0z; i < len(tasks); i += 1) {
+ const t = tasks[i];
if (len(args) == 0z) {
- printtask(t)?;
+ printtask(t, i)?;
};
for (const s .. args) {
- if (strings::contains(t.name, s)) {
- printtask(t)?;
+ const lname = ascii::strlower(t.name);
+ defer free(lname);
+ const ls = ascii::strlower(s);
+ defer free(ls);
+ if (strings::contains(lname, ls)) {
+ printtask(t, i)?;
};
};
};
};
+
+fn listall(tasks: []task) void = {
+ const headpad = PADDING - len("name") + len("priority");
+ const namepad = 10 - len("id") + len("name");
+ fmt::printfln("id{%}{%}",
+ "name", &fmt::mods {
+ pad = ' ',
+ width = namepad,
+ ...
+ },"priority", &fmt::mods {
+ pad = ' ',
+ width = headpad,
+ ...
+ },
+ )!;
+ for (let i = 0z; i < len(tasks); i += 1) {
+ printtask(tasks[i], i)!;
+ };
+};
+
+fn strerror(e: error) str = {
+ match (e) {
+ case let e: !str =>
+ return e;
+ case let e: io::error =>
+ return io::strerror(e);
+ case let e: path::error =>
+ return path::strerror(e);
+ case let e: exec::error =>
+ return exec::strerror(e);
+ case let e: strconv::error =>
+ return strconv::strerror(e);
+ };
+};
diff --git a/hatask.ha b/hatask.ha
index 3984165..c15f2a0 100644
--- a/hatask.ha
+++ b/hatask.ha
@@ -11,9 +11,11 @@ use format::ini;
use strconv;
use encoding::utf8;
use getopt;
+use sort;
type task = struct {
name: str,
+ path: str,
context: (str | void),
tags: ([]str | void),
priority: uint,
@@ -88,12 +90,14 @@ fn readtask(taskpath: str) (task | rtaskerror) = {
if (t.name == "") {
t.name = strings::dup(path::basename(taskpath));
};
+ t.path = strings::dup(taskpath);
t.content = strings::dup(strings::trim(memio::string(&content)?));
return t;
};
fn freetask(t: *task) void = {
free(t.name);
+ free(t.path);
free(t.content);
if (t.context is str) {
free(t.context as str);
@@ -109,18 +113,24 @@ fn finishall(tasks: []task) void = {
};
};
+fn sortname(a: const *opaque, b: const *opaque) int = {
+ const a = a: *task;
+ const b = b: *task;
+ return strings::compare(a.name, b.name);
+};
+
export fn main() void = {
const cmd = getopt::parse(os::args,
"tasklist",
- "cmd",
+ ("filter", ["filter tasks", "id"]: []getopt::help),
+ ("f", ["filter tasks", "id"]: []getopt::help),
+ ("show", ["show task details", "id"]: []getopt::help),
+ ("s", ["show task details", "id"]: []getopt::help),
+ ("write", ["write a task", "id"]: []getopt::help),
+ ("w", ["write a task", "id"]: []getopt::help),
);
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 =>
@@ -130,7 +140,21 @@ export fn main() void = {
case let tasks: []task =>
yield tasks;
};
+ sort::sort(tasks: []opaque, size(task), &sortname);
defer finishall(tasks);
- execcommand(com[0], tasks, com[1..]...)!;
+ const com: (str, *getopt::command) = match (cmd.subcmd) {
+ case void =>
+ listall(tasks);
+ return;
+ case let subcmd: (str, *getopt::command) =>
+ yield (subcmd.0, subcmd.1);
+ };
+
+ match (execcommand(com.0, tasks, com.1)) {
+ case let e: error =>
+ fmt::fatal(strerror(e));
+ case =>
+ void;
+ };
};