Compare commits

..

4 Commits

5 changed files with 28 additions and 23 deletions

View File

@ -46,7 +46,7 @@ Some other common properties I use are:
- `resolution`: for short notes about why an issue was moved to `done`, - `resolution`: for short notes about why an issue was moved to `done`,
especially if it the action wasn't taken or if it is not completely clear especially if it the action wasn't taken or if it is not completely clear
that this issue was completed. that this issue was completed.
## Configuration Options ## Configuration Options
@ -107,7 +107,7 @@ in the configuration file. All options are optional unless stated otherwise.
- `defaultContext`: if present all invokations to the CLI will - `defaultContext`: if present all invokations to the CLI will
be in this context. This is like adding a `--context <defaultContext>` be in this context. This is like adding a `--context <defaultContext>`
parameter to every CLI invocation. Any actual `--context` parameter will parameter to every CLI invocation. Any actual `--context` parameter will
override this value. override this value.
- `verbose`: Show issue details when listing issues (same as - `verbose`: Show issue details when listing issues (same as
`--verbose` flag). `--verbose` flag).
@ -135,7 +135,4 @@ in the configuration file. All options are optional unless stated otherwise.
"Personal"; it does not need an alternate display name. "Personal"; it does not need an alternate display name.
* `tasksDir` **required**: a file path to the root directory for the issue * `tasksDir` **required**: a file path to the root directory for the issue
repository (same as `--tasks-dir` CLI parameter). repository (same as `--tasks-dir` CLI parameter).
- CLI parameter: *cannot be specified via CLI*
- config file key: `contexts`

View File

@ -1,6 +1,6 @@
# Package # Package
version = "4.9.3" version = "4.11.0"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Personal issue tracker." description = "Personal issue tracker."
license = "MIT" license = "MIT"
@ -10,9 +10,9 @@ bin = @["pit", "pit_api"]
# Dependencies # Dependencies
requires @[ requires @[
"nim >= 0.19.0", "nim >= 1.4.0",
"docopt 0.6.8", "docopt 0.6.8",
"jester 0.4.1", "jester 0.5.0",
"uuids 0.1.10", "uuids 0.1.10",
"https://git.jdb-labs.com/jdb/nim-cli-utils.git >= 0.6.4", "https://git.jdb-labs.com/jdb/nim-cli-utils.git >= 0.6.4",

View File

@ -199,6 +199,10 @@ proc list(ctx: CliContext, filter: Option[IssueFilter], state: Option[IssueState
if state.isSome: if state.isSome:
ctx.loadIssues(state.get) ctx.loadIssues(state.get)
if filter.isSome: ctx.filterIssues(filter.get) if filter.isSome: ctx.filterIssues(filter.get)
if state.get == Done and showToday:
ctx.issues[Done] = ctx.issues[Done].filterIt(
it.hasProp("completed") and
sameDay(getTime().local, it.getDateTime("completed")))
stdout.write ctx.formatSection(ctx.issues[state.get], state.get, "", verbose) stdout.write ctx.formatSection(ctx.issues[state.get], state.get, "", verbose)
return return
@ -221,13 +225,6 @@ proc list(ctx: CliContext, filter: Option[IssueFilter], state: Option[IssueState
if ctx.issues.hasKey(s) and ctx.issues[s].len > 0: if ctx.issues.hasKey(s) and ctx.issues[s].len > 0:
stdout.write ctx.formatSection(ctx.issues[s], s, indent, verbose) stdout.write ctx.formatSection(ctx.issues[s], s, indent, verbose)
if ctx.issues.hasKey(Done):
let doneIssues = ctx.issues[Done].filterIt(
it.hasProp("completed") and
sameDay(getTime().local, it.getDateTime("completed")))
if doneIssues.len > 0:
stdout.write ctx.formatSection(doneIssues, Done, indent, verbose)
# Future items # Future items
if future: if future:
if today: ctx.writeHeader("Future") if today: ctx.writeHeader("Future")
@ -466,6 +463,10 @@ Options:
filter.properties["context"] = ctx.defaultContext.get filter.properties["context"] = ctx.defaultContext.get
filterOption = some(filter) filterOption = some(filter)
if args["--tags"]:
filter.hasTags = ($args["--tags"]).split(',')
filterOption = some(filter)
# Finally, if the "context" is "all", don't filter on context # Finally, if the "context" is "all", don't filter on context
if filter.properties.hasKey("context") and if filter.properties.hasKey("context") and
filter.properties["context"] == "all": filter.properties["context"] == "all":

View File

@ -22,6 +22,7 @@ type
IssueFilter* = ref object IssueFilter* = ref object
completedRange*: Option[tuple[b, e: DateTime]] completedRange*: Option[tuple[b, e: DateTime]]
fullMatch*, summaryMatch*: Option[Regex] fullMatch*, summaryMatch*: Option[Regex]
hasTags*: seq[string]
properties*: TableRef[string, string] properties*: TableRef[string, string]
PitConfig* = ref object PitConfig* = ref object
@ -69,6 +70,7 @@ proc initFilter*(): IssueFilter =
completedRange: none(tuple[b, e: DateTime]), completedRange: none(tuple[b, e: DateTime]),
fullMatch: none(Regex), fullMatch: none(Regex),
summaryMatch: none(Regex), summaryMatch: none(Regex),
hasTags: @[],
properties: newTable[string, string]()) properties: newTable[string, string]())
proc propsFilter*(props: TableRef[string, string]): IssueFilter = proc propsFilter*(props: TableRef[string, string]): IssueFilter =
@ -91,6 +93,10 @@ proc fullMatchFilter*(pattern: string): IssueFilter =
result = initFilter() result = initFilter()
result.fullMatch = some(re("(?i)" & pattern)) result.fullMatch = some(re("(?i)" & pattern))
proc hasTagsFilter*(tags: seq[string]): IssueFilter =
result = initFilter()
result.hasTags = tags
proc groupBy*(issues: seq[Issue], propertyKey: string): TableRef[string, seq[Issue]] = proc groupBy*(issues: seq[Issue], propertyKey: string): TableRef[string, seq[Issue]] =
result = newTable[string, seq[Issue]]() result = newTable[string, seq[Issue]]()
for i in issues: for i in issues:
@ -259,6 +265,9 @@ proc filter*(issues: seq[Issue], filter: IssueFilter): seq[Issue] =
let p = filter.fullMatch.get let p = filter.fullMatch.get
result = result.filterIt( it.summary.find(p).isSome or it.details.find(p).isSome) result = result.filterIt( it.summary.find(p).isSome or it.details.find(p).isSome)
for tag in filter.hasTags:
result = result.filterIt(it.tags.find(tag) >= 0)
### Configuration utilities ### Configuration utilities
proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitConfig = proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitConfig =
let pitrcLocations = @[ let pitrcLocations = @[
@ -266,9 +275,9 @@ proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitCo
".pitrc", $getEnv("PITRC"), $getEnv("HOME") & "/.pitrc"] ".pitrc", $getEnv("PITRC"), $getEnv("HOME") & "/.pitrc"]
var pitrcFilename: string = var pitrcFilename: string =
foldl(pitrcLocations, if len(a) > 0: a elif existsFile(b): b else: "") foldl(pitrcLocations, if len(a) > 0: a elif fileExists(b): b else: "")
if not existsFile(pitrcFilename): if not fileExists(pitrcFilename):
warn "pit: could not find .pitrc file: " & pitrcFilename warn "pit: could not find .pitrc file: " & pitrcFilename
if isEmptyOrWhitespace(pitrcFilename): if isEmptyOrWhitespace(pitrcFilename):
pitrcFilename = $getEnv("HOME") & "/.pitrc" pitrcFilename = $getEnv("HOME") & "/.pitrc"
@ -299,12 +308,10 @@ proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitCo
if isEmptyOrWhitespace(result.tasksDir): if isEmptyOrWhitespace(result.tasksDir):
raise newException(Exception, "no tasks directory configured") raise newException(Exception, "no tasks directory configured")
if not existsDir(result.tasksDir): if not dirExists(result.tasksDir):
raise newException(Exception, "cannot find tasks dir: " & result.tasksDir) raise newException(Exception, "cannot find tasks dir: " & result.tasksDir)
# Create our tasks directory structure if needed # Create our tasks directory structure if needed
for s in IssueState: for s in IssueState:
if not existsDir(result.tasksDir / $s): if not dirExists(result.tasksDir / $s):
(result.tasksDir / $s).createDir (result.tasksDir / $s).createDir

View File

@ -1 +1 @@
const PIT_VERSION* = "4.9.3" const PIT_VERSION* = "4.11.0"