From 6fbe5754710523e3aca78324ba11fadd1d1adc5f Mon Sep 17 00:00:00 2001 From: Martin Pander Date: Fri, 11 Sep 2026 13:17:04 +0200 Subject: [PATCH] Fix latency issue --- main.go | 7 +++++++ pages/main.go | 12 +++++++++++- pages/report.go | 3 +-- pages/timePage.go | 21 +++++++-------------- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/main.go b/main.go index 060cb55..4dcc0f1 100644 --- a/main.go +++ b/main.go @@ -13,9 +13,16 @@ import ( "tasksquire/timewarrior" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" ) func main() { + // TaskSquire's Iceberg palette is a light theme. Tell Lip Gloss explicitly + // so adaptive styles in third-party components do not issue an OSC 11 + // terminal query. Some terminals do not answer that query, and termenv waits + // five seconds before falling back. + lipgloss.SetHasDarkBackground(false) + var taskrcPath string if taskrcEnv := os.Getenv("TASKRC"); taskrcEnv != "" { taskrcPath = taskrcEnv diff --git a/pages/main.go b/pages/main.go index dc4f637..c637d9f 100644 --- a/pages/main.go +++ b/pages/main.go @@ -34,7 +34,9 @@ func NewMainPage(common *common.Common) *MainPage { } func (m *MainPage) Init() tea.Cmd { - return tea.Batch(m.taskPage.Init(), m.timePage.Init()) + // Initialize only the visible page. Messages from commands started for an + // inactive page would be routed to the active page and discarded. + return tea.Batch(m.activePage.Init(), doTick()) } func (m *MainPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -57,6 +59,14 @@ func (m *MainPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.activePage = activePage.(common.Component) return m, cmd + case tickMsg: + // Own the single application tick loop here. Pages only react to ticks; + // allowing each page and refresh action to schedule another tick creates + // duplicate loops and eventually floods the CLI wrappers with requests. + activePage, cmd := m.activePage.Update(msg) + m.activePage = activePage.(common.Component) + return m, tea.Batch(cmd, doTick()) + case tea.KeyMsg: // Only handle tab key for page switching when at the top level (no subpages active) if key.Matches(msg, m.common.Keymap.Next) && !m.common.HasSubpages() { diff --git a/pages/report.go b/pages/report.go index 19124b2..eeccc6b 100644 --- a/pages/report.go +++ b/pages/report.go @@ -93,7 +93,7 @@ func min(a, b int) int { } func (p *ReportPage) Init() tea.Cmd { - return tea.Batch(p.getTasks(), doTick()) + return p.getTasks() } func (p *ReportPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -104,7 +104,6 @@ func (p *ReportPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // case BackMsg: case tickMsg: cmds = append(cmds, p.getTasks()) - cmds = append(cmds, doTick()) return p, tea.Batch(cmds...) case taskMsg: p.tasks = taskwarrior.Tasks(msg) diff --git a/pages/timePage.go b/pages/timePage.go index 584fd14..419d20f 100644 --- a/pages/timePage.go +++ b/pages/timePage.go @@ -142,14 +142,14 @@ func (p *TimePage) renderHeader() string { start.Year()) } - slog.Info("Rendering time page header", "text", headerText, "timespan", p.selectedTimespan) + slog.Debug("Rendering time page header", "text", headerText, "timespan", p.selectedTimespan) // Make header bold and prominent headerStyle := lipgloss.NewStyle().Bold(true).Foreground(p.common.Styles.Palette.Accent.GetForeground()) return headerStyle.Render(headerText) } func (p *TimePage) Init() tea.Cmd { - return tea.Batch(p.getIntervals(), doTick()) + return p.getIntervals() } func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -177,17 +177,11 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { p.common.TW.StopActiveTasks() p.common.TW.StartTask(msg.Task) cmds = append(cmds, p.getIntervals()) - cmds = append(cmds, doTick()) } case RefreshIntervalsMsg: cmds = append(cmds, p.getIntervals()) - cmds = append(cmds, doTick()) - case BackMsg: - // Restart tick loop when returning from subpage - cmds = append(cmds, doTick()) case tickMsg: cmds = append(cmds, p.getIntervals()) - cmds = append(cmds, doTick()) case tea.KeyMsg: switch { case key.Matches(msg, p.common.Keymap.Quit): @@ -232,7 +226,6 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { p.pendingSyncAction = "start" } cmds = append(cmds, p.getIntervals()) - cmds = append(cmds, doTick()) return p, tea.Batch(cmds...) } case key.Matches(msg, p.common.Keymap.Delete): @@ -240,7 +233,7 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if row != nil { interval := (*timewarrior.Interval)(row) p.common.TimeW.DeleteInterval(interval.ID) - return p, tea.Batch(p.getIntervals(), doTick()) + return p, p.getIntervals() } case key.Matches(msg, p.common.Keymap.Edit): row := p.intervals.SelectedRow() @@ -261,11 +254,11 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if row != nil { interval := (*timewarrior.Interval)(row) p.common.TimeW.FillInterval(interval.ID) - return p, tea.Batch(p.getIntervals(), doTick()) + return p, p.getIntervals() } case key.Matches(msg, p.common.Keymap.Undo): p.common.TimeW.Undo() - return p, tea.Batch(p.getIntervals(), doTick()) + return p, p.getIntervals() case key.Matches(msg, p.common.Keymap.Join): row := p.intervals.SelectedRow() if row != nil { @@ -273,7 +266,7 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Don't join if this is the last (oldest) interval if interval.ID < len(p.data) { p.common.TimeW.JoinInterval(interval.ID) - return p, tea.Batch(p.getIntervals(), doTick()) + return p, p.getIntervals() } } } @@ -313,7 +306,7 @@ func (p *TimePage) View() string { tableHeight := lipgloss.Height(tableView) headerHeight := lipgloss.Height(header) - slog.Info("TimePage View rendered", + slog.Debug("TimePage View rendered", "headerLen", len(header), "dataCount", len(p.data), "headerHeight", headerHeight,