summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-07 09:07:05 +0300
committerPaul Buetow <paul@buetow.org>2026-04-07 09:24:18 +0300
commitf2b75267a6085f28a415bc8464cf2a70b650e65f (patch)
treeb420c89466161dd627011b1267f423accbb9bca5
parent0aee798f25d09203742361c173e9dcd1a300d700 (diff)
ui: fix priority black spot and q/esc search-clear in ultra mode
Priority field: the no-priority dash (-) was rendered with terminal- default (black) background because the priority badge path unconditionally passed bg="" to suppress the badge colour. Now only H/M/L pass bg="" to preserve their coloured pill; the dash case inherits the card bg. q/esc with active search: first press clears the ultra search filter (regex + filtered index + cursor reset) and stays in ultra mode, same as esc behaves in normal table mode. A second press with no active search exits ultra / quits the app as before. Tests updated accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--internal/ui/keyhandlers.go11
-rw-r--r--internal/ui/table_test.go44
-rw-r--r--internal/ui/ultra.go7
3 files changed, 45 insertions, 17 deletions
diff --git a/internal/ui/keyhandlers.go b/internal/ui/keyhandlers.go
index d68a7f5..ffd52b1 100644
--- a/internal/ui/keyhandlers.go
+++ b/internal/ui/keyhandlers.go
@@ -157,6 +157,15 @@ func (m *Model) handleQuitOrEscape() (tea.Model, tea.Cmd) {
return m, nil
}
if m.showUltra {
+ // Active search: q/esc clears the search filter first, same as in
+ // normal table mode. Only proceed to exit/quit when no search is active.
+ if m.ultraSearchRegex != nil {
+ m.ultraSearchRegex = nil
+ m.ultraFiltered = nil
+ m.ultraCursor = 0
+ m.ultraOffset = 0
+ return m, nil
+ }
// When started via --ultra flag there is no table view to return to,
// so q/esc exits the application directly.
if m.ultraStartup {
@@ -164,8 +173,6 @@ func (m *Model) handleQuitOrEscape() (tea.Model, tea.Cmd) {
}
m.ultraClearFocusedID()
m.showUltra = false
- m.ultraSearchRegex = nil
- m.ultraFiltered = nil
m.ultraSearchInput.SetValue("")
return m, nil
}
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
index 0acbfab..a065ca7 100644
--- a/internal/ui/table_test.go
+++ b/internal/ui/table_test.go
@@ -898,22 +898,30 @@ func TestUltraExitHotkeysClearUltraState(t *testing.T) {
m.ultraSearchInput.SetValue("ultra needle")
m.ultraFocusedID = 17
+ // First q clears the active search but stays in ultra mode.
mv, cmd = (&m).Update(tea.KeyPressMsg{Code: 'q', Text: "q"})
if cmd != nil {
- t.Fatalf("q in ultra mode unexpectedly returned a command")
+ t.Fatalf("q with active search unexpectedly returned a command")
}
m = *mv.(*Model)
- if m.showUltra {
- t.Fatalf("q did not exit ultra mode")
+ if !m.showUltra {
+ t.Fatalf("q with active search should stay in ultra mode")
}
if m.ultraSearchRegex != nil {
- t.Fatalf("q did not clear ultraSearchRegex")
+ t.Fatalf("first q did not clear ultraSearchRegex")
}
if m.ultraFiltered != nil {
- t.Fatalf("q did not clear ultraFiltered")
+ t.Fatalf("first q did not clear ultraFiltered")
}
- if got := m.ultraSearchInput.Value(); got != "" {
- t.Fatalf("q did not clear ultraSearchInput, got %q", got)
+
+ // Second q (no active search) exits ultra mode.
+ mv, cmd = (&m).Update(tea.KeyPressMsg{Code: 'q', Text: "q"})
+ if cmd != nil {
+ t.Fatalf("q in ultra mode (no search) unexpectedly returned a command")
+ }
+ m = *mv.(*Model)
+ if m.showUltra {
+ t.Fatalf("second q did not exit ultra mode")
}
if m.ultraFocusedID != 0 {
t.Fatalf("q did not clear ultraFocusedID, got %d", m.ultraFocusedID)
@@ -929,22 +937,30 @@ func TestUltraExitHotkeysClearUltraState(t *testing.T) {
m.ultraFiltered = []int{2}
m.ultraSearchInput.SetValue("second needle")
+ // First esc clears the active search, stays in ultra.
mv, cmd = (&m).Update(tea.KeyPressMsg{Code: tea.KeyEsc})
if cmd != nil {
- t.Fatalf("esc in ultra mode unexpectedly returned a command")
+ t.Fatalf("esc with active search unexpectedly returned a command")
}
m = *mv.(*Model)
- if m.showUltra {
- t.Fatalf("esc did not exit ultra mode")
+ if !m.showUltra {
+ t.Fatalf("esc with active search should stay in ultra mode")
}
if m.ultraSearchRegex != nil {
- t.Fatalf("esc did not clear ultraSearchRegex")
+ t.Fatalf("first esc did not clear ultraSearchRegex")
}
if m.ultraFiltered != nil {
- t.Fatalf("esc did not clear ultraFiltered")
+ t.Fatalf("first esc did not clear ultraFiltered")
+ }
+
+ // Second esc (no active search) exits ultra mode.
+ mv, cmd = (&m).Update(tea.KeyPressMsg{Code: tea.KeyEsc})
+ if cmd != nil {
+ t.Fatalf("esc in ultra mode (no search) unexpectedly returned a command")
}
- if got := m.ultraSearchInput.Value(); got != "" {
- t.Fatalf("esc did not clear ultraSearchInput, got %q", got)
+ m = *mv.(*Model)
+ if m.showUltra {
+ t.Fatalf("second esc did not exit ultra mode")
}
if m.ultraFocusedID != 0 {
t.Fatalf("esc did not clear ultraFocusedID, got %d", m.ultraFocusedID)
diff --git a/internal/ui/ultra.go b/internal/ui/ultra.go
index 9fccc0c..e2ad3e9 100644
--- a/internal/ui/ultra.go
+++ b/internal/ui/ultra.go
@@ -654,7 +654,12 @@ func (m *Model) renderUltraHeaderWithRegex(t task.Task, width int, re *regexp.Re
sep := ultraFieldSep(bg)
id := m.ultraStyledText(re, lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("253")), idText, bg)
- priority := m.ultraStyledText(re, ultraPriorityStyle(m.theme, t.Priority), priorityText, "") // priority badge keeps its own bg
+ // H/M/L badges keep their own coloured background; plain "-" uses the card bg.
+ priorityBG := bg
+ if t.Priority == "H" || t.Priority == "M" || t.Priority == "L" {
+ priorityBG = ""
+ }
+ priority := m.ultraStyledText(re, ultraPriorityStyle(m.theme, t.Priority), priorityText, priorityBG)
status := m.ultraStyledText(re, lipgloss.NewStyle().Foreground(lipgloss.Color("246")), statusText, bg)
urgency := m.ultraStyledText(re, lipgloss.NewStyle().Foreground(lipgloss.Color("214")), urgencyText, bg)
age := m.ultraStyledText(re, lipgloss.NewStyle().Foreground(lipgloss.Color("240")), ageText, bg)