From 759d00e2f8abbec5ff6eb8e82dd0e30c0b12bb6b Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Wed, 19 Nov 2025 17:10:14 -0600 Subject: [PATCH] Move filter logic earlier in CLI processing, support state filtering. --- src/pit.nim | 97 +++++++++++++++++++++++++--------------------- src/pit/libpit.nim | 16 +++++++- 2 files changed, 68 insertions(+), 45 deletions(-) diff --git a/src/pit.nim b/src/pit.nim index 730bcb2..00862da 100644 --- a/src/pit.nim +++ b/src/pit.nim @@ -31,6 +31,7 @@ proc parseExclPropertiesOption(propsOpt: string): TableRef[string, seq[string]] if result.hasKey(pair[0]): result[pair[0]].add(val) else: result[pair[0]] = @[val] + proc reorder(ctx: CliContext, state: IssueState) = # load the issues to make sure the order file contains all issues in the state. @@ -87,6 +88,10 @@ when isMainModule: var tagsOption = none(seq[string]) var exclTagsOption = none(seq[string]) + let filter = initFilter() + var filterOption = none(IssueFilter) + + if args["--properties"] or args["--context"]: var props = @@ -116,6 +121,54 @@ when isMainModule: if args["--excl-tags"]: exclTagsOption = some(($args["--excl-tags"]).split(",").mapIt(it.strip)) + # Initialize filter with properties (if given) + if propertiesOption.isSome: + filter.properties = propertiesOption.get + filterOption = some(filter) + + # Add property exclusions (if given) + if exclPropsOption.isSome: + filter.exclProperties = exclPropsOption.get + filterOption = some(filter) + + # If they supplied text matches, add that to the filter. + if args["--match"]: + filter.summaryMatch = some(re("(?i)" & $args["--match"])) + filterOption = some(filter) + + if args["--match-all"]: + filter.fullMatch = some(re("(?i)" & $args["--match-all"])) + filterOption = some(filter) + + # If no "context" property is given, use the default (if we have one) + if ctx.defaultContext.isSome and not filter.properties.hasKey("context"): + stderr.writeLine("Limiting to default context: " & ctx.defaultContext.get) + filter.properties["context"] = ctx.defaultContext.get + filterOption = some(filter) + + if tagsOption.isSome: + filter.hasTags = tagsOption.get + filterOption = some(filter) + + if exclTagsOption.isSome: + filter.exclTags = exclTagsOption.get + filterOption = some(filter) + + if args["--today"]: + filter.inclStates.add(@[Current, TodoToday, Pending]) + filterOption = some(filter) + + if args["--future"]: + filter.inclStates.add(@[Pending, Todo]) + filterOption = some(filter) + + # Finally, if the "context" is "all", don't filter on context + if filter.properties.hasKey("context") and + filter.properties["context"] == "all": + + filter.properties.del("context") + filter.exclProperties.del("context") + ## Actual command runners if args["new"] or args["add"]: let state = @@ -224,7 +277,6 @@ when isMainModule: updatedIssues.add(nextIssue) stdout.writeLine formatIssue(nextIssue) - issue.changeState(ctx.cfg.tasksDir, targetState) updatedIssues.add(issue) @@ -276,49 +328,6 @@ when isMainModule: elif args["list"]: - let filter = initFilter() - var filterOption = none(IssueFilter) - - # Initialize filter with properties (if given) - if propertiesOption.isSome: - filter.properties = propertiesOption.get - filterOption = some(filter) - - # Add property exclusions (if given) - if exclPropsOption.isSome: - filter.exclProperties = exclPropsOption.get - filterOption = some(filter) - - # If they supplied text matches, add that to the filter. - if args["--match"]: - filter.summaryMatch = some(re("(?i)" & $args["--match"])) - filterOption = some(filter) - - if args["--match-all"]: - filter.fullMatch = some(re("(?i)" & $args["--match-all"])) - filterOption = some(filter) - - # If no "context" property is given, use the default (if we have one) - if ctx.defaultContext.isSome and not filter.properties.hasKey("context"): - stderr.writeLine("Limiting to default context: " & ctx.defaultContext.get) - filter.properties["context"] = ctx.defaultContext.get - filterOption = some(filter) - - if tagsOption.isSome: - filter.hasTags = tagsOption.get - filterOption = some(filter) - - if exclTagsOption.isSome: - filter.exclTags = exclTagsOption.get - filterOption = some(filter) - - # Finally, if the "context" is "all", don't filter on context - if filter.properties.hasKey("context") and - filter.properties["context"] == "all": - - filter.properties.del("context") - filter.exclProperties.del("context") - var listContexts = false var listTags = false var statesOption = none(seq[IssueState]) diff --git a/src/pit/libpit.nim b/src/pit/libpit.nim index 5d1e717..bbde607 100644 --- a/src/pit/libpit.nim +++ b/src/pit/libpit.nim @@ -18,13 +18,15 @@ type Current = "current", TodoToday = "todo-today", Pending = "pending", - Done = "done", Todo = "todo" Dormant = "dormant" + Done = "done", IssueFilter* = ref object completedRange*: Option[tuple[b, e: DateTime]] fullMatch*, summaryMatch*: Option[Regex] + inclStates*: seq[IssueState] + exclStates*: seq[IssueState] hasTags*: seq[string] exclTags*: seq[string] properties*: TableRef[string, string] @@ -136,6 +138,8 @@ proc initFilter*(): IssueFilter = completedRange: none(tuple[b, e: DateTime]), fullMatch: none(Regex), summaryMatch: none(Regex), + inclStates: @[], + exclStates: @[], hasTags: @[], exclTags: @[], properties: newTable[string, string](), @@ -165,6 +169,10 @@ proc hasTagsFilter*(tags: seq[string]): IssueFilter = result = initFilter() result.hasTags = tags +proc stateFilter*(states: seq[IssueState]): IssueFilter = + result = initFilter() + result.inclStates = states + proc groupBy*(issues: seq[Issue], propertyKey: string): TableRef[string, seq[Issue]] = result = newTable[string, seq[Issue]]() for i in issues: @@ -426,6 +434,12 @@ proc filter*(issues: seq[Issue], filter: IssueFilter): seq[Issue] = let exclTag = exclTagLent f = f --> filter(it.tags.find(exclTag) < 0) + if filter.inclStates.len > 0: + f = f --> filter(filter.inclStates.contains(it.state)) + + if filter.exclStates.len > 0: + f = f --> filter(not filter.exclStates.contains(it.state)) + return f # not using result because zero_functional doesn't play nice with it proc find*(