aboutsummaryrefslogtreecommitdiff
path: root/src/then.nim
diff options
context:
space:
mode:
authorhistoria <gravel.justness270@slmail.me>2024-07-26 05:21:32 -0400
committerhistoria <gravel.justness270@slmail.me>2024-07-26 05:21:32 -0400
commit9ba419479378a5e827f9e815a4faaf38983b1e13 (patch)
treed32af1966f97c17f9662fb141c96685f98a77913 /src/then.nim
parent6d419844c18f2eb1f74a2b36c8e37071cde6a440 (diff)
downloadsoon-9ba419479378a5e827f9e815a4faaf38983b1e13.tar.gz
Removing < and > operators because they do not have much real world use. Replacing these with ranges indicated with a dash as documented in the README. Partially implemented a shunting yard algorithm to parse parentheses but will likely simplify this and remove support for parentheses outside of date groups. The complex example cases with parens aren't realistic.
Diffstat (limited to 'src/then.nim')
-rw-r--r--src/then.nim123
1 files changed, 104 insertions, 19 deletions
diff --git a/src/then.nim b/src/then.nim
index 67700a4..be3e813 100644
--- a/src/then.nim
+++ b/src/then.nim
@@ -1,15 +1,20 @@
-import std/[times, os, strutils, strbasics, strscans, sets], parseopt
+import std/[times, os, strutils, strbasics, strscans, sets, re, deques], parseopt
const VERSION = "0.1"
-const defaultConfigDir = expandTilde("~/.config/then/")
-const defaultConfigFile = defaultConfigDir & "then.toml"
-const defaultCalendarFile = defaultConfigDir & "calendar.then"
+const configDir = expandTilde("~/.config/then/")
+const defaultConfigFile = configDir & "then.toml"
+const defaultCalendarFile = configDir & "calendar.then"
+
+type
+ Token = object
+ token: string
+ precedence: int
# Creates a default configuration file if it doesn't exist
proc createDefaultConfigFile() =
if not fileExists(defaultConfigFile):
- if not dirExists(defaultConfigDir):
- createDir(defaultConfigDir)
+ if not dirExists(configDir):
+ createDir(configDir)
writeFile(defaultConfigFile, """
[config]
directory = "~/.config/then/"
@@ -18,10 +23,9 @@ proc createDefaultConfigFile() =
# Creates a default calendar file if it doesn't exist
proc createDefaultCalendarFile() =
if not fileExists(defaultCalendarFile):
- if not dirExists(defaultConfigDir):
- createDir(defaultConfigDir)
+ if not dirExists(configDir):
+ createDir(configDir)
writeFile(defaultCalendarFile, """
- # Default calendar file
# Add your events here
""")
@@ -52,7 +56,12 @@ proc printVersion() =
proc checkType(cond: string): string =
if cond.len == 4 and parseInt(cond) != 0: return "year"
if cond.len in [1, 2] and parseInt(cond) != 0: return "day"
- if cond in ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].toHashSet: return "month"
+ if cond in DefaultLocale.MMM.toHashSet or cond in DefaultLocale.MMMM.toHashSet: return "month"
+ if cond in DefaultLocale.ddd.toHashSet or cond in DefaultLocale.dddd.toHashSet: return "dayofweek"
+ if find(cond, re"\d{1,2}:\d{2}") > -1: return "time"
+ if find(cond, re"\dw") > -1: return "firstweek"
+ if find(cond, re"\dl") > -1: return "lastweek"
+ if find(cond, re"J%\d([-+]\d)?") > -1: return "julian"
return "unknown"
proc checkCond(cond: string, day: DateTime): bool =
@@ -65,6 +74,15 @@ proc checkCond(cond: string, day: DateTime): bool =
of "month":
if cond == day.format("MMM"): return true
if cond == day.format("MMMM"): return true
+ of "dayofweek":
+ if cond == day.format("ddd"): return true
+ if cond == day.format("dddd"): return true
+ of "time":
+ return true
+ of "firstweek":
+ discard
+# Uh oh we didn't think about this hard enough
+
of "unknown":
echo "UNKNOWN THING ", cond
return false
@@ -74,21 +92,88 @@ proc getConditions(dateStr: string): seq[string] =
conditions = dateStr.rsplit(' ')
return conditions
+# TODO simplify?? Would it be easier to identify conditions and replace them with TRUE/FALSE then just process the string?
+
+# Shunting yard to parse conditions, parens, and logical operators
+# Does NOT parse out individual conditions yet because some individual
+# conditions (like 1W) require context of surrounding conditions.
+# The logic around parentheses is a little weird because conditions like
+# "<(March 15)" contain parentheses that we don't want to throw out
+proc parseDateToEvents(dateStr: string): seq[string] =
+ var holdingStack = initDeque[Token]()
+ var resultStack = initDeque[Token]()
+ var newToken: string = ""
+ for c in dateStr:
+ echo c
+ case c:
+ of '(':
+ if newToken.len == 1:
+ if newToken[0] == '>' or newToken[0] == '<':
+ newToken.add(c)
+ else
+ echo "ERROR: newToken exists but we got an open paren?"
+ else:
+ holdingStack.addLast(Token(token: "(", precedence: 0))
+ of ')':
+ if newToken.len > 0: # Closing token like <(March 15). Push the token.
+ resultStack.addLast(Token(token: newToken, precedence: 0))
+ newToken = ""
+ else: # Logical closing paren. Pop stack until (.
+ while holdingStack.len > 0 and holdingStack.peekLast.token != "(":
+ if holdingStack.len == 0:
+ echo "UH OH, ERROR MISMATCHED PARENS"
+ resultStack.addLast(holdingStack.popLast)
+ discard holdingStack.popLast # Pop the (
+ of '!':
+ holdingStack.addLast(Token(token: "!", precedence: 3))
+ of '|':
+ while holdingStack.len > 0 and holdingStack.peekLast.precedence > 2:
+ resultStack.addLast(holdingStack.popLast)
+ holdingStack.addLast(Token(token: "|", precedence: 2))
+ of ' ':
+ if newToken.len > 1 and newToken[1] == '(' and newToken[newToken.len-1] != ')': # Middle of token like <(March 15).
+ newToken.add(c)
+ else: # End of new token, implicit &
+ # Add newToken to result
+ resultStack.addLast(Token(token: newToken, precedence: 0))
+ newToken = ""
+ # Add implicit & to holding
+ while holdingStack.len > 0 and holdingStack.peekLast.precedence > 1:
+ resultStack.addLast(holdingStack.popLast)
+ holdingStack.addLast(Token(token:"&", precedence: 1))
+ of '>','<',':','-','a'..'z','A'..'Z','0'..'9':
+ newToken.add(c)
+ else:
+ echo "Weird character in dateStr: ", c
+ discard
+ # Push last token
+ if newToken.len > 0:
+ resultStack.addLast(Token(token: newToken, precedence: 0))
+ # Clear the holding stack
+ while holdingStack.len > 0:
+ var t = holdingStack.popLast
+ if t.token != "(":
+ resultStack.addLast(t)
+ echo resultStack
+
+
proc getEvents(cal: seq[string], day: DateTime): seq[string] =
var events: seq[string]
for line in cal:
- var (success, dateStr, eventStr) = scanTuple(line, "$+,$*")
+ var (success, dateStr, eventStr) = scanTuple(line, "$*,$*")
if success:
dateStr.strip
eventStr.strip
- let conditions = getConditions(dateStr)
- var match = true
- for c in conditions:
- if checkCond(c, day) == false:
- match = false
- break
- if match:
- events.add(eventStr)
+ discard parseDateToEvents(dateStr)
+ #let conditions = getConditions(dateStr)
+ # var match = true
+ # for c in conditions:
+ # c = c.toLower.capitalizeAscii
+ # if checkCond(c, day) == false:
+ # match = false
+ # break
+ # if match:
+ # events.add(eventStr)
else:
echo "WARNING: Cannot parse line: ", line
return events