aboutsummaryrefslogtreecommitdiff
path: root/src/soon.nim
blob: 61ac16d553a03314e2ba689577402d85c85acb37 (plain)
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
import std/[os, strutils, strtabs, sequtils, osproc, parseopt]
import soon/[config, agenda, todos]

const VERSION = "0.1"

proc printHelp(badCmd: string) =
  if badCmd != "":
    echo badCmd & " is not a valid option\n"
  echo """
Usage: soon [options]

Options:
-a                 print agenda
-c                 print reference calendar
-t                 print todos
-d                 print deadlines
-e                 open default calendar file in $EDITOR
-i                 open TUI in interactive mode to schedule/archive events
-w, -m, -y         print agenda for upcoming week, month, or year
-j                 print the modified julian day
-i, --date         print today's date
-p, --past=DAYS    days in past to print agenda (default: 1)
-f, --future=DAYS  days in future to print agenda (default: 14)
-h, --help         show this help
-v, --version      print version

Check the docs at https://codeberg.org/historia/soon
  """
  quit()

proc printVersion() =
  echo "soon " & VERSION
  quit()

proc createDefaultCalendarFile(file: string) =
  if not fileExists(file):
    writeFile(file, "# This is your first calendar file. Put events and todos in here.")

proc getFileLines(file: string): seq[string] =
  let f = open(file)
  for line in f.lines:
    if line == "": continue
    if line.strip[0] == '#': continue
    result.add(line)
  f.close()

proc readAllSoonFiles(path: string): seq[string] =
  var soonFileExists = false
  for file in os.walkDirRec(path):
    if file.toLower().endsWith(".soon"):
      soonFileExists = true
      result = result.concat(getFileLines(file))
  if not soonFileExists:
    echo "No .soon files exist at " & path
    echo "Check your paths in ~/.config/soon/soon.conf"
    quit()

proc processCalendars(path: string, past: int, future: int) =
  var calendar = readAllSoonFiles(path)
  agenda.printAgenda(calendar, past, future)
  todos.printTodos(calendar)

proc parseArgs(config: StringTableRef): seq[string] =
  for kind, key, val in getopt():
    case kind
    of cmdEnd: break
    of cmdLongOption, cmdShortOption:
      case key
        of "past",    "p": config["past"] = val
        of "future",  "f": config["future"] = val
        of "help",    "h": printHelp("")
        of "version", "v": printVersion()
        else:
          result.add(key)
    of cmdArgument:
      printHelp(key)
  if result.len == 0:
    result.add("a")
    result.add("t")
    result.add("d")
    echo "I'm running soon -atd, but I should've checked the user config and run that!"

proc printReference() =
  discard execCmd("cal -3")

proc sanitize(str: string): string =
  result = ""
  for ch in str:
    if ch.isAlphaNumeric() or ch in {'/', '~', '.'}:
      result.add(ch)

proc openEditor(path: string, file: string) =
  var editor = getEnv("EDITOR").sanitize
  if editor.isEmptyOrWhitespace: editor = "vim"
  let sanePath = path.sanitize
  let saneFile = file.sanitize
  discard execCmd("$1 $2/$3" % [editor, sanePath, saneFile])

proc validateConfig(config: StringTableRef) =
  createDefaultCalendarFile(config["path"] / config["defaultFile"])

proc processCommands(commands: seq[string], conf: StringTableRef) =
  var calendar = readAllSoonFiles(conf["calendarPath"])
  var past = 0 - parseInt(conf["past"])
  var future = parseInt(conf["future"])
  for command in commands:
    case command
      of "a": agenda.printAgenda(calendar, past, future)
      of "w": agenda.printAgenda(calendar, 0, 7)
      of "m": agenda.printAgenda(calendar, 0, 28)
      of "y": agenda.printAgenda(calendar, 0, 365)
      of "t": todos.printTodos(calendar)
      of "d": todos.printDeadlineTodos(calendar)
      of "c": printReference()
      of "e": openEditor(conf["calendarPath"], conf["defaultFile"])

proc main() =
  var conf = config.loadConfig()
  let commands = parseArgs(conf)
  validateConfig(conf)
  processCommands(commands, conf)

when isMainModule:
  main()