summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/ui/ultra.go64
1 files changed, 48 insertions, 16 deletions
diff --git a/internal/ui/ultra.go b/internal/ui/ultra.go
index e2ad3e9..16c1a2c 100644
--- a/internal/ui/ultra.go
+++ b/internal/ui/ultra.go
@@ -460,34 +460,66 @@ func (m *Model) ultraFilteredIndexes(re *regexp.Regexp) []int {
return indexes
}
+// handleUltraSearchMode handles keystrokes while the ultra search input is open.
+// Results are filtered live on every keystroke; Enter confirms (keeps the
+// filter, closes the input); Esc cancels (clears the filter, closes the input).
+// The search term is treated as a regular expression.
func (m *Model) handleUltraSearchMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
- onEnter := func(value string) error {
- if value == "" {
+ switch msg.String() {
+ case "enter":
+ // Empty input clears the filter; non-empty confirms and keeps it.
+ if strings.TrimSpace(m.ultraSearchInput.Value()) == "" {
m.ultraSearchRegex = nil
m.ultraFiltered = nil
m.ultraCursor = 0
m.ultraOffset = 0
- return nil
}
+ m.ultraSearching = false
+ m.ultraSearchInput.Blur()
+ return m, nil
+ case "esc":
+ // Cancel: clear the filter and close the search input.
+ m.ultraSearching = false
+ m.ultraSearchInput.SetValue("")
+ m.ultraSearchInput.Blur()
+ m.ultraSearchRegex = nil
+ m.ultraFiltered = nil
+ m.ultraCursor = 0
+ m.ultraOffset = 0
+ return m, nil
+ }
- re, err := compileAndCacheRegex(value)
- if err != nil {
- return err
- }
+ // Forward the keystroke to the text input widget.
+ var cmd tea.Cmd
+ m.ultraSearchInput, cmd = m.ultraSearchInput.Update(msg)
+
+ // Recompile and refilter on every change for live results.
+ m.ultraApplySearch(m.ultraSearchInput.Value())
+ return m, cmd
+}
- m.ultraSearchRegex = re
- m.ultraFiltered = m.ultraFilteredIndexes(re)
+// ultraApplySearch compiles value as a regex and updates the filtered task
+// index. If value is empty the filter is cleared. If the regex is invalid
+// (e.g. mid-typing an incomplete pattern) the existing filter is left
+// unchanged so the display does not flicker.
+func (m *Model) ultraApplySearch(value string) {
+ value = strings.TrimSpace(value)
+ if value == "" {
+ m.ultraSearchRegex = nil
+ m.ultraFiltered = nil
m.ultraCursor = 0
m.ultraOffset = 0
- return nil
+ return
}
-
- onExit := func() {
- m.ultraSearching = false
- m.ultraSearchInput.SetValue("")
+ re, err := compileAndCacheRegex(value)
+ if err != nil {
+ // Keep the previous filter while the regex is incomplete.
+ return
}
-
- return m.handleTextInput(msg, &m.ultraSearchInput, onEnter, onExit)
+ m.ultraSearchRegex = re
+ m.ultraFiltered = m.ultraFilteredIndexes(re)
+ m.ultraCursor = 0
+ m.ultraOffset = 0
}
func (m *Model) ultraMoveSearchMatch(delta int) {