aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhistoria <gravel.justness270@slmail.me>2024-08-09 02:52:41 -0400
committerhistoria <gravel.justness270@slmail.me>2024-08-09 02:52:41 -0400
commit8e3a4ecb66f30bbb8cd57cbf1b51235ef8b54d82 (patch)
tree49fc251e40f2491fb8a2f072c12f4d085889917a
parentedd24af0a7b79f418356d6a0c45d2ee23e3325df (diff)
downloadsoon-8e3a4ecb66f30bbb8cd57cbf1b51235ef8b54d82.tar.gz
Feature: Attachments ('+') for events
-rw-r--r--README.md27
-rw-r--r--src/soon.nim68
2 files changed, 50 insertions, 45 deletions
diff --git a/README.md b/README.md
index 724462f..b942099 100644
--- a/README.md
+++ b/README.md
@@ -14,15 +14,13 @@ In terms of features and complexity, Soon lies between [When](https://www.lighta
# Quick Start
-1. Download Soon and copy it into you PATH (e.g. /usr/local/bin)
+1. Run `soon -e`. This will generate a config and calendar file under $XDG_CONFIG_HOME/soon and open the calendar file in your editor.
-2. Run `soon -e`. This will generate a config and calendar file under $XDG_CONFIG_HOME/soon and open the calendar file in your editor.
+2. Check the example calendar and add some events/todos. You can just add `J%2, Hello World` for an event that repeats every other day if you want to quickly see how it looks.
-3. Check the example calendar and add some events/todos. You can just add `J%2, Hello World` for an event that repeats every other day if you want to quickly see how it looks.
+3. Run `soon` to see your agenda. With no options it will show you the next 14 days of events as well as your todos and deadlines.
-4. Run `soon` to see your agenda. With no options it will show you the next 14 days of events as well as your todos and deadlines.
-
-5. Run `soon -i` to start interactive mode and archive events or todos. Select events/todos with HJKL and archive them with Space. Esc to exit.
+4. Run `soon -i` to start interactive mode and archive events or todos. Select events/todos with HJKL and archive them with Space. Esc to exit.
# Example Calendar
@@ -41,11 +39,17 @@ Fri !13, Every Friday except the 13th
# Ranges
(Jul 7 2024)-(Jul 13 2024), Shark Week
July 7-13 2024, Shark Week
+Mon-Fri 9am-5pm, What a way to make a living
# Uncommon recurrence patterns
J%3, Every third day (See: Advanced Recurrence)
Fri 1W, First Friday of the month
+# Add details to the above event with +
+2025 Aug 1, Doctor's Appointment
++ Address: 123 Oak Street, Woodsville
++ Phone: +1 555-555-5555
+
# Todos start with a hyphen
- Buy milk
- Read War and Peace
@@ -147,7 +151,7 @@ Any line starting with a `+` is attached to the nearest above event. This can be
## Advanced Recurrence (Modified Julian Day `J%x+y`)
-Soon supports using a Modified Julian Day as `J`. `J` is the number of full days since midnight November 17, 1858. This can be used along with the modulo operator `%` to create complex recurring events.
+Soon supports using a Modified Julian Day as `J`. `J` is the number of full days since midnight November 17, 1858. Combined with the modulo operator `%` and an optional `+`/`-` offset this creates complex recurring events.
This condition returns **true** when the result is 0 (This is the opposite of how When works).
@@ -184,15 +188,12 @@ Attach a line with `+ Due: DATE` and it will show up in a list of upcoming deadl
+ Due: Aug 7 2025
```
-You can delete finished todos from `then i` or just from your text editor.
+You can delete finished todos from `soon i` or just from your text editor.
# Archive File
-You can archive events in interactive mode with `soon i`. This lets you archive an event like "Pay rent" early so you know it's done.
+You can archive events in interactive mode with `soon -i`. This lets you archive an event like "Pay rent" early so you know it's done. The default behavior is to delete the event from your calendar file when the last instance of the event is archived.
-- For recurring events with no end date, only the individual instance is archived.
-- For events with one date, the event is removed from your calendar file.
-- For events with an end date, it will only be removed from your calendar file if all occurences are archived.
`showPastArchivedEvents` and `showFutureArchivedEvents` determine if archived events are hidden from your agenda entirely or show up as (Archived).
@@ -216,7 +217,7 @@ Soon is a [When](https://www.lightandmatter.com/when/when.html) alternative with
3. You can optionally keep events on the agenda until manually archived. This mimics the behavior of keeping overdue calendar reminders in your email inbox.
-4. Zero nonsense todos with upcoming deadlines.
+4. Todos with upcoming deadlines and nothing else. It's just a list in a text file.
# Alternatives
diff --git a/src/soon.nim b/src/soon.nim
index 0850bd6..d154846 100644
--- a/src/soon.nim
+++ b/src/soon.nim
@@ -56,7 +56,7 @@ proc splitWhitespaceExceptParens(str:string): seq[string] =
return output
# Returns Table[conditionType, seq of conditions]
-proc parseDateToTable(date:string): Table[string,seq[string]] =
+proc parseDateToTable(date:string): Table[string, seq[string]] =
var table = initTable[string,seq[string]]()
let conditions = splitWhitespaceExceptParens(date)
for c in conditions:
@@ -66,47 +66,49 @@ proc parseDateToTable(date:string): Table[string,seq[string]] =
table[condType].add(c)
return table
-
-proc getEvents(cal: seq[string], date: DateTime): seq[string] =
- var events: seq[string] = newSeq[string]()
+proc checkAllConditions(dateConditions: string, date: DateTime): bool =
+ let conditions = parseDateToTable(dateConditions.strip)
+ for k,cs in conditions:
+ var keyMatched = false
+ for c in cs:
+ if checkCond(c, date) == true:
+ keyMatched = true
+ break
+ if not keyMatched:
+ return false
+ return true
+
+# Returns Table[eventName, eventAttachedLines]
+proc getEventsForDate(cal: seq[string], date: DateTime): Table[string, seq[string]] =
+ var lastInsertion = ""
for line in cal:
var (success, dateConditions, event) = scanTuple(line, "$*,$*")
if success:
- dateConditions.strip
- event.strip
- let conditions = parseDateToTable(dateConditions)
- var match = true
- # key = Condition Type (e.g. month), cs = Seq of conditions
- for k,cs in conditions:
- var keyMatched = false
- for c in cs:
- if checkCond(c, date) == true:
- keyMatched = true
- break
- if not keyMatched:
- match = false
- break
- if match:
- events.add(event)
+ if checkAllConditions(dateConditions, date) == true:
+ event.strip
+ result[event] = @[]
+ lastInsertion = event
+ elif line.strip[0] == '+':
+ if result.hasKey(lastInsertion):
+ result[lastInsertion].add(line)
else:
echo "WARNING: Cannot parse line: ", line
- return events
proc printEvents(cal: seq[string], date: DateTime, format: string) =
- let events = getEvents(cal, date)
+ let events = getEventsForDate(cal, date)
if events.len > 0:
- for e in events:
+ for e in events.keys:
echo date.format(format), " ", e
+ for attachment in events[e]:
+ echo attachment.indent(date.format(format).len + 2)
-proc printCalendar(calendar: seq[string], config: StringTableRef) =
- let past = 0 - parseInt(config["past"])
- let future = parseInt(config["future"])
+proc printAgenda(calendar: seq[string], past: int, future: int) =
let now = now()
for i in past..future:
let curDay = now + i.days
printEvents(calendar, curDay, "ddd yyyy MMM dd")
-proc openCalendar(file: string): seq[string] =
+proc getCalendarFileLines(file: string): seq[string] =
let f = open(file)
for line in f.lines:
if line == "": continue
@@ -114,12 +116,12 @@ proc openCalendar(file: string): seq[string] =
result.add(line)
f.close()
-proc processCalendars(config: StringTableRef) =
+proc processCalendars(calendarPath: string, past: int, future: int) =
var calendar = newSeq[string]()
- for file in os.walkDirRec(config["calendarPath"]):
+ for file in os.walkDirRec(calendarPath):
if file.toLower().endsWith(".soon"):
- calendar = calendar.concat(openCalendar(file))
- printCalendar(calendar, config)
+ calendar = calendar.concat(getCalendarFileLines(file))
+ printAgenda(calendar, past, future)
proc parseArgs(config: StringTableRef): seq[string] =
for kind, key, val in getopt():
@@ -143,7 +145,9 @@ proc main() =
var conf = config.loadConfig()
let commands = parseArgs(conf)
validateConfig(conf)
- processCalendars(conf)
+ let past = 0 - parseInt(conf["past"])
+ let future = parseInt(conf["future"])
+ processCalendars(conf["calendarPath"], past, future)
when isMainModule:
main()