From c234be24815452fa1143c9a523f4615e0d745fb7 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 18 Mar 2026 09:29:33 +0200 Subject: refactor: extract keyboardState, filterState, processState sub-structs from tui.Model (task 429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tui.Model had 33 fields mixing keyboard tracking, filter chain, process selection, and UI presentation concerns (SRP violation). Extract three focused sub-structs: - keyboardState (kb): enhancements, lastEvent{ID,At,WasPress}, suppress{ID,Until} — 7 fields managed by keys_normalize.go - filterState (filter): global filter, history slice, label stack — 3 fields for the trace filter chain - processState (proc): pid, tid, pickerReturn — 3 fields for PID/TID selection and picker navigation Model drops from 33 to 23 top-level fields. All field accesses in tui.go, keys_normalize.go, and tui_test.go are updated accordingly. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- internal/tui/keys_normalize.go | 24 +++---- internal/tui/tui.go | 139 +++++++++++++++++++++++------------------ internal/tui/tui_test.go | 100 ++++++++++++++--------------- 3 files changed, 140 insertions(+), 123 deletions(-) diff --git a/internal/tui/keys_normalize.go b/internal/tui/keys_normalize.go index 173847e..777749b 100644 --- a/internal/tui/keys_normalize.go +++ b/internal/tui/keys_normalize.go @@ -19,9 +19,9 @@ func (m *Model) normalizeKeyEvent(msg tea.Msg) (tea.Msg, bool) { case tea.KeyReleaseMsg: pressMsg := tea.KeyPressMsg(keyMsg) keyID := keyEventID(pressMsg) - if m.lastKeyEventWasPress && keyID != "" && keyID == m.lastKeyEventID && time.Since(m.lastKeyEventAt) <= 500*time.Millisecond { + if m.kb.lastEventWasPress && keyID != "" && keyID == m.kb.lastEventID && time.Since(m.kb.lastEventAt) <= 500*time.Millisecond { // Some terminals emit both press+release; avoid handling release as a duplicate. - m.lastKeyEventWasPress = false + m.kb.lastEventWasPress = false return nil, false } if !releaseHasIdentity(pressMsg) { @@ -41,14 +41,14 @@ func (m *Model) normalizeKeyEvent(msg tea.Msg) (tea.Msg, bool) { } func (m *Model) shouldSuppressPress(keyID string) bool { - if m.suppressPressKeyID == "" { + if m.kb.suppressID == "" { return false } - if time.Now().After(m.suppressPressUntil) { + if time.Now().After(m.kb.suppressUntil) { m.clearPressSuppression() return false } - if keyID == "" || keyID != m.suppressPressKeyID { + if keyID == "" || keyID != m.kb.suppressID { return false } m.clearPressSuppression() @@ -60,19 +60,19 @@ func (m *Model) armPressSuppression(keyID string) { return } // Keep this short so fast repeated key presses still work naturally. - m.suppressPressKeyID = keyID - m.suppressPressUntil = time.Now().Add(60 * time.Millisecond) + m.kb.suppressID = keyID + m.kb.suppressUntil = time.Now().Add(60 * time.Millisecond) } func (m *Model) clearPressSuppression() { - m.suppressPressKeyID = "" - m.suppressPressUntil = time.Time{} + m.kb.suppressID = "" + m.kb.suppressUntil = time.Time{} } func (m *Model) recordKeyEvent(msg tea.KeyPressMsg, wasPress bool) { - m.lastKeyEventID = keyEventID(msg) - m.lastKeyEventAt = time.Now() - m.lastKeyEventWasPress = wasPress + m.kb.lastEventID = keyEventID(msg) + m.kb.lastEventAt = time.Now() + m.kb.lastEventWasPress = wasPress } func keyEventID(msg tea.KeyPressMsg) string { diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 252e722..3a866e5 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -270,6 +270,37 @@ func RunTestFlamesWithTraceStarterConfig(cfg flags.Config, starter TraceStarter) return err } +// keyboardState groups keyboard event tracking and press-suppression fields. +// These fields are read and written exclusively by keys_normalize.go methods. +type keyboardState struct { + enhancements tea.KeyboardEnhancementsMsg + enhancementsKnown bool + lastEventID string + lastEventAt time.Time + lastEventWasPress bool + // Some terminals emit release+press for a single physical key event. + // When we fallback-handle a release as a press, suppress the immediate + // matching press to avoid double-handling. + suppressID string + suppressUntil time.Time +} + +// filterState groups the trace filter chain: the active filter, the undo +// history, and the human-readable label stack used in the status bar. +type filterState struct { + global globalfilter.Filter + history []globalfilter.Filter + stack []string +} + +// processState groups PID/TID filter values and the picker navigation +// return bookmark used to restore the dashboard after re-selecting a process. +type processState struct { + pid int + tid int + pickerReturn *pickerReturnState +} + // Model is the top-level Bubble Tea model that routes between PID picker and dashboard. type Model struct { screen Screen @@ -296,27 +327,13 @@ type Model struct { startTrace TraceStarter traceStop context.CancelFunc - pidFilter int - tidFilter int - globalFilter globalfilter.Filter - filterHistory []globalfilter.Filter - filterStack []string - pickerReturn *pickerReturnState + kb keyboardState + filter filterState + proc processState + exportEnabled bool isDark bool focused bool - - keyboardEnhancements tea.KeyboardEnhancementsMsg - keyboardEnhancementsKnown bool - - lastKeyEventID string - lastKeyEventAt time.Time - lastKeyEventWasPress bool - // Some terminals emit release+press for a single physical key event. - // When we fallback-handle a release as a press, suppress the immediate - // matching press to avoid double-handling. - suppressPressKeyID string - suppressPressUntil time.Time } type pickerReturnState struct { @@ -374,7 +391,7 @@ func newModelWithRuntimeConfig(initialPID int, startupFilter globalfilter.Filter keys: keys, spin: spin, startTrace: startTrace, - globalFilter: startupFilter.Clone(), + filter: filterState{global: startupFilter.Clone()}, exportEnabled: exportEnabled, isDark: true, focused: true, @@ -422,8 +439,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.applyTheme(msg.IsDark()) return m, nil case tea.KeyboardEnhancementsMsg: - m.keyboardEnhancements = msg - m.keyboardEnhancementsKnown = true + m.kb.enhancements = msg + m.kb.enhancementsKnown = true if msg.SupportsKeyDisambiguation() { log.Printf("tui: keyboard enhancements enabled (flags=%d, eventTypes=%t)", msg.Flags, msg.SupportsEventTypes()) } @@ -470,7 +487,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.attaching = false m.dashboard.SetStreamSource(m.runtime.eventStreamSource()) m.dashboard.SetLiveTrie(m.runtime.liveTrie()) - m.dashboard.SetGlobalFilter(m.globalFilter) + m.dashboard.SetGlobalFilter(m.filter.global) m.syncDashboardFilterState() width, height := common.EffectiveViewport(m.width, m.height) next, sizeCmd := m.dashboard.Update(tea.WindowSizeMsg{Width: width, Height: height}) @@ -510,7 +527,7 @@ func (m Model) canHandleDashboardShortcut(msg tea.KeyPressMsg) bool { func (m Model) shouldCancelPickerToDashboard(msg tea.KeyPressMsg) bool { return m.screen == ScreenPIDPicker && - m.pickerReturn != nil && + m.proc.pickerReturn != nil && (isEscKey(msg) || key.Matches(msg, m.keys.Quit)) } @@ -590,7 +607,7 @@ func (m Model) handleGlobalKeyPress(msg tea.KeyPressMsg) (tea.Model, tea.Cmd, bo return m, nil, true } if m.canHandleDashboardShortcut(msg) && key.Matches(msg, m.keys.Filter) { - m.filterModal = m.filterModal.Open(m.globalFilter) + m.filterModal = m.filterModal.Open(m.filter.global) return m, nil, true } if m.canHandleDashboardShortcut(msg) && key.Matches(msg, m.keys.FilterUndo) { @@ -709,7 +726,7 @@ func (m Model) handlePidSelected(msg PidSelectedMsg) (tea.Model, tea.Cmd) { m.stopTrace() m.runtime.resetStreamBuffer() m.setProcessFilters(pid, -1) - m.pickerReturn = nil + m.proc.pickerReturn = nil m.screen = ScreenDashboard m.attaching = true m.lastErr = nil @@ -718,7 +735,7 @@ func (m Model) handlePidSelected(msg PidSelectedMsg) (tea.Model, tea.Cmd) { func (m Model) handleTidSelected(msg TidSelectedMsg) (tea.Model, tea.Cmd) { tid := selectedPIDFilter(msg.Tid) - pid := m.pidFilter + pid := m.proc.pid if msg.Pid > 0 { pid = msg.Pid } @@ -729,7 +746,7 @@ func (m Model) handleTidSelected(msg TidSelectedMsg) (tea.Model, tea.Cmd) { m.stopTrace() m.runtime.resetStreamBuffer() m.setProcessFilters(pid, tid) - m.pickerReturn = nil + m.proc.pickerReturn = nil m.screen = ScreenDashboard m.attaching = true m.lastErr = nil @@ -741,9 +758,9 @@ func (m Model) reselectPID() (tea.Model, tea.Cmd) { m.lastErr = err return m, nil } - m.pickerReturn = &pickerReturnState{ - pidFilter: m.pidFilter, - tidFilter: m.tidFilter, + m.proc.pickerReturn = &pickerReturnState{ + pidFilter: m.proc.pid, + tidFilter: m.proc.tid, } m.stopTrace() m.screen = ScreenPIDPicker @@ -766,15 +783,15 @@ func (m Model) reselectPID() (tea.Model, tea.Cmd) { } func (m Model) reselectTID() (tea.Model, tea.Cmd) { - pid := m.pidFilter + pid := m.proc.pid if err := m.stopRecording(); err != nil { m.lastErr = err return m, nil } - m.pickerReturn = &pickerReturnState{ - pidFilter: m.pidFilter, - tidFilter: m.tidFilter, + m.proc.pickerReturn = &pickerReturnState{ + pidFilter: m.proc.pid, + tidFilter: m.proc.tid, } m.stopTrace() m.screen = ScreenPIDPicker @@ -804,15 +821,15 @@ func selectedPIDFilter(pid int) int { } func (m Model) cancelPickerToDashboard() (tea.Model, tea.Cmd) { - if m.pickerReturn == nil { + if m.proc.pickerReturn == nil { return m, nil } if err := m.stopRecording(); err != nil { m.lastErr = err return m, nil } - returnState := *m.pickerReturn - m.pickerReturn = nil + returnState := *m.proc.pickerReturn + m.proc.pickerReturn = nil m.stopTrace() m.setProcessFilters(returnState.pidFilter, returnState.tidFilter) m.screen = ScreenDashboard @@ -825,7 +842,7 @@ func (m *Model) beginTraceCmd() tea.Cmd { ctx, cancel := context.WithCancel(context.Background()) m.traceStop = cancel ctx = ContextWithRuntimeBindings(ctx, m.runtime) - ctx = ContextWithTraceFilters(ctx, m.globalFilter) + ctx = ContextWithTraceFilters(ctx, m.filter.global) return startTraceCmd(m.startTrace, ctx) } @@ -851,30 +868,30 @@ func filterFromConfig(cfg flags.Config) globalfilter.Filter { } func (m *Model) setProcessFilters(pid, tid int) { - m.pidFilter = pid - m.tidFilter = tid - m.globalFilter = applyProcessFilters(m.globalFilter, pid, tid) - for i := range m.filterHistory { - m.filterHistory[i] = applyProcessFilters(m.filterHistory[i], pid, tid) + m.proc.pid = pid + m.proc.tid = tid + m.filter.global = applyProcessFilters(m.filter.global, pid, tid) + for i := range m.filter.history { + m.filter.history[i] = applyProcessFilters(m.filter.history[i], pid, tid) } m.syncDashboardFilterState() } func (m *Model) setGlobalFilter(filter globalfilter.Filter) { - m.globalFilter = filter.Clone() + m.filter.global = filter.Clone() // EqValue returns (0, false) when no equality filter is set; // selectedPIDFilter maps non-positive values to -1 ("no filter"). - pid, _ := m.globalFilter.PID.EqValue() - tid, _ := m.globalFilter.TID.EqValue() - m.pidFilter = selectedPIDFilter(pid) - m.tidFilter = selectedPIDFilter(tid) + pid, _ := m.filter.global.PID.EqValue() + tid, _ := m.filter.global.TID.EqValue() + m.proc.pid = selectedPIDFilter(pid) + m.proc.tid = selectedPIDFilter(tid) m.syncDashboardFilterState() } func (m *Model) syncDashboardFilterState() { - m.dashboard.SetPidFilter(m.pidFilter) - m.dashboard.SetGlobalFilter(m.globalFilter) - m.dashboard.SetFilterStack(m.filterStack) + m.dashboard.SetPidFilter(m.proc.pid) + m.dashboard.SetGlobalFilter(m.filter.global) + m.dashboard.SetFilterStack(m.filter.stack) m.dashboard.SetRecordingStatus(m.recordingStatus()) } @@ -887,10 +904,10 @@ func applyProcessFilters(filter globalfilter.Filter, pid, tid int) globalfilter. func (m Model) applyGlobalFilter(filter globalfilter.Filter, action string) (tea.Model, tea.Cmd) { nextFilter := filter.Clone() - changed := !m.globalFilter.Equal(nextFilter) + changed := !m.filter.global.Equal(nextFilter) if changed { - m.filterHistory = append(m.filterHistory, m.globalFilter.Clone()) - m.filterStack = append(m.filterStack, globalFilterActionLabel(m.globalFilter, nextFilter, action)) + m.filter.history = append(m.filter.history, m.filter.global.Clone()) + m.filter.stack = append(m.filter.stack, globalFilterActionLabel(m.filter.global, nextFilter, action)) } m.setGlobalFilter(nextFilter) if !changed || m.screen != ScreenDashboard { @@ -906,13 +923,13 @@ func (m Model) applyGlobalFilter(filter globalfilter.Filter, action string) (tea } func (m Model) undoGlobalFilter() (tea.Model, tea.Cmd) { - if len(m.filterHistory) == 0 { + if len(m.filter.history) == 0 { return m, nil } - prev := m.filterHistory[len(m.filterHistory)-1] - m.filterHistory = m.filterHistory[:len(m.filterHistory)-1] - if len(m.filterStack) > 0 { - m.filterStack = m.filterStack[:len(m.filterStack)-1] + prev := m.filter.history[len(m.filter.history)-1] + m.filter.history = m.filter.history[:len(m.filter.history)-1] + if len(m.filter.stack) > 0 { + m.filter.stack = m.filter.stack[:len(m.filter.stack)-1] } m.setGlobalFilter(prev) if m.screen != ScreenDashboard { @@ -1022,8 +1039,8 @@ func (m Model) windowTitle() string { case ScreenPIDPicker: return "ior - select process" case ScreenDashboard: - if m.pidFilter > 0 { - return fmt.Sprintf("ior - tracing PID %d", m.pidFilter) + if m.proc.pid > 0 { + return fmt.Sprintf("ior - tracing PID %d", m.proc.pid) } } return "ior - I/O Riot" diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go index 7f43961..27bf041 100644 --- a/internal/tui/tui_test.go +++ b/internal/tui/tui_test.go @@ -102,11 +102,11 @@ func TestPidSelectedTransitionsToDashboardAndSetsPIDFilter(t *testing.T) { if !updated.attaching { t.Fatalf("expected attaching state to be true") } - if updated.pidFilter != 42 { - t.Fatalf("expected pid filter 42, got %d", updated.pidFilter) + if updated.proc.pid != 42 { + t.Fatalf("expected pid filter 42, got %d", updated.proc.pid) } - if updated.tidFilter != -1 { - t.Fatalf("expected tid filter reset to -1, got %d", updated.tidFilter) + if updated.proc.tid != -1 { + t.Fatalf("expected tid filter reset to -1, got %d", updated.proc.tid) } } @@ -129,8 +129,8 @@ func TestPidSelectedAllSetsNoFilter(t *testing.T) { next, _ := m.Update(PidSelectedMsg{Pid: 0}) updated := next.(Model) - if updated.pidFilter != -1 { - t.Fatalf("expected pid filter -1 for all pids, got %d", updated.pidFilter) + if updated.proc.pid != -1 { + t.Fatalf("expected pid filter -1 for all pids, got %d", updated.proc.pid) } } @@ -264,8 +264,8 @@ func TestQuitKeyOnReselectPIDPickerReturnsToDashboardLikeEsc(t *testing.T) { m.attaching = false m.width = 120 m.height = 30 - m.pidFilter = 1111 - m.tidFilter = 2222 + m.proc.pid = 1111 + m.proc.tid = 2222 m.dashboard.SetPidFilter(1111) next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'2'}[0], Text: string([]rune{'2'})}) @@ -291,11 +291,11 @@ func TestQuitKeyOnReselectPIDPickerReturnsToDashboardLikeEsc(t *testing.T) { if updated.quitting { t.Fatalf("expected q in reselect picker to behave like esc, not quit") } - if updated.pickerReturn != nil { + if updated.proc.pickerReturn != nil { t.Fatalf("expected picker return context to clear after cancel") } - if updated.pidFilter != 1111 || updated.tidFilter != 2222 { - t.Fatalf("expected previous pid/tid filters restored, got pid=%d tid=%d", updated.pidFilter, updated.tidFilter) + if updated.proc.pid != 1111 || updated.proc.tid != 2222 { + t.Fatalf("expected previous pid/tid filters restored, got pid=%d tid=%d", updated.proc.pid, updated.proc.tid) } } @@ -305,8 +305,8 @@ func TestEscOnReselectPIDPickerReturnsToDashboard(t *testing.T) { m.attaching = false m.width = 120 m.height = 30 - m.pidFilter = 3333 - m.tidFilter = 4444 + m.proc.pid = 3333 + m.proc.tid = 4444 m.dashboard.SetPidFilter(3333) next, _ := m.Update(tea.KeyPressMsg{Code: []rune{'2'}[0], Text: string([]rune{'2'})}) @@ -332,11 +332,11 @@ func TestEscOnReselectPIDPickerReturnsToDashboard(t *testing.T) { if updated.quitting { t.Fatalf("expected esc in reselect picker not to quit app") } - if updated.pickerReturn != nil { + if updated.proc.pickerReturn != nil { t.Fatalf("expected picker return context to clear after cancel") } - if updated.pidFilter != 3333 || updated.tidFilter != 4444 { - t.Fatalf("expected previous pid/tid filters restored, got pid=%d tid=%d", updated.pidFilter, updated.tidFilter) + if updated.proc.pid != 3333 || updated.proc.tid != 4444 { + t.Fatalf("expected previous pid/tid filters restored, got pid=%d tid=%d", updated.proc.pid, updated.proc.tid) } } @@ -993,7 +993,7 @@ func TestNormalizeKeyEventReleaseFallbackSuppressesImmediatePressOnly(t *testing } // Expire suppression deterministically instead of waiting on wall clock time. - m.suppressPressUntil = time.Now().Add(-time.Nanosecond) + m.kb.suppressUntil = time.Now().Add(-time.Nanosecond) if normalized, ok = m.normalizeKeyEvent(tea.KeyPressMsg{Code: tea.KeySpace, Text: " "}); !ok { t.Fatalf("expected press to be accepted after suppression window") } @@ -1180,11 +1180,11 @@ func TestTidSelectedTransitionsToDashboardAndSetsTIDFilter(t *testing.T) { if !updated.attaching { t.Fatalf("expected attaching state to be true") } - if updated.tidFilter != 3333 { - t.Fatalf("expected tid filter 3333, got %d", updated.tidFilter) + if updated.proc.tid != 3333 { + t.Fatalf("expected tid filter 3333, got %d", updated.proc.tid) } - if updated.pidFilter != 2222 { - t.Fatalf("expected pid filter to remain 2222, got %d", updated.pidFilter) + if updated.proc.pid != 2222 { + t.Fatalf("expected pid filter to remain 2222, got %d", updated.proc.pid) } } @@ -1199,11 +1199,11 @@ func TestTidSelectedFromAllPIDModeSetsOwningPID(t *testing.T) { if updated.screen != ScreenDashboard { t.Fatalf("expected dashboard screen, got %v", updated.screen) } - if updated.pidFilter != 4444 { - t.Fatalf("expected pid filter switched to owning pid 4444, got %d", updated.pidFilter) + if updated.proc.pid != 4444 { + t.Fatalf("expected pid filter switched to owning pid 4444, got %d", updated.proc.pid) } - if updated.tidFilter != 5555 { - t.Fatalf("expected tid filter 5555, got %d", updated.tidFilter) + if updated.proc.tid != 5555 { + t.Fatalf("expected tid filter 5555, got %d", updated.proc.tid) } } @@ -1245,8 +1245,8 @@ func TestStreamFilterModalConsumesEKeyInsteadOfOpeningExport(t *testing.T) { if m.exporter.Visible() { t.Fatalf("expected export modal to remain closed while stream filter modal handles typing") } - if m.globalFilter.Syscall == nil || m.globalFilter.Syscall.Pattern != "ope" { - t.Fatalf("expected typed syscall filter to be stored globally, got %+v", m.globalFilter.Syscall) + if m.filter.global.Syscall == nil || m.filter.global.Syscall.Pattern != "ope" { + t.Fatalf("expected typed syscall filter to be stored globally, got %+v", m.filter.global.Syscall) } } @@ -1416,7 +1416,7 @@ func TestGlobalFilterModalOpensFromDashboardShortcut(t *testing.T) { func TestQuitClosesGlobalFilterModalWithoutQuitting(t *testing.T) { m := NewModel(-1, func(context.Context) error { return nil }) m.screen = ScreenDashboard - m.filterModal = m.filterModal.Open(m.globalFilter) + m.filterModal = m.filterModal.Open(m.filter.global) next, cmd := m.Update(tea.KeyPressMsg{Code: []rune{'q'}[0], Text: string([]rune{'q'})}) m = next.(Model) @@ -1455,8 +1455,8 @@ func TestGlobalFilterModalUpdatesStoredFilterState(t *testing.T) { if m.filterModal.Visible() { t.Fatalf("expected global filter modal to close after esc") } - if m.globalFilter.Syscall == nil || m.globalFilter.Syscall.Pattern != "read" { - t.Fatalf("expected stored global filter updated from modal, got %+v", m.globalFilter.Syscall) + if m.filter.global.Syscall == nil || m.filter.global.Syscall.Pattern != "read" { + t.Fatalf("expected stored global filter updated from modal, got %+v", m.filter.global.Syscall) } if !stopped { t.Fatalf("expected filter apply to stop the active trace") @@ -1540,8 +1540,8 @@ func TestPausedStreamEnterAppliesSelectedCellAsGlobalFilter(t *testing.T) { if cmd == nil { t.Fatalf("expected applying selected-cell global filter to restart tracing") } - if m.globalFilter.Comm == nil || m.globalFilter.Comm.Pattern != "systemd" { - t.Fatalf("expected selected comm applied globally, got %+v", m.globalFilter.Comm) + if m.filter.global.Comm == nil || m.filter.global.Comm.Pattern != "systemd" { + t.Fatalf("expected selected comm applied globally, got %+v", m.filter.global.Comm) } if !stopped { t.Fatalf("expected selected-cell global filter to stop the active trace") @@ -1549,8 +1549,8 @@ func TestPausedStreamEnterAppliesSelectedCellAsGlobalFilter(t *testing.T) { if !m.attaching { t.Fatalf("expected selected-cell global filter to restart tracing") } - if len(m.filterStack) != 1 || m.filterStack[0] != "comm~systemd" { - t.Fatalf("expected selected-cell action pushed to filter stack, got %+v", m.filterStack) + if len(m.filter.stack) != 1 || m.filter.stack[0] != "comm~systemd" { + t.Fatalf("expected selected-cell action pushed to filter stack, got %+v", m.filter.stack) } } @@ -1577,11 +1577,11 @@ func TestGlobalFilterUndoKeyPopsLatestStackEntry(t *testing.T) { if cmd == nil { t.Fatalf("expected F to trigger global filter undo") } - if m.globalFilter.IsActive() { - t.Fatalf("expected undo to restore the previous all-filter state, got %+v", m.globalFilter) + if m.filter.global.IsActive() { + t.Fatalf("expected undo to restore the previous all-filter state, got %+v", m.filter.global) } - if len(m.filterStack) != 0 || len(m.filterHistory) != 0 { - t.Fatalf("expected filter stack/history cleared after undo, got stack=%+v history=%d", m.filterStack, len(m.filterHistory)) + if len(m.filter.stack) != 0 || len(m.filter.history) != 0 { + t.Fatalf("expected filter stack/history cleared after undo, got stack=%+v history=%d", m.filter.stack, len(m.filter.history)) } if !stopped { t.Fatalf("expected undo to stop the active trace") @@ -1631,11 +1631,11 @@ func TestPausedStreamEscUndoesLatestGlobalFilter(t *testing.T) { if cmd == nil { t.Fatalf("expected esc undo to restart tracing") } - if m.globalFilter.IsActive() { - t.Fatalf("expected esc undo to restore all-filter state, got %+v", m.globalFilter) + if m.filter.global.IsActive() { + t.Fatalf("expected esc undo to restore all-filter state, got %+v", m.filter.global) } - if len(m.filterStack) != 0 { - t.Fatalf("expected filter stack cleared after esc undo, got %+v", m.filterStack) + if len(m.filter.stack) != 0 { + t.Fatalf("expected filter stack cleared after esc undo, got %+v", m.filter.stack) } if !stopped { t.Fatalf("expected esc undo to stop the active trace") @@ -1706,11 +1706,11 @@ func TestProcessesTabEnterAppliesSelectedProcessAsGlobalFilter(t *testing.T) { if cmd == nil { t.Fatalf("expected selected process filter to restart tracing") } - if m.globalFilter.PID == nil || m.globalFilter.PID.Value != 222 { - t.Fatalf("expected selected process pid applied globally, got %+v", m.globalFilter.PID) + if m.filter.global.PID == nil || m.filter.global.PID.Value != 222 { + t.Fatalf("expected selected process pid applied globally, got %+v", m.filter.global.PID) } - if len(m.filterStack) != 1 || m.filterStack[0] != "pid=222" { - t.Fatalf("expected pid filter pushed to stack, got %+v", m.filterStack) + if len(m.filter.stack) != 1 || m.filter.stack[0] != "pid=222" { + t.Fatalf("expected pid filter pushed to stack, got %+v", m.filter.stack) } if !stopped { t.Fatalf("expected selected process filter to stop the active trace") @@ -2051,10 +2051,10 @@ func TestKeyboardEnhancementsMsgHandledGracefully(t *testing.T) { } updated := next.(Model) - if !updated.keyboardEnhancementsKnown { + if !updated.kb.enhancementsKnown { t.Fatalf("expected keyboard enhancements to be marked as known") } - if !updated.keyboardEnhancements.SupportsKeyDisambiguation() { + if !updated.kb.enhancements.SupportsKeyDisambiguation() { t.Fatalf("expected non-zero flags to report key disambiguation support") } } @@ -2069,13 +2069,13 @@ func TestViewSetsDynamicWindowTitle(t *testing.T) { } m.screen = ScreenDashboard - m.pidFilter = 1234 + m.proc.pid = 1234 view = m.View() if view.WindowTitle != "ior - tracing PID 1234" { t.Fatalf("unexpected tracing window title: %q", view.WindowTitle) } - m.pidFilter = -1 + m.proc.pid = -1 view = m.View() if view.WindowTitle != "ior - I/O Riot" { t.Fatalf("unexpected default window title: %q", view.WindowTitle) -- cgit v1.2.3