aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhistoria <gravel.justness270@slmail.me>2024-08-16 23:52:17 -0400
committerhistoria <gravel.justness270@slmail.me>2024-08-16 23:52:17 -0400
commita31cf66d9400059752a2c480bac132960383a8d9 (patch)
tree99073a9056263b5ceb5d3ec5f7577ca6667766ff /src
parente5c80a22c35a5745ae957b8e84da42abd0c41d4d (diff)
downloadsoon-a31cf66d9400059752a2c480bac132960383a8d9.tar.gz
feat: parsing times to sort events works besides ugly edge cases
Diffstat (limited to 'src')
-rw-r--r--src/soon.nim12
-rw-r--r--src/soon/agenda.nim52
-rw-r--r--src/soon/parsetime.nim59
-rw-r--r--src/soon/typechecker.nim6
4 files changed, 105 insertions, 24 deletions
diff --git a/src/soon.nim b/src/soon.nim
index cede38c..2c5f109 100644
--- a/src/soon.nim
+++ b/src/soon.nim
@@ -35,7 +35,7 @@ proc createDefaultCalendarFile(file: string) =
if not fileExists(file):
writeFile(file, "# This is your first calendar file. Put events and todos in here.")
-proc getCalendarFileLines(file: string): seq[string] =
+proc getFileLines(file: string): seq[string] =
let f = open(file)
for line in f.lines:
if line == "": continue
@@ -43,11 +43,13 @@ proc getCalendarFileLines(file: string): seq[string] =
result.add(line)
f.close()
-proc processCalendars(calendarPath: string, past: int, future: int) =
- var calendar = newSeq[string]()
- for file in os.walkDirRec(calendarPath):
+proc readAllSoonFiles(path: string): seq[string] =
+ for file in os.walkDirRec(path):
if file.toLower().endsWith(".soon"):
- calendar = calendar.concat(getCalendarFileLines(file))
+ result = result.concat(getFileLines(file))
+
+proc processCalendars(path: string, past: int, future: int) =
+ var calendar = readAllSoonFiles(path)
agenda.printAgenda(calendar, past, future)
todos.printTodos(calendar)
diff --git a/src/soon/agenda.nim b/src/soon/agenda.nim
index 4288f0a..59bbe12 100644
--- a/src/soon/agenda.nim
+++ b/src/soon/agenda.nim
@@ -1,5 +1,10 @@
-import std/[times, strutils, strbasics, strscans, tables]
-import conditionchecker, typechecker
+import std/[times, strutils, strbasics, strscans, tables, algorithm, re]
+import conditionchecker, typechecker, parsetime
+
+type Event = tuple
+ name: string
+ time: DateTime
+ attachments: seq[string]
# Splits a string on whitespace, but maintains whitespace in date groups
proc splitWhitespaceExceptParens(str:string): seq[string] =
@@ -26,8 +31,7 @@ proc parseDateToTable(date:string): Table[string, seq[string]] =
table[condType].add(c)
return table
-proc allConditionsMet(dateConditions: string, date: DateTime): bool =
- let conditions = parseDateToTable(dateConditions.strip)
+proc allConditionsMet(conditions: Table[string,seq[string]], date: DateTime): bool =
if conditions.hasKey("unknown"): return false
for k,cs in conditions:
var keyMatched = false
@@ -39,30 +43,48 @@ proc allConditionsMet(dateConditions: string, date: DateTime): bool =
return false
return true
+#proc formatTime(time: string): DateTime =
+# let (start, end) = time.split("-", maxsplit = 1)
+# var matches: array[1, string]
+# discard find(condition, re"0?(\d{1,2})(:)?(\d{2})?([AaPp][Mm])?(\-(\d{1,2})(:)?(\d{2})?([AaPp][Mm])?)?", matches)
+
+
# Returns Table[event, attachments]
-proc getEventsForDate(cal: seq[string], date: DateTime): Table[string, seq[string]] =
+proc getEventsForDate(cal: seq[string], date: DateTime): seq[Event] =
var lastInsertion = ""
for line in cal:
var (success, dateConditions, event) = scanTuple(line, "$*,$*")
if success:
- if allConditionsMet(dateConditions, date):
+ dateConditions.strip
+ let conditions = parseDateToTable(dateConditions)
+ if allConditionsMet(conditions, date):
event.strip
- result[event] = @[]
+ if conditions.hasKey("time"):
+ echo conditions["time"]
+ #echo formatTime(conditions["time"])
+ result.add((event, now(), @[]))
lastInsertion = event
elif line.strip[0] == '+':
- if result.hasKey(lastInsertion):
- result[lastInsertion].add(line)
+ if result[result.high].name == lastInsertion:
+ result[result.high].attachments.add(line)
elif line[0..1] == "- ":
lastInsertion = ""
else:
echo "WARNING: Cannot parse line: ", line
-proc printEvents(cal: seq[string], date: DateTime, format: string) =
- let events = getEventsForDate(cal, date)
+#proc sortTable(t: Table[string, seq[string]]) =
+# for
+
+# Check nim-lang algorithm basic usage
+proc compare(a, b: string): int =
+ cmp(a.len, b.len)
+
+proc printDaysEvents(cal: seq[string], date: DateTime, format: string) =
+ var events = getEventsForDate(cal, date)
if events.len > 0:
- for e in events.keys:
- echo date.format(format), " ", e
- for attachment in events[e]:
+ for event in events:
+ echo date.format(format), " ", event.name
+ for attachment in event.attachments:
let space = date.format(format).len + 2
echo attachment.indent(space)
@@ -71,4 +93,4 @@ proc printAgenda*(calendar: seq[string], past: int, future: int) =
var today = dateTime(now.year, now.month, now.monthday, 00, 00, 00, 00, local())
for i in past..future:
let curDay = today + i.days
- printEvents(calendar, curDay, "ddd yyyy MMM dd")
+ printDaysEvents(calendar, curDay, "ddd yyyy MMM dd")
diff --git a/src/soon/parsetime.nim b/src/soon/parsetime.nim
new file mode 100644
index 0000000..5cfa245
--- /dev/null
+++ b/src/soon/parsetime.nim
@@ -0,0 +1,59 @@
+import strutils, tables, re, times
+
+proc flipAmPm(s : string): string =
+ case s
+ of "am": return "pm"
+ of "pm": return "am"
+ else: return "am"
+
+proc fixTwelveAm(hour: int, meridiem: string): int =
+ if hour == 12 and meridiem == "am":
+ return 0
+ if hour == 24:
+ return 0
+ return hour
+
+# Returns (hour, minute, meridium)
+proc parseString(t: string): (int, int, string) =
+ var matches: array[3, string]
+ discard find(t, re"^(\d{1,2}):?(\d{2})?([PpAa][Mm])?", matches)
+ var
+ hour = parseInt(matches[0])
+ minute = 0
+ meridiem = matches[2]
+ if matches[1] != "": minute = parseInt(matches[1])
+ hour = fixTwelveAm(hour, meridiem)
+ if hour > 12:
+ hour = hour - 12
+ meridiem = "pm"
+ return (hour, minute, meridiem)
+
+proc getMeridiem(startHour: int, startMin: int, endTime: string): string =
+# Determine meridium of the left hand side of a time range when it isn't specified
+ var (endHour, endMinute, endMeridiem) = parseString(endTime)
+ if (startHour < endHour and endHour == 12):
+ return "am"
+ if (startHour < endHour) or (startHour == endHour and startMin < endMinute):
+ return endMeridiem
+ elif startHour > endHour:
+ return flipAmPm(endMeridiem)
+
+proc timeToStr(time: int): string =
+ result = intToStr(time)
+ if result.len == 1:
+ result = "0" & result
+
+proc toDateTime*(time: string): DateTime =
+# Returns a DateTime for any time string like 9am. 09:00, or 9-10pm
+ let splitTime = time.split("-", maxsplit = 1)
+ let startTime = splitTime[0]
+ var (hour, minute, meridiem) = parseString(startTime)
+ if meridiem == "" and splitTime.len > 1:
+ meridiem = getMeridiem(hour, minute, splitTime[1])
+ var sHour = timeToStr(hour)
+ var sMin = timeToStr(minute)
+ result = parse(sHour & sMin, "HHmm", utc())
+ if meridiem == "pm" and hour <= 12:
+ result = result + 12.hours
+ if result.monthday == 2:
+ result = result - 1.days
diff --git a/src/soon/typechecker.nim b/src/soon/typechecker.nim
index 34e5723..0163c9f 100644
--- a/src/soon/typechecker.nim
+++ b/src/soon/typechecker.nim
@@ -32,11 +32,9 @@ proc checkType*(c: string): string =
if find(cond, re"^\([A-Za-z0-9 ]+\)$") > -1: return "dategroup"
if find(cond, re"^\d{4}-\d{4}$") > -1: return "rangeyear"
if find(cond, re"^\d{1,2}-\d{1,2}$") > -1: return "rangeday"
- if find(cond, re"^\d{1,2}:\d{2}(-\d{1,2}:\d{2})?$") > -1: return "time"
- if find(cond, re"^\d{1,2}(:\d{2})?[AaPp]\.?[Mm](-\d{1,2}(:\d{2})?[AaPp]\.?[Mm])?") > -1: return "time"
- if find(cond, re"^\(?\s*[Jj]\s*%\s*\d+\s*([-+]\s*\d+)?\s*\)?$") > -1: return "julian"
+ if find(cond, re"^\(?\s*[Jj]\s*%\s*\d+\s*([-+]\s*\d+)?\s*\)?$") > -1: return "julian"
+ if find(cond, re"^\d{1,2}(:\d{2})?([AaPp][Mm])?(-\d{1,2}(:\d{2})?)?([AaPp][Mm])?$") > -1: return "time"
cond = cond.toLower.capitalizeAscii
if cond in MONTHS: return "month"
if cond in WEEKDAYS: return "weekday"
-
return checkForRanges(cond)