diff options
| author | historia <gravel.justness270@slmail.me> | 2024-07-26 05:21:32 -0400 |
|---|---|---|
| committer | historia <gravel.justness270@slmail.me> | 2024-07-26 05:21:32 -0400 |
| commit | 9ba419479378a5e827f9e815a4faaf38983b1e13 (patch) | |
| tree | d32af1966f97c17f9662fb141c96685f98a77913 /src | |
| parent | 6d419844c18f2eb1f74a2b36c8e37071cde6a440 (diff) | |
| download | soon-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')
| -rw-r--r-- | src/then.nim | 123 |
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 |
