|
|
@ -4,7 +4,7 @@
|
|
|
|
## Simple time keeping CLI
|
|
|
|
## Simple time keeping CLI
|
|
|
|
|
|
|
|
|
|
|
|
import algorithm, docopt, json, langutils, logging, os, nre, sequtils,
|
|
|
|
import algorithm, docopt, json, langutils, logging, os, nre, sequtils,
|
|
|
|
strutils, tempfile, terminal, times, timeutils, uuids
|
|
|
|
sets, strutils, tempfile, terminal, times, timeutils, uuids
|
|
|
|
|
|
|
|
|
|
|
|
import ptkutil
|
|
|
|
import ptkutil
|
|
|
|
|
|
|
|
|
|
|
@ -23,7 +23,8 @@ const ISO_TIME_FORMAT = "yyyy:MM:dd'T'HH:mm:ss"
|
|
|
|
|
|
|
|
|
|
|
|
const TIME_FORMATS = @[
|
|
|
|
const TIME_FORMATS = @[
|
|
|
|
"H:mm", "HH:mm", "H:mm:ss", "HH:mm:ss",
|
|
|
|
"H:mm", "HH:mm", "H:mm:ss", "HH:mm:ss",
|
|
|
|
"yyyy:MM:dd'T'HH:mm:ss", "yyyy:MM:dd'T'HH:mm"]
|
|
|
|
"yyyy:MM:dd'T'HH:mm:ss", "yyyy:MM:dd'T'HH:mm",
|
|
|
|
|
|
|
|
"yyyy:MM:dd HH:mm:ss", "yyyy:MM:dd HH:mm"]
|
|
|
|
|
|
|
|
|
|
|
|
#proc `$`*(mark: Mark): string =
|
|
|
|
#proc `$`*(mark: Mark): string =
|
|
|
|
#return (($mark.uuid)[
|
|
|
|
#return (($mark.uuid)[
|
|
|
@ -99,10 +100,11 @@ proc writeMarks(timeline: Timeline, indices: seq[int], includeNotes = false): vo
|
|
|
|
var idxs = indices.sorted(
|
|
|
|
var idxs = indices.sorted(
|
|
|
|
proc(a, b: int): int = cmp(marks[a].time, marks[b].time))
|
|
|
|
proc(a, b: int): int = cmp(marks[a].time, marks[b].time))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let largestInterval = now - marks[idxs.first].time
|
|
|
|
let timeFormat =
|
|
|
|
let timeFormat =
|
|
|
|
if now - marks[idxs.first].time > 1.years: "yyyy-MM-dd HH:mm"
|
|
|
|
if largestInterval > 1.years: "yyyy-MM-dd HH:mm"
|
|
|
|
elif now - marks[idxs.first].time > 7.days: "MMM dd HH:mm"
|
|
|
|
elif largestInterval > 7.days: "MMM dd HH:mm"
|
|
|
|
elif now - marks[idxs.first].time > 1.days: "ddd HH:mm"
|
|
|
|
elif largestInterval > 1.days: "ddd HH:mm"
|
|
|
|
else: "HH:mm"
|
|
|
|
else: "HH:mm"
|
|
|
|
|
|
|
|
|
|
|
|
var toWrite: seq[WriteData] = @[]
|
|
|
|
var toWrite: seq[WriteData] = @[]
|
|
|
@ -254,6 +256,24 @@ proc filterMarkIndices(timeline: Timeline, args: Table[string, Value]): seq[int]
|
|
|
|
"invalid value for --before: " & getCurrentExceptionMsg())
|
|
|
|
"invalid value for --before: " & getCurrentExceptionMsg())
|
|
|
|
result = result.filterIt(marks[it].time < endTime)
|
|
|
|
result = result.filterIt(marks[it].time < endTime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args["--today"]:
|
|
|
|
|
|
|
|
let now = getLocalTime(getTime())
|
|
|
|
|
|
|
|
let b = now.startOfDay
|
|
|
|
|
|
|
|
let e = b + 1.days
|
|
|
|
|
|
|
|
result = result.filterIt(marks[it].time >= b and marks[it].time < e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args["--this-week"]:
|
|
|
|
|
|
|
|
let now = getLocalTime(getTime())
|
|
|
|
|
|
|
|
let b = now.startOfWeek(dSun)
|
|
|
|
|
|
|
|
let e = b + 7.days
|
|
|
|
|
|
|
|
result = result.filterIt(marks[it].time >= b and marks[it].time < e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args["--last-week"]:
|
|
|
|
|
|
|
|
let now = getLocalTime(getTime())
|
|
|
|
|
|
|
|
let e = now.startOfWeek(dSun)
|
|
|
|
|
|
|
|
let b = e - 7.days
|
|
|
|
|
|
|
|
result = result.filterIt(marks[it].time >= b and marks[it].time < e)
|
|
|
|
|
|
|
|
|
|
|
|
if args["--tags"]:
|
|
|
|
if args["--tags"]:
|
|
|
|
let tags = (args["--tags"] ?: "").split({',', ';'})
|
|
|
|
let tags = (args["--tags"] ?: "").split({',', ';'})
|
|
|
|
result = result.filter(proc (i: int): bool =
|
|
|
|
result = result.filter(proc (i: int): bool =
|
|
|
@ -276,6 +296,7 @@ Usage:
|
|
|
|
ptk add [options]
|
|
|
|
ptk add [options]
|
|
|
|
ptk add [options] <summary>
|
|
|
|
ptk add [options] <summary>
|
|
|
|
ptk amend [options] <id> [<summary>]
|
|
|
|
ptk amend [options] <id> [<summary>]
|
|
|
|
|
|
|
|
ptk merge <timeline> [<timeline>...]
|
|
|
|
ptk stop [options]
|
|
|
|
ptk stop [options]
|
|
|
|
ptk continue
|
|
|
|
ptk continue
|
|
|
|
ptk delete <id>
|
|
|
|
ptk delete <id>
|
|
|
@ -300,6 +321,9 @@ Options:
|
|
|
|
-m --matching <pattern> Restric the selection to marks matching <pattern>.
|
|
|
|
-m --matching <pattern> Restric the selection to marks matching <pattern>.
|
|
|
|
-n --notes <notes> For add and amend, set the notes for a time mark.
|
|
|
|
-n --notes <notes> For add and amend, set the notes for a time mark.
|
|
|
|
-t --time <time> For add and amend, use this time instead of the current time.
|
|
|
|
-t --time <time> For add and amend, use this time instead of the current time.
|
|
|
|
|
|
|
|
-T --today Restrict the selection to marks during today.
|
|
|
|
|
|
|
|
-w --this-week Restrict the selection to marks during this week.
|
|
|
|
|
|
|
|
-W --last-week Restrict the selection to marks during the last week.
|
|
|
|
-v --verbose Include notes in timeline entry output.
|
|
|
|
-v --verbose Include notes in timeline entry output.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
@ -309,7 +333,7 @@ Options:
|
|
|
|
let now = getLocalTime(getTime())
|
|
|
|
let now = getLocalTime(getTime())
|
|
|
|
|
|
|
|
|
|
|
|
# Parse arguments
|
|
|
|
# Parse arguments
|
|
|
|
let args = docopt(doc, version = "ptk 0.3.0")
|
|
|
|
let args = docopt(doc, version = "ptk 0.6.0")
|
|
|
|
|
|
|
|
|
|
|
|
if args["--echo-args"]: echo $args
|
|
|
|
if args["--echo-args"]: echo $args
|
|
|
|
|
|
|
|
|
|
|
@ -355,6 +379,30 @@ Options:
|
|
|
|
if args["init"]:
|
|
|
|
if args["init"]:
|
|
|
|
doInit(foldl(timelineLocations, if len(a) > 0: a else: b))
|
|
|
|
doInit(foldl(timelineLocations, if len(a) > 0: a else: b))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif args["merge"]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let filesToMerge = args["<timeline>"]
|
|
|
|
|
|
|
|
let timelines = filesToMerge.mapIt(loadTimeline(it))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let names = timelines.mapIt(it.name).toSet
|
|
|
|
|
|
|
|
let mergedName = sequtils.toSeq(names.items).foldl(a & " + " & b)
|
|
|
|
|
|
|
|
var merged: Timeline = (
|
|
|
|
|
|
|
|
name: mergedName,
|
|
|
|
|
|
|
|
marks: @[])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for timeline in timelines:
|
|
|
|
|
|
|
|
for mark in timeline.marks:
|
|
|
|
|
|
|
|
var existingMarkIdx = merged.marks.findById($mark.id)
|
|
|
|
|
|
|
|
if existingMarkIdx >= 0:
|
|
|
|
|
|
|
|
if merged.marks[existingMarkIdx].summary != mark.summary:
|
|
|
|
|
|
|
|
merged.marks[existingMarkIdx].summary &= " | " & mark.summary
|
|
|
|
|
|
|
|
if merged.marks[existingMarkIdx].notes != mark.notes:
|
|
|
|
|
|
|
|
merged.marks[existingMarkIdx].notes &= "\r\n--------\r\b" & mark.notes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else: merged.marks.add(mark)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
writeLine(stdout, pretty(%merged))
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
|
|
if not fileExists(timelineLocation):
|
|
|
|
if not fileExists(timelineLocation):
|
|
|
|