Fix latency issue

This commit is contained in:
Martin Pander
2026-09-11 13:17:04 +02:00
parent 6b1418fc71
commit 6fbe575471
4 changed files with 26 additions and 17 deletions

View File

@@ -13,9 +13,16 @@ import (
"tasksquire/timewarrior" "tasksquire/timewarrior"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
) )
func main() { 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 var taskrcPath string
if taskrcEnv := os.Getenv("TASKRC"); taskrcEnv != "" { if taskrcEnv := os.Getenv("TASKRC"); taskrcEnv != "" {
taskrcPath = taskrcEnv taskrcPath = taskrcEnv

View File

@@ -34,7 +34,9 @@ func NewMainPage(common *common.Common) *MainPage {
} }
func (m *MainPage) Init() tea.Cmd { 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) { 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) m.activePage = activePage.(common.Component)
return m, cmd 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: case tea.KeyMsg:
// Only handle tab key for page switching when at the top level (no subpages active) // 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() { if key.Matches(msg, m.common.Keymap.Next) && !m.common.HasSubpages() {

View File

@@ -93,7 +93,7 @@ func min(a, b int) int {
} }
func (p *ReportPage) Init() tea.Cmd { 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) { 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 BackMsg:
case tickMsg: case tickMsg:
cmds = append(cmds, p.getTasks()) cmds = append(cmds, p.getTasks())
cmds = append(cmds, doTick())
return p, tea.Batch(cmds...) return p, tea.Batch(cmds...)
case taskMsg: case taskMsg:
p.tasks = taskwarrior.Tasks(msg) p.tasks = taskwarrior.Tasks(msg)

View File

@@ -142,14 +142,14 @@ func (p *TimePage) renderHeader() string {
start.Year()) 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 // Make header bold and prominent
headerStyle := lipgloss.NewStyle().Bold(true).Foreground(p.common.Styles.Palette.Accent.GetForeground()) headerStyle := lipgloss.NewStyle().Bold(true).Foreground(p.common.Styles.Palette.Accent.GetForeground())
return headerStyle.Render(headerText) return headerStyle.Render(headerText)
} }
func (p *TimePage) Init() tea.Cmd { 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) { 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.StopActiveTasks()
p.common.TW.StartTask(msg.Task) p.common.TW.StartTask(msg.Task)
cmds = append(cmds, p.getIntervals()) cmds = append(cmds, p.getIntervals())
cmds = append(cmds, doTick())
} }
case RefreshIntervalsMsg: case RefreshIntervalsMsg:
cmds = append(cmds, p.getIntervals()) cmds = append(cmds, p.getIntervals())
cmds = append(cmds, doTick())
case BackMsg:
// Restart tick loop when returning from subpage
cmds = append(cmds, doTick())
case tickMsg: case tickMsg:
cmds = append(cmds, p.getIntervals()) cmds = append(cmds, p.getIntervals())
cmds = append(cmds, doTick())
case tea.KeyMsg: case tea.KeyMsg:
switch { switch {
case key.Matches(msg, p.common.Keymap.Quit): 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" p.pendingSyncAction = "start"
} }
cmds = append(cmds, p.getIntervals()) cmds = append(cmds, p.getIntervals())
cmds = append(cmds, doTick())
return p, tea.Batch(cmds...) return p, tea.Batch(cmds...)
} }
case key.Matches(msg, p.common.Keymap.Delete): 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 { if row != nil {
interval := (*timewarrior.Interval)(row) interval := (*timewarrior.Interval)(row)
p.common.TimeW.DeleteInterval(interval.ID) 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): case key.Matches(msg, p.common.Keymap.Edit):
row := p.intervals.SelectedRow() row := p.intervals.SelectedRow()
@@ -261,11 +254,11 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if row != nil { if row != nil {
interval := (*timewarrior.Interval)(row) interval := (*timewarrior.Interval)(row)
p.common.TimeW.FillInterval(interval.ID) 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): case key.Matches(msg, p.common.Keymap.Undo):
p.common.TimeW.Undo() p.common.TimeW.Undo()
return p, tea.Batch(p.getIntervals(), doTick()) return p, p.getIntervals()
case key.Matches(msg, p.common.Keymap.Join): case key.Matches(msg, p.common.Keymap.Join):
row := p.intervals.SelectedRow() row := p.intervals.SelectedRow()
if row != nil { 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 // Don't join if this is the last (oldest) interval
if interval.ID < len(p.data) { if interval.ID < len(p.data) {
p.common.TimeW.JoinInterval(interval.ID) 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) tableHeight := lipgloss.Height(tableView)
headerHeight := lipgloss.Height(header) headerHeight := lipgloss.Height(header)
slog.Info("TimePage View rendered", slog.Debug("TimePage View rendered",
"headerLen", len(header), "headerLen", len(header),
"dataCount", len(p.data), "dataCount", len(p.data),
"headerHeight", headerHeight, "headerHeight", headerHeight,