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 (using 'cal') -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()