diff --git a/pit.nimble b/pit.nimble index 0e4b215..3db2896 100644 --- a/pit.nimble +++ b/pit.nimble @@ -1,6 +1,6 @@ # Package -version = "4.22.2" +version = "4.23.0" author = "Jonathan Bernard" description = "Personal issue tracker." license = "MIT" @@ -14,7 +14,8 @@ requires @[ "nim >= 1.4.0", "docopt >= 0.6.8", "jester >= 0.5.0", - "uuids >= 0.1.10" + "uuids >= 0.1.10", + "zero_functional" ] # Dependencies from git.jdb-software.com/nim-jdb/packages diff --git a/src/pit.nim b/src/pit.nim index 7d95f13..b80d278 100644 --- a/src/pit.nim +++ b/src/pit.nim @@ -1,8 +1,8 @@ ## Personal Issue Tracker CLI interface ## ==================================== -import std/algorithm, std/logging, std/options, std/os, std/sequtils, - std/wordwrap, std/tables, std/terminal, std/times, std/unicode +import std/[algorithm, logging, options, os, sequtils, wordwrap, tables, + terminal, times, unicode] import cliutils, data_uri, docopt, json, timeutils, uuids from nre import re diff --git a/src/pitpkg/cliconstants.nim b/src/pitpkg/cliconstants.nim index e902a04..4d829ed 100644 --- a/src/pitpkg/cliconstants.nim +++ b/src/pitpkg/cliconstants.nim @@ -1,4 +1,4 @@ -const PIT_VERSION* = "4.22.2" +const PIT_VERSION* = "4.23.0" const USAGE* = """Usage: pit ( new | add) [] [options] diff --git a/src/pitpkg/private/libpit.nim b/src/pitpkg/private/libpit.nim index 6dfa9e6..2cfc3e6 100644 --- a/src/pitpkg/private/libpit.nim +++ b/src/pitpkg/private/libpit.nim @@ -1,8 +1,9 @@ -import std/json, std/logging, std/options, std/os, std/sequtils, std/strformat, - std/strutils, std/tables, std/times -import cliutils, docopt, langutils, timeutils, uuids +import std/[json, logging, options, os, strformat, strutils, tables, times] +import cliutils, docopt, langutils, uuids, zero_functional import nre except toSeq +import timeutils except `>` +from sequtils import deduplicate, toSeq type Issue* = ref object @@ -11,6 +12,7 @@ type summary*, details*: string properties*: TableRef[string, string] tags*: seq[string] + state*: IssueState IssueState* = enum Current = "current", @@ -201,12 +203,13 @@ proc fromStorageFormat*(id: string, issueTxt: string): Issue = continue - let parts = line.split({':'}, 1).mapIt(it.strip()) + let parts = line.split({':'}, 1) --> map(it.strip()) if parts.len != 2: raise newException(ValueError, "unable to parse property line: " & line) # Take care of special properties: `tags` - if parts[0] == "tags": result.tags = parts[1].split({','}).mapIt(it.strip()) + if parts[0] == "tags": + result.tags = parts[1].split({','}) --> map(it.strip()) else: result[parts[0]] = parts[1] of ReadingDetails: @@ -234,6 +237,11 @@ proc loadIssue*(filePath: string): Issue = result = fromStorageFormat(splitFile(filePath).name, readFile(filePath)) result.filepath = filePath + let parentDirName = filePath.splitFile().dir.splitFile().name + let issueState = IssueState.items.toSeq --> find($it == parentDirName) + if issueState.isSome: result.state = issueState.get + else: result.state = IssueState.Done + proc loadIssueById*(tasksDir, id: string): Issue = for path in walkDirRec(tasksDir): if path.splitFile.name.startsWith(id): @@ -273,10 +281,10 @@ proc loadIssues*(path: string): seq[Issue] = let orderedIds = if fileExists(orderFile): - toSeq(orderFile.lines) - .mapIt(it.split(' ')[0]) - .deduplicate - .filterIt(not it.startsWith("> ") and not it.isEmptyOrWhitespace) + (orderFile.lines.toSeq --> + map(it.split(' ')[0]). + filter(not it.startsWith("> ") and not it.isEmptyOrWhitespace)). + deduplicate() else: newSeq[string]() type TaggedIssue = tuple[issue: Issue, ordered: bool] @@ -332,6 +340,7 @@ proc nextRecurrence*(tasksDir: string, rec: Recurrence, defaultIssue: Issue): Is result = Issue( id: genUUID(), + state: baseIssue.state, summary: baseIssue.summary, properties: newProps, tags: baseIssue.tags) @@ -354,36 +363,38 @@ proc nextRecurrence*(tasksDir: string, rec: Recurrence, defaultIssue: Issue): Is ## Utilities for working with issue collections. proc filter*(issues: seq[Issue], filter: IssueFilter): seq[Issue] = - result = issues + var f: seq[Issue] = issues for k,v in filter.properties: - result = result.filterIt(it.hasProp(k) and it[k] == v) + f = f --> filter(it.hasProp(k) and it[k] == v) for k,v in filter.exclProperties: - result = result.filter(proc (iss: Issue): bool = - not iss.hasProp(k) or - not v.anyIt(it == iss[k]) - ) + f = f --> filter(not (it.hasProp(k) and v.contains(it[k]))) if filter.completedRange.isSome: let range = filter.completedRange.get - result = result.filterIt( + f = f --> filter( 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) + f = f --> filter(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) + f = f --> + filter(it.summary.find(p).isSome or it.details.find(p).isSome) - for tag in filter.hasTags: - result = result.filterIt(it.tags.find(tag) >= 0) + for tagLent in filter.hasTags: + let tag = tagLent + f = f --> filter(it.tags.find(tag) >= 0) - for exclTag in filter.exclTags: - result = result.filterIt(it.tags.find(exclTag) < 0) + for exclTagLent in filter.exclTags: + let exclTag = exclTagLent + f = f --> filter(it.tags.find(exclTag) < 0) + + return f # not using result because zero_functional doesn't play nice with it proc find*( issues: TableRef[IssueState, seq[Issue]], @@ -400,7 +411,7 @@ proc loadConfig*(args: Table[string, Value] = initTable[string, Value]()): PitCo ".pitrc", $getEnv("PITRC"), $getEnv("HOME") & "/.pitrc"] var pitrcFilename: string = - foldl(pitrcLocations, if len(a) > 0: a elif fileExists(b): b else: "") + pitrcLocations --> fold("", if fileExists(it): it else: a) if not fileExists(pitrcFilename): warn "could not find .pitrc file: " & pitrcFilename