diff --git a/clock.go b/clock.go index b442406..c58918e 100644 --- a/clock.go +++ b/clock.go @@ -27,17 +27,17 @@ func (c *Clock) AddDays(n int) { c.t = c.t.AddDate(0, 0, n) } -// AddDays adds n days to the current date. +// AddDays adds n days to the current date and clears the minutes func (c *Clock) AddHours(n int) { c.t = time.Date( - c.t.Year(), // Year - c.t.Month(), // Month - c.t.Day(), // Day - c.t.Hour(), // Hour - 0, // Minutes set to 0 - 0, // Seconds set to 0 - 0, // Nanoseconds set to 0 - c.t.Location(), // Location (timezone) + c.t.Year(), + c.t.Month(), + c.t.Day(), + c.t.Hour(), + 0, // Minutes set to 0 + 0, // Seconds set to 0 + 0, // Nanoseconds set to 0 + c.t.Location(), ) c.t = c.t.Add(time.Hour * time.Duration(n)) } diff --git a/config.go b/config.go index b5dce5f..202dbfb 100644 --- a/config.go +++ b/config.go @@ -47,8 +47,7 @@ func LoadConfig(tzConfigs []string) (*Config, error) { zones := make([]*Zone, len(tzConfigs)+1) // Setup with Local time zone - now := Now.Time() - localZoneName, _ := now.Zone() + localZoneName, _ := time.Now().Zone() zones[0] = &Zone{ Name: fmt.Sprintf("(%s) Local", localZoneName), DbName: localZoneName, @@ -56,7 +55,7 @@ func LoadConfig(tzConfigs []string) (*Config, error) { // Add zones from TZ_LIST for i, zoneConf := range tzConfigs { - zone, err := SetupZone(now, zoneConf) + zone, err := SetupZone(time.Now(), zoneConf) if err != nil { return nil, err } diff --git a/main.go b/main.go index 93ce3b2..d4a7c12 100644 --- a/main.go +++ b/main.go @@ -35,9 +35,6 @@ const CurrentVersion = "0.7.0" var ( term = termenv.ColorProfile() hasDarkBackground = termenv.HasDarkBackground() - - // Now is used around tz to share/set the current time. - Now *Clock = NewClock(0) ) type tickMsg time.Time @@ -75,8 +72,7 @@ func openInTimeAndDateDotCom(t time.Time) error { type model struct { zones []*Zone - now time.Time - hour int + clock Clock showDates bool interactive bool isMilitary bool @@ -103,39 +99,28 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case "left", "h": - if m.hour == 0 { - m.hour = 23 - } else { - m.hour-- - } - Now.AddHours(-1) + m.clock.AddHours(-1) case "right", "l": - if m.hour > 22 { - m.hour = 0 - } else { - m.hour++ - } - Now.AddHours(1) + m.clock.AddHours(1) case "H": - Now.AddDays(-1) + m.clock.AddDays(-1) case "L": - Now.AddDays(1) + m.clock.AddDays(1) case "<": - Now.AddDays(-7) + m.clock.AddDays(-7) case ">": - Now.AddDays(7) + m.clock.AddDays(7) case "o": - openInTimeAndDateDotCom(Now.Time()) + openInTimeAndDateDotCom(m.clock.Time()) case "t": - Now = NewClock(0) - m.hour = Now.Time().Hour() + m.clock = *NewClock(0) case "?": m.showHelp = !m.showHelp @@ -146,9 +131,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tickMsg: if m.watch { - m.now = time.Time(msg) - Now = NewClock(0) - m.hour = Now.Time().Hour() + m.clock = *NewClock(0) } return m, tick() } @@ -179,9 +162,6 @@ func main() { os.Exit(0) } - if *when != 0 { - Now = NewClock(*when) - } config, err := LoadConfig(flag.Args()) if err != nil { fmt.Fprintf(os.Stderr, "Config error: %s\n", err) @@ -189,19 +169,33 @@ func main() { } var initialModel = model{ zones: config.Zones, - now: Now.Time(), - hour: Now.Time().Hour(), + clock: *NewClock(0), showDates: false, isMilitary: *military, watch: *watch, showHelp: false, } + if *when != 0 { + initialModel.clock = *NewClock(*when) + } + initialModel.interactive = !*exitQuick + // if len(os.Getenv("DEBUG")) > 0 { + // f, err := tea.LogToFile("debug.log", "debug") + // if err != nil { + // fmt.Println("fatal:", err) + // os.Exit(1) + // } + // defer f.Close() + // } + p := tea.NewProgram(initialModel) if err := p.Start(); err != nil { fmt.Printf("Alas, there's been an error: %v", err) os.Exit(1) } + + // loadConfigFile() } diff --git a/main_test.go b/main_test.go index 96758ca..0a7ef2a 100644 --- a/main_test.go +++ b/main_test.go @@ -19,10 +19,27 @@ package main import ( "strings" "testing" + "time" tea "github.com/charmbracelet/bubbletea" ) +func getTimestampWithHour(hour int) int64 { + if hour == -1 { + hour = time.Now().Hour() + } + return time.Date( + time.Now().Year(), + time.Now().Month(), + time.Now().Day(), + hour, + 0, // Minutes set to 0 + 0, // Seconds set to 0 + 0, // Nanoseconds set to 0 + time.Now().Location(), + ).Unix() +} + func TestUpdateIncHour(t *testing.T) { // "l" key -> go right msg := tea.KeyMsg{ @@ -45,19 +62,18 @@ func TestUpdateIncHour(t *testing.T) { for _, test := range tests { m := model{ zones: DefaultZones, - hour: test.startHour, + clock: *NewClock(getTimestampWithHour(test.startHour)), } - // Do we enjoy global mutable state? - db := Now.Time().Day() + db := m.clock.Time().Day() nextState, cmd := m.Update(msg) - da := Now.Time().Day() + da := m.clock.Time().Day() if cmd != nil { t.Errorf("Expected nil Cmd, but got %v", cmd) return } - h := nextState.(model).hour + h := nextState.(model).clock.t.Hour() if h != test.nextHour { t.Errorf("Expected %d, but got %d", test.nextHour, h) } @@ -88,14 +104,14 @@ func TestUpdateDecHour(t *testing.T) { for _, test := range tests { m := model{ zones: DefaultZones, - hour: test.startHour, + clock: *NewClock(getTimestampWithHour(test.startHour)), } nextState, cmd := m.Update(msg) if cmd != nil { t.Errorf("Expected nil Cmd, but got %v", cmd) return } - h := nextState.(model).hour + h := nextState.(model).clock.t.Hour() if h != test.nextHour { t.Errorf("Expected %d, but got %d", test.nextHour, h) } @@ -112,7 +128,7 @@ func TestUpdateQuitMsg(t *testing.T) { m := model{ zones: DefaultZones, - hour: 10, + clock: *NewClock(getTimestampWithHour(-1)), } _, cmd := m.Update(msg) if cmd == nil { @@ -126,13 +142,12 @@ func TestUpdateQuitMsg(t *testing.T) { func TestMilitaryTime(t *testing.T) { m := model{ zones: DefaultZones, - hour: 14, - now: Now.Time(), + clock: *NewClock(getTimestampWithHour(-1)), isMilitary: true, showDates: true, } s := m.View() - if !strings.Contains(s, m.now.Format("15:04")) { - t.Errorf("Expected military time of %s, but got %s", m.now.Format("15:04"), s) + if !strings.Contains(s, m.clock.t.Format("15:04")) { + t.Errorf("Expected military time of %s, but got %s", m.clock.t.Format("15:04"), s) } } diff --git a/view.go b/view.go index 257a9d1..ce67826 100644 --- a/view.go +++ b/view.go @@ -36,7 +36,7 @@ func (m model) View() string { startHour := 0 if zi > 0 { - startHour = (zone.currentTime().Hour() - m.zones[0].currentTime().Hour()) % 24 + startHour = (zone.currentTime(m.clock.t).Hour() - m.zones[0].currentTime(m.clock.t).Hour()) % 24 } dateChanged := false @@ -46,7 +46,7 @@ func (m model) View() string { out = out.Foreground(term.Color(hourColorCode(hour))) // Cursor - if m.hour == i-startHour { + if m.clock.t.Hour() == i-startHour { out = out.Background(term.Color(hourColorCode(hour))) if hasDarkBackground { out = out.Foreground(term.Color("#262626")).Bold() @@ -72,12 +72,12 @@ func (m model) View() string { var datetime string if m.isMilitary { - datetime = zone.ShortMT() + datetime = zone.ShortMT(m.clock.t) } else { - datetime = zone.ShortDT() + datetime = zone.ShortDT(m.clock.t) } - zoneHeader := fmt.Sprintf("%s %-60s %76s", zone.ClockEmoji(), normalTextStyle(zone.String()), dateTimeStyle(datetime)) + zoneHeader := fmt.Sprintf("%s %-60s %76s", zone.ClockEmoji(m.clock.t), normalTextStyle(zone.String()), dateTimeStyle(datetime)) s += fmt.Sprintf(" %s\n %s\n %s\n", zoneHeader, hours.String(), dates.String()) } @@ -117,8 +117,8 @@ func status(m model) string { } func formatDayChange(m *model, z *Zone) string { - zTime := z.currentTime() - if zTime.Hour() > m.now.Hour() { + zTime := z.currentTime(m.clock.t) + if zTime.Hour() > m.clock.t.Hour() { zTime = zTime.AddDate(0, 0, 1) } diff --git a/zone.go b/zone.go index 32ad9f7..32ddac6 100644 --- a/zone.go +++ b/zone.go @@ -57,30 +57,29 @@ func (z Zone) String() string { } // ClockEmoji returns the corresponding emoji clock for a given hour -func (z Zone) ClockEmoji() string { - h := ((z.currentTime().Hour() % 12) + 12) % 12 +func (z Zone) ClockEmoji(t time.Time) string { + h := ((z.currentTime(t).Hour() % 12) + 12) % 12 return EmojiClocks[h] } // ShortDT returns the current time in short format. -func (z Zone) ShortDT() string { - return z.currentTime().Format("3:04PM, Mon Jan 02, 2006") +func (z Zone) ShortDT(t time.Time) string { + return z.currentTime(t).Format("3:04PM, Mon Jan 02, 2006") } // ShortMT returns the current military time in short format. -func (z Zone) ShortMT() string { - return z.currentTime().Format("15:04, Mon Jan 02, 2006") +func (z Zone) ShortMT(t time.Time) string { + return z.currentTime(t).Format("15:04, Mon Jan 02, 2006") } -func (z Zone) currentTime() time.Time { - now := Now.Time() - zName, _ := now.Zone() +func (z Zone) currentTime(t time.Time) time.Time { + zName, _ := t.Zone() if z.DbName != zName { loc, err := time.LoadLocation(z.DbName) if err != nil { - return now + return t } - return now.In(loc) + return t.In(loc) } - return now + return t }