~bmp/hayom

ref: 4e35cc4390d56531be2256245eef737a3058b019 hayom/cli.ts -rw-r--r-- 2.9 KiB
4e35cc43Benjamin Pollack extract rendering logic 9 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { DateTime, parseDate } from "./deps.ts";
import { flags } from "./deps.ts";
import { loadConfig } from "./config.ts";
import {
  Entry,
  filterEntries,
  makeEntry,
  parseEntries,
  printEntry,
  saveEntries,
} from "./mod.ts";

function tryDate(d?: string): DateTime | undefined {
  return d ? DateTime.fromJSDate(parseDate(d)) : undefined;
}

function readEntries(entries: Entry[], opts: flags.Args) {
  let from = tryDate(opts.from);
  let to = tryDate(opts.to);
  if (opts.on) {
    const on = tryDate(opts.on);
    if (typeof on !== "object") {
      throw new Error("Bad date");
    }
    [from, to] = [on.startOf("day"), on.endOf("day")];
  }
  const tags = opts._.filter((arg) =>
    typeof arg === "string" && arg.match(/^@./)
  ) as string[];
  const limit = opts.limit;

  const filtered = filterEntries(
    entries,
    {
      from,
      to,
      limit,
      tags,
    },
  );
  let first = true;
  for (const entry of filtered) {
    if (!first && !opts.summary) {
      console.log();
    }
    first = false;
    printEntry(entry, opts.summary);
  }
}

async function edit(body: string, editor: string[]) {
  const temp = Deno.makeTempFileSync({ suffix: ".hayom" });
  try {
    Deno.writeTextFileSync(temp, body);
    const proc = Deno.run({ cmd: [...editor, temp] });
    const status = await proc.status();
    if (status.success) {
      return Deno.readTextFileSync(temp);
    }
  } finally {
    Deno.remove(temp);
  }
}

function printHelp() {
  console.log(`
usage: hayom [-j journal] ...
options:
   --summary | -s: print summary line only
   --from | -f:    from timestamp
   --to | -t:      to timestamp
   --on:           on timestamp
   --count | -n:   number of entries to print
   --journal | -j: journal to use
`);
}

async function main() {
  const args = [...Deno.args];
  const config = loadConfig();

  const opts = flags.parse(args, {
    boolean: ["summary"],
    alias: {
      "s": ["summary"],
      "f": ["from"],
      "t": ["to"],
      "n": ["count"],
      "j": ["journal"],
    },
  });

  if (opts.help) {
    printHelp();
    return;
  }

  const journal = opts.journal ?? config.default;
  const path = config.journals[journal].journal;

  try {
    Deno.lstatSync(path);
  } catch (e) {
    if (e instanceof Deno.errors.NotFound) {
      Deno.createSync(path).close();
    } else throw e;
  }

  const entries = parseEntries(Deno.readTextFileSync(path));

  if (
    ["from", "f", "to", "t", "on", "count", "n"].some((arg) => arg in opts) ||
    (opts._.length > 0 &&
      opts._.every((e) => typeof e === "string" && e[0] === "@"))
  ) {
    readEntries(entries, opts);
  } else {
    const rawEntry = opts._.length > 0
      ? opts._.join(" ")
      : await edit("", config.editor.split(/\s/));
    if (rawEntry && rawEntry.trim() !== "") {
      const entry = makeEntry(rawEntry);
      entries.push(entry);
      saveEntries(path, entries);
    }
  }
}

if (import.meta.main) {
  main();
}