Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a273091dc7 | |||
| e35bd9f85a | |||
| 3d8fafd7b2 | |||
| 7d5d55d24a | |||
| 89c924bb72 |
@@ -1,2 +1,2 @@
|
||||
[tools]
|
||||
nim = "2.2.6"
|
||||
nim = "2.2.8"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Package
|
||||
|
||||
version = "4.31.1"
|
||||
version = "4.33.1"
|
||||
author = "Jonathan Bernard"
|
||||
description = "Personal issue tracker."
|
||||
license = "MIT"
|
||||
@@ -19,7 +19,7 @@ requires @[
|
||||
|
||||
# Dependencies from git.jdb-software.com/jdb/nim-packages
|
||||
requires @[
|
||||
"cliutils >= 0.10.2",
|
||||
"cliutils >= 0.11.1",
|
||||
"langutils >= 0.4.0",
|
||||
"timeutils >= 0.5.4",
|
||||
"data_uri > 1.0.0",
|
||||
|
||||
42
src/pit.nim
42
src/pit.nim
@@ -92,8 +92,8 @@ proc addIssue(
|
||||
"Do you want to set a value for '" & propName & "'? " &
|
||||
"You can use the numbers above to use an existing value, enter " &
|
||||
"something new, or leave blank to indicate no value.\p" &
|
||||
withColor(propName, fgMagenta) & ":" &
|
||||
withColor(" ", fgBlue, bright=true, skipReset=true))
|
||||
color(propName, fg=cMagenta) & ":" &
|
||||
ansiEscSeq(fg=cBrightBlue) & " ")
|
||||
|
||||
let resp = stdin.readLine.strip
|
||||
let numberResp = resp.match(numberRegex)
|
||||
@@ -106,7 +106,7 @@ proc addIssue(
|
||||
elif resp.len > 0:
|
||||
issueProps[propName] = resp
|
||||
|
||||
stdout.writeLine(termReset)
|
||||
stdout.writeLine(RESET_FORMATTING)
|
||||
|
||||
result = Issue(
|
||||
id: genUUID(),
|
||||
@@ -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"]:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const PIT_VERSION* = "4.31.1"
|
||||
const PIT_VERSION* = "4.33.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]
|
||||
|
||||
@@ -6,36 +6,36 @@ import ./libpit
|
||||
proc adjustedTerminalWidth(): int = min(terminalWidth(), 80)
|
||||
|
||||
proc formatIssue*(issue: Issue): string =
|
||||
result = ($issue.id).withColor(fgBlack, true) & "\n"&
|
||||
issue.summary.withColor(fgWhite) & "\n"
|
||||
result = ($issue.id).color(cBrightBlack) & "\n"&
|
||||
issue.summary.color(cWhite) & "\n"
|
||||
|
||||
if issue.tags.len > 0:
|
||||
result &= "tags: ".withColor(fgMagenta) &
|
||||
issue.tags.join(",").withColor(fgGreen, true) & "\n"
|
||||
result &= "tags: ".color(cMagenta) &
|
||||
issue.tags.join(",").color(cBrightGreen) & "\n"
|
||||
|
||||
if issue.properties.len > 0:
|
||||
for k, v in issue.properties:
|
||||
|
||||
if k == "project":
|
||||
result &= "project: ".withColor(fgMagenta) &
|
||||
v.withColor(fgBlue, bright = true) & "\n"
|
||||
result &= "project: ".color(cMagenta) &
|
||||
v.color(cBrightBlue) & "\n"
|
||||
|
||||
elif k == "milestone":
|
||||
result &= "milestone: ".withColor(fgMagenta) &
|
||||
v.withColor(fgBlue, bright = true) & "\n"
|
||||
result &= "milestone: ".color(cMagenta) &
|
||||
v.color(cBrightBlue) & "\n"
|
||||
|
||||
elif k == "priority":
|
||||
result &= "priority: ".withColor(fgMagenta) &
|
||||
v.withColor(fgRed, bright = true) & "\n"
|
||||
result &= "priority: ".color(cMagenta) &
|
||||
v.color(cBrightRed) & "\n"
|
||||
|
||||
else:
|
||||
result &= termColor(fgMagenta) & k & ": " & v & "\n"
|
||||
result &= ansiEscSeq(fg = cMagenta) & k & ": " & v & "\n"
|
||||
|
||||
result &= "--------".withColor(fgBlack, true) & "\n"
|
||||
result &= "--------".color(cBrightBlack) & "\n"
|
||||
if not issue.details.isEmptyOrWhitespace:
|
||||
result &= issue.details.strip.withColor(fgCyan) & "\n"
|
||||
result &= issue.details.strip.color(cCyan) & "\n"
|
||||
|
||||
result &= termReset
|
||||
result &= RESET_FORMATTING
|
||||
|
||||
|
||||
proc formatPlainIssueSummary*(issue: Issue): string =
|
||||
@@ -64,7 +64,7 @@ proc formatSectionIssue*(
|
||||
verbose = false,
|
||||
bold = false): string =
|
||||
|
||||
result = (indent & ($issue.id)[0..<6]).withColor(fgBlack, true) & " "
|
||||
result = (indent & ($issue.id)[0..<6]).color(cBrightBlack) & " "
|
||||
|
||||
let showDetails = not issue.details.isEmptyOrWhitespace and verbose
|
||||
|
||||
@@ -75,7 +75,8 @@ proc formatSectionIssue*(
|
||||
.wrapWords(summaryWidth)
|
||||
.splitLines
|
||||
|
||||
result &= summaryLines[0].termFmt(fgWhite, bold=bold, underline=bold)
|
||||
result &= summaryLines[0].termFmt(fg=cWhite, bg=cDefault,
|
||||
style = if bold: { tsBold, tsUnderline } else: {})
|
||||
|
||||
for line in summaryLines[1..^1]:
|
||||
result &= "\p" & line.indent(summaryIndentLen)
|
||||
@@ -84,11 +85,11 @@ proc formatSectionIssue*(
|
||||
|
||||
if issue.hasProp("delegated-to"):
|
||||
if lastLineLen + issue["delegated-to"].len + 1 < summaryWidth:
|
||||
result &= " " & issue["delegated-to"].withColor(fgMagenta)
|
||||
result &= " " & issue["delegated-to"].color(cMagenta)
|
||||
lastLineLen += issue["delegated-to"].len + 1
|
||||
else:
|
||||
result &= "\p" & issue["delegated-to"]
|
||||
.withColor(fgMagenta)
|
||||
.color(cMagenta)
|
||||
.indent(summaryIndentLen)
|
||||
lastLineLen = issue["delegated-to"].len
|
||||
|
||||
@@ -99,28 +100,28 @@ proc formatSectionIssue*(
|
||||
|
||||
if tagsStrLines.len == 1 and
|
||||
(lastLineLen + tagsStrLines[0].len + 1) < summaryWidth:
|
||||
result &= " " & tagsStrLines[0].withColor(fgGreen)
|
||||
result &= " " & tagsStrLines[0].color(cGreen)
|
||||
lastLineLen += tagsStrLines[0].len + 1
|
||||
else:
|
||||
result &= "\p" & tagsStrLines
|
||||
.mapIt(it.indent(summaryIndentLen))
|
||||
.join("\p")
|
||||
.withColor(fgGreen)
|
||||
.color(cGreen)
|
||||
lastLineLen = tagsStrLines[^1].len
|
||||
|
||||
if issue.hasProp("pending"):
|
||||
result &= "\p" & ("Pending: " & issue["pending"])
|
||||
.wrapwords(summaryWidth)
|
||||
.withColor(fgCyan)
|
||||
.color(cCyan)
|
||||
.indent(summaryIndentLen)
|
||||
|
||||
if showDetails:
|
||||
result &= "\p" & issue.details
|
||||
.strip
|
||||
.withColor(fgBlack, bright = true)
|
||||
.color(cBrightBlack)
|
||||
.indent(summaryIndentLen)
|
||||
|
||||
result &= termReset
|
||||
result &= RESET_FORMATTING
|
||||
|
||||
|
||||
proc formatSectionIssueList*(
|
||||
@@ -139,19 +140,19 @@ proc formatSection(ctx: CliContext, issues: seq[Issue], state: IssueState,
|
||||
indent = "", verbose = false): string =
|
||||
let innerWidth = adjustedTerminalWidth() - (indent.len * 2)
|
||||
|
||||
result = termColor(fgBlue) &
|
||||
result = ansiEscSeq(fg = cBlue) &
|
||||
(indent & ".".repeat(innerWidth)) & "\n" &
|
||||
state.displayName.center(adjustedTerminalWidth()) & "\n\n" &
|
||||
termReset
|
||||
RESET_FORMATTING
|
||||
|
||||
let issuesByContext = issues.groupBy("context")
|
||||
|
||||
if issues.len > 5 and issuesByContext.len > 1:
|
||||
for context, ctxIssues in issuesByContext:
|
||||
|
||||
result &= termColor(fgYellow) &
|
||||
result &= ansiEscSeq(fg = cYellow) &
|
||||
indent & ctx.getIssueContextDisplayName(context) & ":" &
|
||||
termReset & "\n\n"
|
||||
RESET_FORMATTING & "\n\n"
|
||||
|
||||
result &= formatSectionIssueList(ctxIssues, innerWidth - 2, indent & " ", verbose)
|
||||
result &= "\n"
|
||||
@@ -160,11 +161,11 @@ proc formatSection(ctx: CliContext, issues: seq[Issue], state: IssueState,
|
||||
|
||||
|
||||
proc writeHeader*(ctx: CliContext, header: string) =
|
||||
stdout.setForegroundColor(fgRed, true)
|
||||
stdout.write(ansiEscSeq(fg = cBrightRed))
|
||||
stdout.writeLine('_'.repeat(adjustedTerminalWidth()))
|
||||
stdout.writeLine(header.center(adjustedTerminalWidth()))
|
||||
stdout.writeLine('~'.repeat(adjustedTerminalWidth()))
|
||||
stdout.resetAttributes
|
||||
stdout.write(RESET_FORMATTING)
|
||||
|
||||
|
||||
proc list*(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -230,7 +230,9 @@ proc fromStorageFormat*(id: string, issueTxt: string): Issue =
|
||||
var detailLines: seq[string] = @[]
|
||||
|
||||
for line in issueTxt.splitLines():
|
||||
if line.startsWith("#"): continue # ignore lines starting with '#'
|
||||
if line.startsWith("#") and parseState != ReadingDetails:
|
||||
# ignore lines starting with '#', unless we're in the details section.
|
||||
continue
|
||||
|
||||
case parseState
|
||||
|
||||
|
||||
@@ -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(termFmt(
|
||||
ctx.getIssueContextDisplayName(context) & ":",
|
||||
fgYellow) & termReset)
|
||||
stdout.writeLine("")
|
||||
fg=cYellow))
|
||||
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,18 +203,24 @@ 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(termFmt(project.name, cBrightBlue, style = { tsBold }))
|
||||
linesToPrint.add(termFmt(
|
||||
"─".repeat(runeLen(stripAnsi(project.name))),
|
||||
fgBlue, bold = true))
|
||||
cBrightBlue, style = { tsBold} ))
|
||||
|
||||
for milestone in project.milestoneOrder:
|
||||
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,
|
||||
@@ -214,31 +229,31 @@ proc formatProjectIssue(
|
||||
|
||||
var firstLine = ""
|
||||
if issue.state == IssueState.Done:
|
||||
firstLine &= withColor(" ✔ ", fgBlack, bold=true, bright=true)
|
||||
firstLine &= termFmt(" ✔ ", fg = cBrightBlack, style = { tsBold })
|
||||
else:
|
||||
case issue.getPriority
|
||||
of IssuePriority.essential:
|
||||
firstLine &= withColor("❶ ", fgRed, bold=true, bright=true)
|
||||
firstLine &= termFmt("❶ ", fg=cBrightRed, style={ tsBold })
|
||||
of IssuePriority.vital:
|
||||
firstLine &= withColor("❷ ", fgYellow, bold=true, bright=true)
|
||||
firstLine &= termFmt("❷ ", fg=cBrightYellow, style={ tsBold })
|
||||
of IssuePriority.important:
|
||||
firstLine &= withColor("❸ ", fgBlue, bold=true, bright=true)
|
||||
firstLine &= termFmt("❸ ", fg=cBrightBlue, style={ tsBold })
|
||||
of IssuePriority.optional:
|
||||
firstLine &= withColor("❹ ", fgBlack, bold=false, bright=true)
|
||||
firstLine &= termFmt("❹ ", fg=cBrightBlack)
|
||||
|
||||
let summaryText = formatSectionIssue(issue, width - 3,
|
||||
bold = [Current, TodoToday].contains(issue.state)).splitLines
|
||||
firstLine &= summaryText[0]
|
||||
|
||||
if issue.state == IssueState.Done:
|
||||
firstLine = withColor(stripAnsi(firstLine), fgBlack, bright=true)
|
||||
firstLine = termFmt(stripAnsi(firstLine), fg=cBrightBlack)
|
||||
|
||||
result.add(firstLine)
|
||||
result.add(summaryText[1 .. ^1] --> map(" " & it))
|
||||
|
||||
if issue.state == IssueState.Done:
|
||||
let origLines = result
|
||||
result = origLines --> map(withColor(stripAnsi(it), fgBlack, bright=true))
|
||||
result = origLines --> map(termFmt(stripAnsi(it), fg = cBrightBlack))
|
||||
|
||||
proc formatParentIssue*(
|
||||
ctx: CliContext,
|
||||
@@ -250,7 +265,7 @@ proc formatParentIssue*(
|
||||
|
||||
for child in sorted(children, cmp):
|
||||
let childLines = ctx.formatProjectIssue(child, width - 3)
|
||||
result.add(childLines --> map(withColor(" │ ", fgBlack, bright=true) & it))
|
||||
result.add(childLines --> map(termFmt(" │ ", fg=cBrightBlack) & it))
|
||||
|
||||
result.add("")
|
||||
|
||||
@@ -262,8 +277,8 @@ proc formatMilestone*(
|
||||
availWidth: int): seq[string] =
|
||||
|
||||
result = @[""]
|
||||
result.add(withColor(milestone, fgWhite, bold=true))
|
||||
result.add(withColor("─".repeat(availWidth), fgWhite))
|
||||
result.add(termFmt(milestone, fg=cWhite, style={tsBold}))
|
||||
result.add(termFmt("─".repeat(availWidth), fg=cWhite))
|
||||
|
||||
var parentsToChildren = issues -->
|
||||
filter(it.hasProp("parent")).group(it["parent"])
|
||||
@@ -306,23 +321,25 @@ 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) & "┐",
|
||||
fgBlue, bold=true))
|
||||
stdout.writeLine(
|
||||
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) & "│",
|
||||
fgBlue, bold=true))
|
||||
linesToPrint.add("")
|
||||
linesToPrint.add(termFmt(
|
||||
"┌" & "─".repeat(project.name.runeLen + 2) &
|
||||
"┬" & "─".repeat(fullWidth - project.name.runeLen - 4) & "┐",
|
||||
fg=cBlue, style={tsBold}))
|
||||
linesToPrint.add(
|
||||
termFmt("│ ", fg=cBlue, style={tsBold}) &
|
||||
termFmt(project.name, fg=cBrightBlue, style={tsBold}) &
|
||||
termFmt(" │" & " ".repeat(fullWidth - project.name.runeLen - 4) & "│",
|
||||
fg=cBlue, style={tsBold}))
|
||||
linesToPrint.add(termFmt(
|
||||
"├" & "─".repeat(project.name.runeLen + 2) &
|
||||
"┘" & " ".repeat(fullWidth - project.name.runeLen - 4) & "│",
|
||||
fg=cBlue, style={tsBold}))
|
||||
|
||||
let milestoneTexts: seq[seq[string]] = project.milestoneOrder -->
|
||||
filter(project.milestones.hasKey(it) and project.milestones[it].len > 0).
|
||||
@@ -338,15 +355,21 @@ proc showProject*(ctx: CliContext, project: Project) =
|
||||
|
||||
for line in joinedLines:
|
||||
let padLen = fullWidth - runeLen(stripAnsi(line)) - 3
|
||||
stdout.writeLine(
|
||||
withColor("│ ", fgBlue) &
|
||||
linesToPrint.add(
|
||||
termFmt("│ ", fg=cBlue) &
|
||||
line &
|
||||
" ".repeat(padLen) &
|
||||
withColor(" │", fgBlue))
|
||||
termFmt(" │", fg=cBlue))
|
||||
|
||||
stdout.writeLine(withColor(
|
||||
linesToPrint.add(termFmt(
|
||||
"└" & "─".repeat(terminalWidth() - 2) & "┘",
|
||||
fgBlue, bold=true))
|
||||
fg=cBlue, style={tsBold}))
|
||||
|
||||
if isatty(stdout):
|
||||
stdout.writeLine(linesToPrint.join("\p"))
|
||||
else:
|
||||
stdout.writeLine(stripAnsi(linesToPrint.join("\p")))
|
||||
|
||||
|
||||
|
||||
proc showProjectBoard*(ctx: CliContext, filter = none[IssueFilter]()) =
|
||||
@@ -367,9 +390,9 @@ proc showProjectBoard*(ctx: CliContext, filter = none[IssueFilter]()) =
|
||||
for (context, projects) in contextsAndProjects:
|
||||
if contextsAndProjects.len > 1:
|
||||
stdout.writeLine("")
|
||||
stdout.writeLine(withColor(
|
||||
stdout.writeLine(termFmt(
|
||||
ctx.getIssueContextDisplayName(context) & ":",
|
||||
fgYellow, bold=true))
|
||||
fg=cYellow, style={tsBold}))
|
||||
stdout.writeLine("")
|
||||
|
||||
for p in projects:
|
||||
|
||||
Reference in New Issue
Block a user