package main import ( "fmt" "strconv" "strings" "time" "github.com/pborman/uuid" ) func cmdStartTimer(args []string) int { var err error var entry *Timer // By default we start the timer now tm := time.Now() tags, rem := pullTagsFromArgs(args) if len(rem) > 0 { // Check if the first argument looks like a date/time tm, err = parseFuzzyTime(rem[0]) } entry = NewTimer(tm, time.Time{}) entry.SetTags(tags) if err = SaveTimer(entry); err != nil { fmt.Println(err) return 1 } fmt.Println("Started:", entry.FriendlyString()) return 0 } func cmdAddTimer(args []string) int { var err error var entry *Timer // By default we're starting the time now tags, rem := pullTagsFromArgs(args) var beg, end time.Time for _, opt := range rem { var tmpBeg, tmpEnd time.Time if strings.Contains(opt, "-") { pts := strings.Split(opt, "-") if len(pts[0]) > 0 { // This should be the starting date tmpBeg, err = parseFuzzyTime(pts[0]) if err != nil { continue } } if len(pts[1]) > 0 { // This should be the ending date tmpEnd, err = parseFuzzyTime(pts[1]) if err != nil { continue } } } if !tmpBeg.IsZero() || !tmpEnd.IsZero() { beg, end = tmpBeg, tmpEnd } } if end.IsZero() { end = time.Now() } entry = NewTimer(beg, end) fmt.Println("Adding Timer:", entry.FriendlyString()) entry.Tags = tags if err = SaveTimer(entry); err != nil { fmt.Println(err) return 1 } fmt.Println("Added Time Entry:", entry.FriendlyString()) return 0 } func cmdContinueTimer(args []string) int { // Get the last running timer and start a new one with the same tags m, err := LoadMetadata() if err != nil { return 1 } tid := m.GetLastStopped() for i := range args { if strings.HasPrefix(args[i], "@") { tid = strings.TrimLeft(args[i], "@") } } t := LoadTimer(tid) fmt.Println("Last Tags:", t.Tags) for i := range t.Tags { t.Tags[i] = "+" + t.Tags[i] } args = append(args, t.Tags...) return cmdStartTimer(args) } func cmdStopTimer(args []string) int { var err error tm := time.Now() actTimers := LoadActiveTimers() var tmr *Timer stopId := "@-" // By default, stop the first timer for i := range args { if args[i][0] == '@' { stopId = args[i] continue } tmpTm, err := parseFuzzyTime(args[i]) if err == nil { // We found a time tm = tmpTm continue } } if stopId != "@all" { // Find the timer that we're stopping timerId, err := strconv.Atoi(stopId[1:]) if err != nil { fmt.Println("Error parsing timer id:", err.Error()) return 1 } tmr = &actTimers[timerId] if timerId >= len(actTimers) || timerId < 0 || tmr == nil { fmt.Println("Error finding timer with id:", timerId) return 1 } } m, err := LoadMetadata() if err != nil { fmt.Println("Unable to load metadata, 'Most Recent' timer may be incorrect") } stopTimer := func(tmr *Timer, at time.Time) int { tmr.SetEnd(at) if err = SaveTimer(tmr); err != nil { fmt.Println(err.Error()) return 1 } m.SetLastStopped(tmr.GetUUID()) fmt.Println("Stopped:", tmr.InferDetailString()) return 0 } if stopId == "@all" { var ret int for _, v := range actTimers { ret += stopTimer(&v, tm) } SaveMetadata(m) if ret > 0 { return 1 } return 0 } ret := stopTimer(tmr, tm) SaveMetadata(m) return ret } func cmdDeleteTimer(args []string) int { if len(args) < 1 { fmt.Println("Delete requires a timer UUID") return 1 } // Try to parse args[0] as a UUID if uuid.Parse(args[0]) == nil { // Not a UUID, bail for now fmt.Print("Invalid UUID given (", args[0], ")\n") return 1 } tmr := LoadTimer(args[0]) if tmr == nil { fmt.Println("Couldn't find timer with UUID (", args[0], ")\n") return 1 } if DeleteTimer(args[0]) != nil { fmt.Println("Error deleting timer") return 1 } return 0 } func cmdModifyTimer(args []string) int { var err error // searchUUID is the [partial] uuid of the timer we're modifying var searchUUID string var edtTmr *Timer var tags, remTags, rem []string tags, rem = pullTagsFromArgs(args) remTags, rem = pullRemoveTagsFromArgs(rem) var start, end time.Time for i := range rem { if strings.HasPrefix(rem[i], "@") { searchUUID = strings.TrimLeft(searchUUID, "@") edtTmr = LoadTimerFromPartialUUID(searchUUID) } if strings.HasPrefix(rem[i], "start=") { stStr := strings.TrimPrefix(rem[i], "start=") start, err = parseFuzzyTime(stStr) if err != nil { fmt.Println("Unable to parse start time: " + stStr) return 1 } } if strings.HasPrefix(rem[i], "end=") { endStr := strings.TrimPrefix(rem[i], "end=") end, err = parseFuzzyTime(endStr) if err != nil { fmt.Println("Unable to parse end time: " + endStr) return 1 } } } if edtTmr == nil { fmt.Println("Error finding timer:", searchUUID) return 1 } fmt.Println(edtTmr.String()) _, _, _, _ = tags, remTags, start, end fmt.Println(tags, remTags, start, end) return 0 } func cmdSwitchTimer(args []string) int { stopId := "@all" stopIdIdx := -1 for i := range args { // See if we have a timer id in the args if args[i][0] == '@' { stopId = args[i] stopIdIdx = i } } if stopIdIdx >= 0 { args = append(args[:stopIdIdx], args[stopIdIdx+1:]...) } if cmdStopTimer([]string{stopId}) != 0 { // Error while stopping tiemrs return 1 } return cmdStartTimer(args) } func cmdPrintStatus(args []string) int { tmrs := LoadActiveTimers() curr := time.Now() var showId bool for i := range args { if strings.HasPrefix(args[i], ":id") { showId = true } } fmt.Println("Current Time:", curr.Format(time.Stamp)) if len(tmrs) == 0 { fmt.Println("No timer running") } else { fmt.Print("Active Timers (", len(tmrs), ")\n") // Find the longest start time & longest duration short := true for _, v := range tmrs { if v.GetStart().Day() != curr.Day() { short = false break } } for i, v := range tmrs { var id string if showId { id = " (" + v.GetUUID() + ")" } if short { fmt.Printf(" @%d %s%s\n", i, v.DetailString(), id) } else { fmt.Printf(" @%d %s%s\n", i, v.LongDetailString(), id) } } } return 0 } func cmdPrintList(args []string) int { var showIds, showActiveTimers, onlyShowActive bool var beg, end time.Time tags, rem := pullTagsFromArgs(args) for _, opt := range rem { var tmpBeg, tmpEnd time.Time // Check for command modifiers if strings.HasPrefix(opt, ":") { switch opt { case ":ids": showIds = true case ":day": beg, _ = parseFuzzyTime("00:00") end, _ = parseFuzzyTime("23:59") case ":week": currDoW := time.Now().Weekday() beg = time.Now().AddDate(0, 0, int(currDoW)*-1) beg = time.Date(beg.Year(), beg.Month(), beg.Day(), 0, 0, 0, 0, beg.Location()) case ":month": currDoM := time.Now().Day() beg = time.Now().AddDate(0, 0, int(currDoM)*-1) beg = time.Date(beg.Year(), beg.Month(), beg.Day(), 0, 0, 0, 0, beg.Location()) case ":year": yr := strconv.Itoa(time.Now().Year()) beg, _ = parseFuzzyTime(yr + "0101T00:00") end, _ = parseFuzzyTime(yr + "1231T23:59") } continue } // Do our best to figure out what timers the user wants to list var err error if strings.Contains(opt, "-") { onlyShowActive = false pts := strings.Split(opt, "-") if len(pts[0]) > 0 { // This should be the starting date tmpBeg, err = parseFuzzyTime(pts[0]) if err != nil { continue } } if len(pts[1]) > 0 { // This should be the ending date tmpEnd, err = parseFuzzyTime(pts[1]) if err != nil { continue } } } if !tmpBeg.IsZero() || !tmpEnd.IsZero() { beg, end = tmpBeg, tmpEnd } } if end.IsZero() { end = time.Now() showActiveTimers = true } // By default, list all entries ending today or still running dayStr := "" var tmrs []Timer if showActiveTimers { tmrs = LoadActiveTimers() } if !onlyShowActive { tmrs = append(tmrs, LoadTimers(beg, end)...) } if len(tags) > 0 { // Filter the tags var filtered []Timer for _, tg := range tags { FilterTimers(tmrs, func(t *Timer) bool { return t.HasTag(tg) }) } tmrs = filtered } var str string if len(tmrs) == 0 { if onlyShowActive { fmt.Println("No timers found for today") } else { begFmt := friendlyFormatForTime(beg) endFmt := friendlyFormatForTime(end) useFmt := endFmt if len(begFmt) > len(endFmt) { useFmt = begFmt } fmt.Println("No timers found in period " + beg.Format(useFmt) + " - " + end.Format(useFmt)) } return 0 } // Get day totals dayTotals := make(map[string]time.Duration) for _, v := range tmrs { dur := v.GetEnd().Sub(v.GetStart()) if v.GetEnd().IsZero() { dur = time.Now().Sub(v.GetStart()) } dayTotals[v.GetStart().Format("2006/01/02")] += dur } for _, v := range tmrs { oldDayStr := dayStr dayStr = v.GetStart().Format("2006/01/02") if dayStr != oldDayStr { vDur := dayTotals[dayStr].Round(GetRoundToDuration()) fmtStr := dayStr + " ( %.2f )\n" str += fmt.Sprintf(fmtStr, DurationToDecimal(vDur)) } if showIds { str += fmt.Sprintf(" %s (%s)\n", v.FriendlyString(), v.GetUUID()) } else { str += fmt.Sprintf(" %s\n", v.FriendlyString()) } } fmt.Println(str) return 0 } func cmdPrintDetail(args []string) int { fmt.Println("Not implemented yet.") return 1 }