package main import ( "fmt" "strings" "time" timertxt "git.bullercodeworks.com/brian/go-timertxt" ) // If we have an active timer in timer.txt, return the most recent one // Otherwise, check if we have a more recent completed timer in done.txt // Return the most recent done from timer.txt or dont.txt func (a *AppState) getMostRecentTimer() (*timertxt.Timer, error) { work, wErr := a.TimerList.GetMostRecentTimer() if wErr == nil && work.FinishDate.IsZero() { return work, nil } if err := a.LoadDoneList(); err != nil { return nil, err } done, dErr := a.DoneList.GetMostRecentTimer() if dErr != nil { return nil, dErr } if !done.FinishDate.IsZero() && work == nil || done.FinishDate.After(work.FinishDate) { return done, nil } return work, nil } func (a *AppState) getFilteredTimerList(args []string) *timertxt.TimerList { var includeArchive bool var err error start := time.Time{} end := time.Now() var contextFilters []string var projectFilters []string var allFilters []func(timertxt.Timer) bool if len(args) > 0 { contextFilters, args = getContextsFromSlice(args) projectFilters, args = getProjectsFromSlice(args) } if len(args) > 0 { if args[0] == "--a" { includeArchive = true args = args[1:] } } if len(args) > 0 { if start, err = parseFuzzyTime(args[0]); err != nil { y, m, d := time.Now().Date() start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location()) } else { args = args[1:] } if len(args) > 0 { if end, err = parseFuzzyTime(args[0]); err != nil { y, m, d := time.Now().Date() end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location()) } else { args = args[1:] } } } list := a.TimerList.GetTimersInRange(start, end) if includeArchive { if err = a.LoadDoneList(); err != nil { fmt.Println("Error loading done.txt entries") fmt.Println(err.Error()) return nil } *list = append(*list, (*a.DoneList.GetTimersInRange(start, end))...) } if len(contextFilters) > 0 { allFilters = append(allFilters, func(t timertxt.Timer) bool { for _, v := range contextFilters { v = strings.TrimPrefix(v, "@") if !t.HasContext(v) { return false } } return true }) } if len(projectFilters) > 0 { allFilters = append(allFilters, func(t timertxt.Timer) bool { for _, v := range projectFilters { v = strings.TrimPrefix(v, "+") if !t.HasProject(v) { return false } } return true }) } doFilters := func(t timertxt.Timer) bool { for _, v := range allFilters { if !v(t) { return false } } // If we made it all the way down here, it matches return true } return list.Filter(doFilters) } func (a *AppState) SetTimerFinished(id int, end time.Time) error { var t *timertxt.Timer var err error if t, err = a.TimerList.GetTimer(id); err != nil { return err } t.FinishDate = end t.Finished = true return nil } func (a *AppState) addTimer(timerString string) error { t, err := timertxt.ParseTimer(timerString) if err != nil { return err } if t.StartDate.IsZero() { t.StartDate = time.Now() } a.TimerList.AddTimer(t) return a.WriteList() } func (a *AppState) archiveTimer(id int) error { var err error var timer *timertxt.Timer if timer, err = a.TimerList.GetTimer(id); err != nil { return err } if err := a.TimerList.ArchiveTimerToFile(*timer, app.getDoneFile()); err != nil { return err } a.TimerList.RemoveTimer(*timer) return a.WriteList() } func (a *AppState) unarchiveTimer(id int) error { var err error var timer *timertxt.Timer if timer, err = a.DoneList.GetTimer(id); err != nil { return err } a.TimerList.AddTimer(timer) if err = a.WriteList(); err != nil { return err } a.DoneList.RemoveTimer(*timer) return a.WriteDoneList() } func (a *AppState) LoadTimerList() error { var err error var tl timertxt.TimerList tl, err = timertxt.LoadFromFilename(a.getTimerFile()) tl.Sort(timertxt.SORT_UNFINISHED_START) a.TimerList = &tl return err } func (a *AppState) WriteList() error { return a.TimerList.WriteToFilename(a.getTimerFile()) } func (a *AppState) LoadDoneList() error { var err error var tl timertxt.TimerList tl, err = timertxt.LoadFromFilename(a.getDoneFile()) a.DoneList = &tl return err } func (a *AppState) WriteDoneList() error { return a.DoneList.WriteToFilename(a.getDoneFile()) } func (a *AppState) getFilterPredicate(filter string) func(timertxt.Timer) bool { var predicates []func(timertxt.Timer) bool // If none of the 'filter' is in upper-case, do a case-insensitive filter checkCase := true if strings.ToLower(filter) == filter { checkCase = false } filterParts := strings.Split(filter, " ") for _, part := range filterParts { if strings.HasPrefix(part, "@") { predicates = append(predicates, func(t timertxt.Timer) bool { for _, v := range t.Contexts { if "@"+v == part { return true } } return false }) } else if strings.HasPrefix(part, "+") { predicates = append(predicates, func(t timertxt.Timer) bool { for _, v := range t.Projects { if "+"+v == part { return true } } return false }) } else { predicates = append(predicates, func(t timertxt.Timer) bool { val := t.Original if !checkCase { val = strings.ToLower(t.Original) } return strings.Contains(val, part) }) } } return func(t timertxt.Timer) bool { for _, v := range predicates { if v(t) { return true } } return false } }