diff --git a/src/vs/workbench/contrib/search/browser/searchActionsTopBar.ts b/src/vs/workbench/contrib/search/browser/searchActionsTopBar.ts index 64aed44242198..8e3fa06a21e7b 100644 --- a/src/vs/workbench/contrib/search/browser/searchActionsTopBar.ts +++ b/src/vs/workbench/contrib/search/browser/searchActionsTopBar.ts @@ -11,7 +11,7 @@ import { IViewsService } from '../../../services/views/common/viewsService.js'; import { searchClearIcon, searchCollapseAllIcon, searchExpandAllIcon, searchRefreshIcon, searchShowAsList, searchShowAsTree, searchStopIcon } from './searchIcons.js'; import * as Constants from '../common/constants.js'; import { ISearchHistoryService } from '../common/searchHistoryService.js'; -import { FileMatch, FolderMatch, FolderMatchNoRoot, FolderMatchWorkspaceRoot, Match, SearchResult } from './searchModel.js'; +import { FileMatch, FolderMatch, FolderMatchNoRoot, FolderMatchWorkspaceRoot, Match, SearchResult, TextSearchResult } from './searchModel.js'; import { VIEW_ID } from '../../../services/search/common/search.js'; import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; @@ -266,8 +266,16 @@ function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { let canCollapseFileMatchLevel = false; let canCollapseFirstLevel = false; + do { + node = navigator.next(); + } while (node instanceof TextSearchResult); + // go to the first non-TextSearchResult node + if (node instanceof FolderMatchWorkspaceRoot || searchView.isTreeLayoutViewVisible) { while (node = navigator.next()) { + if (node instanceof TextSearchResult) { + continue; + } if (node instanceof Match) { canCollapseFileMatchLevel = true; break; @@ -277,13 +285,13 @@ function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { if (node instanceof FolderMatch) { const compressionStartNode = viewer.getCompressedTreeNode(node)?.elements[0].element; - // Match elements should never be compressed, so !(compressionStartNode instanceof Match) should always be true here - nodeToTest = (compressionStartNode && !(compressionStartNode instanceof Match) && !(compressionStartNode instanceof SearchResult)) ? compressionStartNode : node; + // Match elements should never be compressed, so `!(compressionStartNode instanceof Match)` should always be true here. Same with `!(compressionStartNode instanceof TextSearchResult)` + nodeToTest = (compressionStartNode && !(compressionStartNode instanceof Match) && !(compressionStartNode instanceof TextSearchResult) && !(compressionStartNode instanceof SearchResult)) ? compressionStartNode : node; } const immediateParent = nodeToTest.parent(); - if (!(immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot || immediateParent instanceof SearchResult)) { + if (!(immediateParent instanceof TextSearchResult || immediateParent instanceof FolderMatchWorkspaceRoot || immediateParent instanceof FolderMatchNoRoot || immediateParent instanceof SearchResult)) { canCollapseFirstLevel = true; } } @@ -320,6 +328,20 @@ function collapseDeepestExpandedLevel(accessor: ServicesAccessor) { } } while (node = navigator.next()); } + } else if (navigator.first() instanceof TextSearchResult) { + // if AI results are visible, just collapse everything under the TextSearchResult. + node = navigator.first(); + do { + if (!node) { + break; + + } + + if (viewer.getParentElement(node) instanceof TextSearchResult) { + viewer.collapse(node); + } + } while (node = navigator.next()); + } else { viewer.collapseAll(); } diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 0b70373878f7c..9604683c0950f 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -1008,7 +1008,7 @@ export class SearchView extends ViewPane { const navigator = viewer.navigate(); let node = navigator.first(); do { - if (node && !viewer.isCollapsed(node) && (this.viewModel.hasAIResults || node.id() !== AI_TEXT_SEARCH_RESULT_ID)) { + if (node && !viewer.isCollapsed(node) && (this.shouldShowAIResults() && !(node instanceof TextSearchResult))) { // ignore the ai text search result id return true; }