@@ -218,6 +218,9 @@ interface TabState {
218218 filteredLineNumbers: number[] | null;
219219 activeLevelFilter: string | null;
220220 appliedFilterSuggestion: { id: string; title: string } | null;
221+ // Filter suspension — config preserved, view temporarily shows all lines
222+ lastFilterConfig: FilterConfig | null;
223+ filterSuspended: 'auto' | 'manual' | null; // 'auto'=navigation triggered, 'manual'=user toggled
221224}
222225
223226// Per-connection state for Live panel
@@ -249,6 +252,8 @@ interface AppState {
249252 isFiltered: boolean;
250253 activeLevelFilter: string | null;
251254 appliedFilterSuggestion: { id: string; title: string } | null;
255+ lastFilterConfig: FilterConfig | null;
256+ filterSuspended: 'auto' | 'manual' | null;
252257 searchResults: SearchResult[];
253258 currentSearchIndex: number;
254259 hiddenSearchMatches: HiddenMatch[];
@@ -326,6 +331,8 @@ const state: AppState = {
326331 isFiltered: false,
327332 activeLevelFilter: null,
328333 appliedFilterSuggestion: null,
334+ lastFilterConfig: null,
335+ filterSuspended: null,
329336 searchResults: [],
330337 currentSearchIndex: -1,
331338 hiddenSearchMatches: [],
@@ -4759,18 +4766,18 @@ function renderFolderSearchResults(pattern: string, cancelled?: boolean): void {
47594766
47604767 const absLine = match.lineNumber - 1; // ripgrep is 1-based → 0-based
47614768
4762- // Same file already open in current tab — just clear filter and navigate
4769+ // Same file already open in current tab — suspend filter and navigate
47634770 if (match.filePath === state.filePath) {
4764- if (state.isFiltered) await clearFilter( );
4771+ if (state.isFiltered) await suspendFilter('auto' );
47654772 await navigateTo(absLine);
47664773 return;
47674774 }
47684775
4769- // File open in another tab — switch to it, clear any restored filter, navigate
4776+ // File open in another tab — switch to it, suspend any restored filter, navigate
47704777 const existingTab = findTabByFilePath(match.filePath);
47714778 if (existingTab) {
47724779 await switchToTab(existingTab.id);
4773- if (state.isFiltered) await clearFilter( );
4780+ if (state.isFiltered) await suspendFilter('auto' );
47744781 await navigateTo(absLine);
47754782 return;
47764783 }
@@ -10514,6 +10521,8 @@ async function applyFilter(providedConfig?: FilterConfig): Promise<void> {
1051410521 state.isFiltered = true;
1051510522 state.filteredLines = result.stats.filteredLines;
1051610523 state.filteredLineNumbers = result.filteredLineNumbers ?? null;
10524+ state.lastFilterConfig = config; // remember for suspension/resume
10525+ state.filterSuspended = null; // filter is now actively applied
1051710526 cachedLines.clear();
1051810527
1051910528 // Reset scroll to top of filtered view
@@ -10541,9 +10550,10 @@ async function clearFilter(): Promise<void> {
1054110550 state.filteredLineNumbers = null;
1054210551 state.activeLevelFilter = null;
1054310552 state.appliedFilterSuggestion = null;
10553+ state.lastFilterConfig = null;
10554+ state.filterSuspended = null;
1054410555 cachedLines.clear();
1054510556
10546- // Clear backend filter state
1054710557 await window.api.clearFilter();
1054810558
1054910559 hideFilterModal();
@@ -10552,6 +10562,30 @@ async function clearFilter(): Promise<void> {
1055210562 updateLevelBadgeStyles();
1055310563}
1055410564
10565+ // Suspend: keep config, temporarily show unfiltered view.
10566+ // reason='auto' (navigation) → badge blinks; reason='manual' → badge solid.
10567+ async function suspendFilter(reason: 'auto' | 'manual' = 'auto'): Promise<void> {
10568+ if (!state.isFiltered) return;
10569+ state.filterSuspended = reason;
10570+ state.isFiltered = false;
10571+ state.filteredLines = null;
10572+ state.filteredLineNumbers = null;
10573+ state.activeLevelFilter = null;
10574+ cachedLines.clear();
10575+
10576+ await window.api.clearFilter();
10577+ await loadVisibleLines();
10578+ updateStatusBar();
10579+ updateLevelBadgeStyles();
10580+ }
10581+
10582+ // Resume: re-apply the saved config from before suspension.
10583+ async function resumeFilter(): Promise<void> {
10584+ if (!state.lastFilterConfig) return;
10585+ state.filterSuspended = null;
10586+ await applyFilter(state.lastFilterConfig);
10587+ }
10588+
1055510589async function applyQuickLevelFilter(level: string): Promise<void> {
1055610590 if (!state.analysisResult) return;
1055710591
@@ -10577,6 +10611,8 @@ async function applyQuickLevelFilter(level: string): Promise<void> {
1057710611 state.filteredLines = result.stats.filteredLines;
1057810612 state.filteredLineNumbers = result.filteredLineNumbers ?? null;
1057910613 state.activeLevelFilter = level;
10614+ state.lastFilterConfig = config;
10615+ state.filterSuspended = null;
1058010616 cachedLines.clear();
1058110617
1058210618 // Reset scroll to top of filtered view
@@ -12183,17 +12219,35 @@ function updateStatusBar(): void {
1218312219 elements.statusLines.textContent = `${state.totalLines.toLocaleString()} lines`;
1218412220 elements.statusSize.textContent = formatBytes(state.fileStats?.size || 0);
1218512221
12222+ const badge = elements.statusFiltered;
1218612223 if (state.isFiltered && state.filteredLines !== null) {
12187- elements.statusFiltered.classList.remove('hidden');
12224+ // Active filter
12225+ badge.classList.remove('hidden', 'suspended', 'suspended-auto', 'suspended-manual');
12226+ badge.title = 'Filter active — click to pause, × to clear';
1218812227 elements.filteredCount.textContent = state.filteredLines.toLocaleString();
12228+ const label = badge.querySelector('.status-filter-label') as HTMLElement | null;
12229+ if (label) label.textContent = 'Filtered:';
12230+ } else if (state.filterSuspended && state.lastFilterConfig) {
12231+ // Suspended filter — show badge with different state
12232+ badge.classList.remove('hidden');
12233+ badge.classList.remove('suspended-auto', 'suspended-manual');
12234+ badge.classList.add('suspended', `suspended-${state.filterSuspended}`);
12235+ badge.title = state.filterSuspended === 'auto'
12236+ ? 'Filter paused (navigated to line) — click to re-enable'
12237+ : 'Filter paused — click to re-enable';
12238+ elements.filteredCount.textContent = '';
12239+ const label = badge.querySelector('.status-filter-label') as HTMLElement | null;
12240+ if (label) label.textContent = 'Filter paused';
1218912241 } else {
12190- elements.statusFiltered.classList.add('hidden');
12242+ badge.classList.add('hidden');
12243+ badge.classList.remove('suspended', 'suspended-auto', 'suspended-manual');
1219112244 }
1219212245 } else {
1219312246 elements.statusFile.textContent = 'No file';
1219412247 elements.statusLines.textContent = '0 lines';
1219512248 elements.statusSize.textContent = '0 B';
1219612249 elements.statusFiltered.classList.add('hidden');
12250+ elements.statusFiltered.classList.remove('suspended', 'suspended-auto', 'suspended-manual');
1219712251 }
1219812252}
1219912253
@@ -14097,6 +14151,15 @@ function init(): void {
1409714151 elements.btnFilter.addEventListener('click', showFilterModal);
1409814152 elements.btnApplyFilter.addEventListener('click', () => applyFilter());
1409914153 elements.btnClearFilter.addEventListener('click', clearFilter);
14154+ // Badge body click = toggle suspend/resume; × button = permanent clear
14155+ elements.statusFiltered.addEventListener('click', async (e) => {
14156+ if ((e.target as HTMLElement).id === 'btn-status-clear-filter') return;
14157+ if (state.isFiltered) {
14158+ await suspendFilter('manual');
14159+ } else if (state.filterSuspended && state.lastFilterConfig) {
14160+ await resumeFilter();
14161+ }
14162+ });
1410014163 document.getElementById('btn-status-clear-filter')?.addEventListener('click', clearFilter);
1410114164 elements.btnAddIncludePattern.addEventListener('click', () => addIncludePatternRow());
1410214165
@@ -14660,6 +14723,8 @@ function saveCurrentTabState(): void {
1466014723 filteredLineNumbers: state.filteredLineNumbers,
1466114724 activeLevelFilter: state.activeLevelFilter,
1466214725 appliedFilterSuggestion: state.appliedFilterSuggestion,
14726+ lastFilterConfig: state.lastFilterConfig,
14727+ filterSuspended: state.filterSuspended,
1466314728 };
1466414729}
1466514730
@@ -14686,6 +14751,8 @@ function restoreTabState(tab: TabState): void {
1468614751 state.filteredLineNumbers = tab.filteredLineNumbers;
1468714752 state.activeLevelFilter = tab.activeLevelFilter;
1468814753 state.appliedFilterSuggestion = tab.appliedFilterSuggestion;
14754+ state.lastFilterConfig = tab.lastFilterConfig;
14755+ state.filterSuspended = tab.filterSuspended;
1468914756
1469014757 // Restore cached lines
1469114758 cachedLines.clear();
@@ -14732,6 +14799,8 @@ function createTab(filePath: string): TabState {
1473214799 filteredLineNumbers: null,
1473314800 activeLevelFilter: null,
1473414801 appliedFilterSuggestion: null,
14802+ lastFilterConfig: null,
14803+ filterSuspended: null,
1473514804 };
1473614805 return tab;
1473714806}
0 commit comments