From 2438fe0116bb4c8abafb4e236c148ba0f8290e6a Mon Sep 17 00:00:00 2001 From: historia Date: Fri, 26 Jul 2024 15:26:41 -0400 Subject: Changed condition data structure to Table --- src/then.nim | 130 ++++++++++++++++++++--------------------------------------- 1 file changed, 44 insertions(+), 86 deletions(-) (limited to 'src/then.nim') diff --git a/src/then.nim b/src/then.nim index be3e813..c7c1e61 100644 --- a/src/then.nim +++ b/src/then.nim @@ -1,4 +1,4 @@ -import std/[times, os, strutils, strbasics, strscans, sets, re, deques], parseopt +import std/[times, os, strutils, strbasics, strscans, sets, re, tables], parseopt const VERSION = "0.1" const configDir = expandTilde("~/.config/then/") @@ -53,9 +53,12 @@ proc printVersion() = echo "then " & VERSION quit() -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" +proc checkType(c: string): string = + var cond = c + if cond[0] == '!': + cond.delete(0..0) + if find(cond, re"^\d{4}$") > -1: return "year" + if find(cond, re"^\d{1,2}$") > -1: return "day" 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" @@ -87,93 +90,48 @@ proc checkCond(cond: string, day: DateTime): bool = echo "UNKNOWN THING ", cond return false -proc getConditions(dateStr: string): seq[string] = - var conditions: 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 +# Splits a string on whitespace, but maintains whitespace in date groups +proc splitWhitespaceExceptParens(str:string): seq[string] = + var result: seq[string] = newSeq[string]() + var inParens = false + for token in str.splitWhitespace: + if token.contains(')'): inParens = false + if inParens: + result.add(result.pop & ' ' & token) + else: + result.add(token) + if token.contains('('): inParens = true + return result + +proc parseDateToTable(date:string): Table[string,seq[string]] = + var table = initTable[string,seq[string]]() + let conditions = splitWhitespaceExceptParens(date) + for c in conditions: + let condType = checkType(c) + if not table.hasKey(condType): + table[condType] = @[] + table[condType].add(c) + return table proc getEvents(cal: seq[string], day: DateTime): seq[string] = - var events: seq[string] + var events: seq[string] = newSeq[string]() for line in cal: - var (success, dateStr, eventStr) = scanTuple(line, "$*,$*") + var (success, date, event) = scanTuple(line, "$*,$*") if success: - dateStr.strip - eventStr.strip - 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) + date.strip + event.strip + let conditions = parseDateToTable(date) + echo conditions + var match = true + #for c in conditions: + # var cond = c.toLower.capitalizeAscii + # if checkCond(cond, day) == false: + # match = false + # break + #if match: + # events.add(event) + # break else: echo "WARNING: Cannot parse line: ", line return events -- cgit v1.2.3