Compare commits

...

3 Commits

5 changed files with 78 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
# Package
version = "4.31.1"
version = "4.32.1"
author = "Jonathan Bernard"
description = "Personal issue tracker."
license = "MIT"

View File

@@ -253,11 +253,6 @@ when isMainModule:
elif args["edit"]:
for editRef in @(args["<ref>"]):
let propsOption =
if args["--properties"]:
some(parsePropertiesOption($args["--properties"]))
else: none(TableRef[string, string])
var stateOption = none(IssueState)
try: stateOption = some(parseEnum[IssueState](editRef))
@@ -267,10 +262,16 @@ when isMainModule:
let state = stateOption.get
ctx.loadIssues(state)
for issue in ctx.issues[state]:
if propsOption.isSome:
for k,v in propsOption.get:
if propertiesOption.isSome:
for k,v in propertiesOption.get:
issue[k] = v
edit(issue)
if tagsOption.isSome:
issue.tags = deduplicate(issue.tags & tagsOption.get)
if exclTagsOption.isSome:
issue.tags = issue.tags.filter(
proc (tag: string): bool = not exclTagsOption.get.anyIt(it == tag))
if args["--non-interactive"]: issue.store()
else: edit(issue)
updatedIssues.add(issue)
else:
@@ -278,7 +279,13 @@ when isMainModule:
if propertiesOption.isSome:
for k,v in propertiesOption.get:
issue[k] = v
edit(issue)
if tagsOption.isSome:
issue.tags = deduplicate(issue.tags & tagsOption.get)
if exclTagsOption.isSome:
issue.tags = issue.tags.filter(
proc (tag: string): bool = not exclTagsOption.get.anyIt(it == tag))
if args["--non-interactive"]: issue.store()
else: edit(issue)
updatedIssues.add(issue)
elif args["tag"]:
@@ -306,6 +313,17 @@ when isMainModule:
issue.store()
updatedIssues.add(issue)
elif args["update-details"]:
let details =
if not args["--file"] or $args["--file"] == "-": readAll(stdin)
else: readFile($args["--file"])
for id in @(args["<id>"]):
var issue = ctx.cfg.tasksDir.loadIssueById(id)
issue.details = details
issue.store()
updatedIssues.add(issue)
elif args["start"] or args["todo-today"] or args["done"] or
args["pending"] or args["todo"] or args["suspend"]:

View File

@@ -1,4 +1,4 @@
const PIT_VERSION* = "4.31.1"
const PIT_VERSION* = "4.32.1"
const USAGE* = """Usage:
pit ( new | add) <summary> [<state>] [options]
@@ -10,6 +10,7 @@ const USAGE* = """Usage:
pit ( start | done | pending | todo-today | todo | suspend ) <id>... [options]
pit edit <ref>... [options]
pit tag <id>... [options]
pit update-details <id> [--file=<path>] [options]
pit untag <id>... [options]
pit reorder <state> [options]
pit delegate <id> <delegated-to> [options]
@@ -247,4 +248,4 @@ Issue Properties:
If present, expected to be a comma-delimited list of text tags. The -g
option is a short-hand for '-p tags:<tags-value>'.
"""
"""

View File

@@ -1,4 +1,4 @@
import std/[json, jsonutils, logging, options, os, strformat, strutils, tables, times,
import std/[json, logging, options, os, strformat, strutils, tables, times,
unicode]
import cliutils, docopt, langutils, uuids, zero_functional

View File

@@ -1,12 +1,12 @@
import std/[algorithm, json, jsonutils, options, os, sets, strutils, tables,
terminal, times, unicode, wordwrap]
terminal, times, unicode]
from std/sequtils import repeat, toSeq
import cliutils, uuids, zero_functional
import ./[formatting, libpit]
const NO_PROJECT* = "<no-project>"
const NO_MILESTONE* = "<no-project>"
const NO_CONTEXT* = "<no-project>"
const NO_PROJECT* = "∅ No Project"
const NO_MILESTONE* = "∅ No Milestone"
const NO_CONTEXT* = "<no-context>"
type
ProjectCfg* = ref object of RootObj
@@ -129,6 +129,8 @@ proc listProjects*(ctx: CliContext, filter = none[IssueFilter]()) =
let projectsCfg = ctx.loadProjectsConfiguration()
var projectsCfgChanged = false
var linesToPrint = newSeq[string]()
if filter.isSome: ctx.filterIssues(filter.get)
let projectsByContext = newTable[string, CountTableRef[string]]()
@@ -150,10 +152,10 @@ proc listProjects*(ctx: CliContext, filter = none[IssueFilter]()) =
for (context, projects) in pairs(projectsByContext):
stdout.writeLine(withColor(
linesToPrint.add(withColor(
ctx.getIssueContextDisplayName(context) & ":",
fgYellow) & termReset)
stdout.writeLine("")
linesToPrint.add("")
var toList = toHashSet(toSeq(keys(projects)))
@@ -164,22 +166,29 @@ proc listProjects*(ctx: CliContext, filter = none[IssueFilter]()) =
for project in projectsCfg[context]:
if project.name in toList:
toList.excl(project.name)
stdout.writeLine(" " & project.name &
linesToPrint.add(" " & project.name &
" (" & $projects[project.name] & " issues)")
# Then list any remaining projects not in the configuration, and add them
# to the configuration
for (projectName, count) in pairs(projects):
if projectName in toList:
stdout.writeLine(" " & projectName & " (" & $count & " issues)")
linesToPrint.add(" " & projectName & " (" & $count & " issues)")
projectsCfg[context].add(ProjectCfg(name: projectName, milestoneOrder: @[]))
projectsCfgChanged = true
stdout.writeLine("")
linesToPrint.add("")
if projectsCfgChanged: ctx.saveProjectsConfiguration(projectsCfg)
if isatty(stdout):
stdout.writeLine(linesToPrint.join("\p"))
else:
stdout.writeLine(stripAnsi(linesToPrint.join("\p")))
proc listMilestones*(ctx: CliContext, filter = none[IssueFilter]()) =
var linesToPrint = newSeq[string]()
ctx.loadAllIssues()
if filter.isSome: ctx.filterIssues(filter.get)
@@ -194,8 +203,8 @@ proc listMilestones*(ctx: CliContext, filter = none[IssueFilter]()) =
if values(project.milestones) --> all(it.len == 0):
continue
stdout.writeLine(withColor(project.name, fgBlue, bold = true, bright=true))
stdout.writeLine(withColor(
linesToPrint.add(withColor(project.name, fgBlue, bold = true, bright=true))
linesToPrint.add(withColor(
"".repeat(runeLen(stripAnsi(project.name))),
fgBlue, bold = true))
@@ -203,9 +212,15 @@ proc listMilestones*(ctx: CliContext, filter = none[IssueFilter]()) =
if project.milestones.hasKey(milestone) and
project.milestones[milestone].len > 0:
let issueCount = project.milestones[milestone].len
stdout.writeLine(" " & milestone & " (" & $issueCount & " issues)")
linesToPrint.add(" " & milestone & " (" & $issueCount & " issues)")
linesToPrint.add("")
if isatty(stdout):
stdout.writeLine(linesToPrint.join("\p"))
else:
stdout.writeLine(stripAnsi(linesToPrint.join("\p")))
stdout.writeLine("")
proc formatProjectIssue(
ctx: CliContext,
@@ -306,22 +321,23 @@ proc joinColumns(columns: seq[seq[string]], columnWidth: int): seq[string] =
proc showProject*(ctx: CliContext, project: Project) =
var linesToPrint = newSeq[string]()
let fullWidth = terminalWidth() - 1
let columnWidth = 80
let numColumns = (fullWidth - 4) div (columnWidth + 2)
stdout.writeLine("")
stdout.writeLine(withColor(
"" & "".repeat(project.name.len + 2) &
"" & "".repeat(fullWidth - project.name.len - 4) & "",
linesToPrint.add("")
linesToPrint.add(withColor(
"" & "".repeat(project.name.runeLen + 2) &
"" & "".repeat(fullWidth - project.name.runeLen - 4) & "",
fgBlue, bold=true))
stdout.writeLine(
linesToPrint.add(
withColor("", fgBlue, bold=true) &
withColor(project.name, fgBlue, bold=true, bright=true) &
withColor("" & " ".repeat(fullWidth - project.name.len - 4) & "", fgBlue, bold=true))
stdout.writeLine(withColor(
"" & "".repeat(project.name.len + 2) &
"" & " ".repeat(fullWidth - project.name.len - 4) & "",
withColor("" & " ".repeat(fullWidth - project.name.runeLen - 4) & "", fgBlue, bold=true))
linesToPrint.add(withColor(
"" & "".repeat(project.name.runeLen + 2) &
"" & " ".repeat(fullWidth - project.name.runeLen - 4) & "",
fgBlue, bold=true))
let milestoneTexts: seq[seq[string]] = project.milestoneOrder -->
@@ -338,16 +354,22 @@ proc showProject*(ctx: CliContext, project: Project) =
for line in joinedLines:
let padLen = fullWidth - runeLen(stripAnsi(line)) - 3
stdout.writeLine(
linesToPrint.add(
withColor("", fgBlue) &
line &
" ".repeat(padLen) &
withColor("", fgBlue))
stdout.writeLine(withColor(
linesToPrint.add(withColor(
"" & "".repeat(terminalWidth() - 2) & "",
fgBlue, bold=true))
if isatty(stdout):
stdout.writeLine(linesToPrint.join("\p"))
else:
stdout.writeLine(stripAnsi(linesToPrint.join("\p")))
proc showProjectBoard*(ctx: CliContext, filter = none[IssueFilter]()) =
ctx.loadAllIssues()