diff --git a/src/pit.nim b/src/pit.nim index 0faca1b..68d23f3 100644 --- a/src/pit.nim +++ b/src/pit.nim @@ -4,6 +4,7 @@ import cliutils, docopt, json, logging, options, os, ospaths, sequtils, tables, terminal, times, timeutils, unicode, uuids +from nre import re import strutils except capitalize, toUpper, toLower import pitpkg/private/libpit export libpit @@ -182,7 +183,7 @@ proc edit(issue: Issue) = getCurrentExceptionMsg() issue.store() -proc list(ctx: CliContext, filter: Option[IssueFilter], state: Option[IssueState], today, future, verbose: bool) = +proc list(ctx: CliContext, filter: Option[IssueFilter], state: Option[IssueState], showToday, showFuture, verbose: bool) = if state.isSome: ctx.loadIssues(state.get) @@ -193,6 +194,12 @@ proc list(ctx: CliContext, filter: Option[IssueFilter], state: Option[IssueState ctx.loadAllIssues() if filter.isSome: ctx.filterIssues(filter.get) + let today = showToday and [Current, TodoToday].anyIt( + ctx.issues.hasKey(it) and ctx.issues[it].len > 0) + + let future = showFuture and [Pending, Todo].anyIt( + ctx.issues.hasKey(it) and ctx.issues[it].len > 0) + let indent = if today and future: " " else: "" # Today's items @@ -246,6 +253,12 @@ Options: -F, --future Limit to future issues. + -m, --match Limit to issues whose summaries match the given + pattern (PCRE regex supported). + + -M, --match-all Limit to the issues whose summaries or details + match the given pattern (PCRE regex supported). + -v, --verbose Show issue details when listing issues. -q, --quiet Suppress verbose output. @@ -380,6 +393,15 @@ Options: filter.properties = propertiesOption.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) diff --git a/src/pitpkg/private/libpit.nim b/src/pitpkg/private/libpit.nim index 148bdd1..d67d071 100644 --- a/src/pitpkg/private/libpit.nim +++ b/src/pitpkg/private/libpit.nim @@ -1,7 +1,8 @@ import cliutils, docopt, json, logging, options, os, ospaths, sequtils, strutils, tables, times, timeutils, uuids -from nre import re, match +from nre import find, match, re, Regex + type Issue* = ref object id*: UUID @@ -19,8 +20,9 @@ type Dormant = "dormant" IssueFilter* = ref object + completedRange*: Option[tuple[b, e: DateTime]] + fullMatch*, summaryMatch*: Option[Regex] properties*: TableRef[string, string] - completedRange*: tuple[b, e: DateTime] PitConfig* = ref object tasksDir*: string @@ -62,22 +64,30 @@ proc setDateTime*(issue: Issue, key: string, dt: DateTime) = proc initFilter*(): IssueFilter = result = IssueFilter( - properties: newTable[string,string](), - completedRange: (fromUnix(0).local, fromUnix(253400659199).local)) + completedRange: none(tuple[b, e: DateTime]), + fullMatch: none(Regex), + summaryMatch: none(Regex), + properties: newTable[string, string]()) -proc initFilter*(props: TableRef[string, string]): IssueFilter = +proc propsFilter*(props: TableRef[string, string]): IssueFilter = if isNil(props): raise newException(ValueError, "cannot initialize property filter without properties") - result = IssueFilter( - properties: props, - completedRange: (fromUnix(0).local, fromUnix(253400659199).local)) + result = initFilter() + result.properties = props -proc initFilter*(range: tuple[b, e: DateTime]): IssueFilter = - result = IssueFilter( - properties: newTable[string, string](), - completedRange: range) +proc dateFilter*(range: tuple[b, e: DateTime]): IssueFilter = + result = initFilter() + result.completedRange = some(range) + +proc summaryMatchFilter*(pattern: string): IssueFilter = + result = initFilter() + result.summaryMatch = some(re("(?i)" & pattern)) + +proc fullMatchFilter*(pattern: string): IssueFilter = + result = initFilter() + result.fullMatch = some(re("(?i)" & pattern)) ## Parse and format issues proc fromStorageFormat*(id: string, issueTxt: string): Issue = @@ -190,10 +200,19 @@ proc filter*(issues: seq[Issue], filter: IssueFilter): seq[Issue] = for k,v in filter.properties: result = result.filterIt(it.hasProp(k) and it[k] == v) - result = result.filterIt(not it.hasProp("completed") or - it.getDateTime("completed").between( - filter.completedRange.b, - filter.completedRange.e)) + if filter.completedRange.isSome: + let range = filter.completedRange.get + result = result.filterIt( + not it.hasProp("completed") or + it.getDateTime("completed").between(range.b, range.e)) + + if filter.summaryMatch.isSome: + let p = filter.summaryMatch.get + result = result.filterIt(it.summary.find(p).isSome) + + if filter.fullMatch.isSome: + let p = filter.fullMatch.get + result = result.filterIt( it.summary.find(p).isSome or it.details.find(p).isSome) ### Configuration utilities proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitConfig =