提交 56a6279a 编写于 作者: R Rob Lourens

Don't use getActions in search view

#92038
上级 856277c8
......@@ -258,6 +258,10 @@ export class FindInput extends Widget {
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
}
public get onDidChange(): Event<string> {
return this.inputBox.onDidChange;
}
public enable(): void {
this.domNode.classList.remove('disabled');
this.inputBox.enable();
......
......@@ -8,53 +8,53 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import * as platform from 'vs/base/common/platform';
import { dirname } from 'vs/base/common/resources';
import { assertIsDefined, assertType } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { ToggleCaseSensitiveKeybinding, TogglePreserveCaseKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/findModel';
import { AbstractGotoLineQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoLineQuickAccess';
import * as nls from 'vs/nls';
import { ICommandAction, MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { Action2, ICommandAction, MenuId, MenuRegistry, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IFileService } from 'vs/platform/files/common/files';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IListService, WorkbenchListFocusContextKey, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { Extensions as QuickAccessExtensions, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { defaultQuickAccessContextKeyValue } from 'vs/workbench/browser/quickaccess';
import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { Extensions as ViewExtensions, IViewsRegistry, IViewContainersRegistry, ViewContainerLocation, IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
import { Extensions as ViewExtensions, IViewContainersRegistry, IViewDescriptorService, IViewsRegistry, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
import { GotoSymbolQuickAccessProvider } from 'vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess';
import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/explorerViewlet';
import { getMultiSelectedResources, IExplorerService } from 'vs/workbench/contrib/files/browser/files';
import { ExplorerFolderContext, ExplorerRootContext, FilesExplorerFocusCondition, VIEWLET_ID as VIEWLET_ID_FILES } from 'vs/workbench/contrib/files/common/files';
import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess';
import { registerContributions as replaceContributions } from 'vs/workbench/contrib/search/browser/replaceContributions';
import { clearHistoryCommand, ClearSearchResultsAction, CloseReplaceAction, CollapseDeepestExpandedLevelAction, copyAllCommand, copyMatchCommand, copyPathCommand, FocusNextInputAction, FocusNextSearchResultAction, FocusPreviousInputAction, FocusPreviousSearchResultAction, focusSearchListCommand, getSearchView, openSearchView, OpenSearchViewletAction, RefreshAction, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceInFilesAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, toggleWholeWordCommand, FindInFilesCommand, ToggleSearchOnTypeAction, ExpandAllAction } from 'vs/workbench/contrib/search/browser/searchActions';
import { cancelSearch, clearHistoryCommand, clearSearchResults, CloseReplaceAction, collapseDeepestExpandedLevel, copyAllCommand, copyMatchCommand, copyPathCommand, expandAll, FindInFilesCommand, FocusNextInputAction, FocusNextSearchResultAction, FocusPreviousInputAction, FocusPreviousSearchResultAction, focusSearchListCommand, getSearchView, openSearchView, OpenSearchViewletAction, refreshSearch, RemoveAction, ReplaceAction, ReplaceAllAction, ReplaceAllInFolderAction, ReplaceInFilesAction, toggleCaseSensitiveCommand, togglePreserveCaseCommand, toggleRegexCommand, ToggleSearchOnTypeAction, toggleWholeWordCommand } from 'vs/workbench/contrib/search/browser/searchActions';
import { searchClearIcon, searchCollapseAllIcon, searchExpandAllIcon, searchRefreshIcon, searchStopIcon, searchViewIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { SearchView } from 'vs/workbench/contrib/search/browser/searchView';
import { registerContributions as searchWidgetContributions } from 'vs/workbench/contrib/search/browser/searchWidget';
import { SymbolsQuickAccessProvider } from 'vs/workbench/contrib/search/browser/symbolsQuickAccess';
import * as Constants from 'vs/workbench/contrib/search/common/constants';
import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants';
import { getWorkspaceSymbols } from 'vs/workbench/contrib/search/common/search';
import { resolveResourcesForSearchIncludes } from 'vs/workbench/contrib/search/common/queryBuilder';
import { getWorkspaceSymbols, SearchStateKey, SearchUIState } from 'vs/workbench/contrib/search/common/search';
import { ISearchHistoryService, SearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { FileMatchOrMatch, ISearchWorkbenchService, RenderableMatch, SearchWorkbenchService, FileMatch, Match, FolderMatch } from 'vs/workbench/contrib/search/common/searchModel';
import { FileMatch, FileMatchOrMatch, FolderMatch, ISearchWorkbenchService, Match, RenderableMatch, SearchWorkbenchService } from 'vs/workbench/contrib/search/common/searchModel';
import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { VIEWLET_ID, VIEW_ID, SEARCH_EXCLUDE_CONFIG, SearchSortOrder, ISearchConfiguration } from 'vs/workbench/services/search/common/search';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ISearchConfiguration, SearchSortOrder, SEARCH_EXCLUDE_CONFIG, VIEWLET_ID, VIEW_ID } from 'vs/workbench/services/search/common/search';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/explorerViewlet';
import { assertType, assertIsDefined } from 'vs/base/common/types';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess';
import { SymbolsQuickAccessProvider } from 'vs/workbench/contrib/search/browser/symbolsQuickAccess';
import { AnythingQuickAccessProvider } from 'vs/workbench/contrib/search/browser/anythingQuickAccess';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { AbstractGotoLineQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoLineQuickAccess';
import { GotoSymbolQuickAccessProvider } from 'vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess';
import { searchViewIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { resolveResourcesForSearchIncludes } from 'vs/workbench/contrib/search/common/queryBuilder';
registerSingleton(ISearchWorkbenchService, SearchWorkbenchService, true);
registerSingleton(ISearchHistoryService, SearchHistoryService, true);
......@@ -128,19 +128,6 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: Constants.CancelActionId,
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, WorkbenchListFocusContextKey),
primary: KeyCode.Escape,
handler: (accessor, args: any) => {
const searchView = getSearchView(accessor.get(IViewsService));
if (searchView) {
searchView.cancelSearch();
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: Constants.RemoveActionId,
weight: KeybindingWeight.WorkbenchContrib,
......@@ -373,6 +360,121 @@ CommandsRegistry.registerCommand({
}
});
registerAction2(class CancelSearchAction extends Action2 {
constructor() {
super({
id: 'search.action.cancel',
title: nls.localize('CancelSearchAction.label', "Cancel Search"),
icon: searchStopIcon,
category,
f1: true,
precondition: SearchStateKey.isEqualTo(SearchUIState.Idle).negate(),
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, WorkbenchListFocusContextKey),
primary: KeyCode.Escape,
},
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 0,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', VIEW_ID), SearchStateKey.isEqualTo(SearchUIState.SlowSearch)),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return cancelSearch(accessor);
}
});
registerAction2(class RefreshAction extends Action2 {
constructor() {
super({
id: 'search.action.refreshSearchResults',
title: nls.localize('RefreshAction.label', "Refresh"),
icon: searchRefreshIcon,
precondition: Constants.ViewHasSearchPatternKey,
category,
f1: true,
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 0,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', VIEW_ID), SearchStateKey.isEqualTo(SearchUIState.SlowSearch).negate()),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return refreshSearch(accessor);
}
});
registerAction2(class CollapseDeepestExpandedLevelAction extends Action2 {
constructor() {
super({
id: 'search.action.collapseSearchResults',
title: nls.localize('CollapseDeepestExpandedLevelAction.label', "Collapse All"),
category,
icon: searchCollapseAllIcon,
f1: true,
precondition: ContextKeyExpr.and(Constants.HasSearchResults, Constants.ViewHasSomeCollapsibleKey),
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 3,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', VIEW_ID), ContextKeyExpr.or(Constants.HasSearchResults.negate(), Constants.ViewHasSomeCollapsibleKey)),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return collapseDeepestExpandedLevel(accessor);
}
});
registerAction2(class ExpandAllAction extends Action2 {
constructor() {
super({
id: 'search.action.expandSearchResults',
title: nls.localize('ExpandAllAction.label', "Expand All"),
category,
icon: searchExpandAllIcon,
f1: true,
precondition: ContextKeyExpr.and(Constants.HasSearchResults, Constants.ViewHasSomeCollapsibleKey.toNegated()),
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 3,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', VIEW_ID), Constants.HasSearchResults, Constants.ViewHasSomeCollapsibleKey.toNegated()),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return expandAll(accessor);
}
});
registerAction2(class ClearSearchResultsAction extends Action2 {
constructor() {
super({
id: 'search.action.clearSearchResults',
title: nls.localize('ClearSearchResultsAction.label', "Clear Search Results"),
category,
icon: searchClearIcon,
f1: true,
precondition: ContextKeyExpr.or(Constants.HasSearchResults, Constants.ViewHasSearchPatternKey, Constants.ViewHasReplacePatternKey, Constants.ViewHasFilePatternKey),
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 1,
when: ContextKeyEqualsExpr.create('view', VIEW_ID),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return clearSearchResults(accessor);
}
});
const RevealInSideBarForSearchResultsCommand: ICommandAction = {
id: Constants.RevealInSideBarForSearchResults,
title: nls.localize('revealInSideBar', "Reveal in Side Bar")
......@@ -449,20 +551,6 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
handler: searchInFolderCommand
});
CommandsRegistry.registerCommand({
id: ClearSearchResultsAction.ID,
handler: (accessor, args: any) => {
accessor.get(IInstantiationService).createInstance(ClearSearchResultsAction, ClearSearchResultsAction.ID, '').run();
}
});
CommandsRegistry.registerCommand({
id: RefreshAction.ID,
handler: (accessor, args: any) => {
accessor.get(IInstantiationService).createInstance(RefreshAction, RefreshAction.ID, '').run();
}
});
const FIND_IN_WORKSPACE_ID = 'filesExplorer.findInWorkspace';
CommandsRegistry.registerCommand({
id: FIND_IN_WORKSPACE_ID,
......@@ -686,12 +774,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
registry.registerWorkbenchAction(SyncActionDescriptor.from(CollapseDeepestExpandedLevelAction), 'Search: Collapse All', category.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ExpandAllAction), 'Search: Expand All', category.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllSymbolsAction, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...');
registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleSearchOnTypeAction), 'Search: Toggle Search on Type', category.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(RefreshAction), 'Search: Refresh', category.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearSearchResultsAction), 'Search: Clear Search Results', category.value);
// Register Quick Access Handler
const quickAccessRegistry = Registry.as<IQuickAccessRegistry>(QuickAccessExtensions.Quickaccess);
......
......@@ -4,34 +4,34 @@
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { ITreeNavigator } from 'vs/base/browser/ui/tree/tree';
import { Action } from 'vs/base/common/actions';
import { createKeybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { isWindows, OS } from 'vs/base/common/platform';
import * as nls from 'vs/nls';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ILabelService } from 'vs/platform/label/common/label';
import { ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ILabelService } from 'vs/platform/label/common/label';
import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IViewsService } from 'vs/workbench/common/views';
import { searchRemoveIcon, searchReplaceAllIcon, searchReplaceIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { SearchView } from 'vs/workbench/contrib/search/browser/searchView';
import * as Constants from 'vs/workbench/contrib/search/common/constants';
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
import { FolderMatch, FileMatch, FolderMatchWithResource, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ISearchConfiguration, VIEW_ID, VIEWLET_ID } from 'vs/workbench/services/search/common/search';
import { ISearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { ITreeNavigator } from 'vs/base/browser/ui/tree/tree';
import { IViewsService } from 'vs/workbench/common/views';
import { SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { FileMatch, FolderMatch, FolderMatchWithResource, Match, RenderableMatch, searchMatchComparer, SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
import { OpenEditorCommandId } from 'vs/workbench/contrib/searchEditor/browser/constants';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { searchRefreshIcon, searchCollapseAllIcon, searchExpandAllIcon, searchClearIcon, searchReplaceAllIcon, searchReplaceIcon, searchRemoveIcon, searchStopIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { OpenSearchEditorArgs } from 'vs/workbench/contrib/searchEditor/browser/searchEditor.contribution';
import { OpenEditorCommandId } from 'vs/workbench/contrib/searchEditor/browser/constants';
import { SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ISearchConfiguration, VIEWLET_ID, VIEW_ID } from 'vs/workbench/services/search/common/search';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
export function isSearchViewFocused(viewsService: IViewsService): boolean {
const searchView = getSearchView(viewsService);
......@@ -289,227 +289,77 @@ export class ToggleSearchOnTypeAction extends Action {
}
}
export class RefreshAction extends Action {
static readonly ID: string = 'search.action.refreshSearchResults';
static LABEL: string = nls.localize('RefreshAction.label', "Refresh");
constructor(id: string, label: string,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, 'search-action ' + ThemeIcon.asClassName(searchRefreshIcon));
}
get enabled(): boolean {
const searchView = getSearchView(this.viewsService);
return !!searchView && searchView.hasSearchPattern();
export function expandAll(accessor: ServicesAccessor) {
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
const viewer = searchView.getControl();
viewer.expandAll();
viewer.domFocus();
viewer.focusFirst();
}
}
update(): void {
this._setEnabled(this.enabled);
export function clearSearchResults(accessor: ServicesAccessor) {
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
searchView.clearSearchResults();
}
}
run(): Promise<void> {
const searchView = getSearchView(this.viewsService);
if (searchView) {
searchView.triggerQueryChange({ preserveFocus: false });
}
return Promise.resolve();
export function cancelSearch(accessor: ServicesAccessor) {
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
searchView.cancelSearch();
}
}
export class CollapseDeepestExpandedLevelAction extends Action {
static readonly ID: string = 'search.action.collapseSearchResults';
static LABEL: string = nls.localize('CollapseDeepestExpandedLevelAction.label', "Collapse All");
constructor(id: string, label: string,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, 'search-action ' + ThemeIcon.asClassName(searchCollapseAllIcon));
this.update();
export function refreshSearch(accessor: ServicesAccessor) {
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
searchView.triggerQueryChange({ preserveFocus: false });
}
}
update(): void {
const searchView = getSearchView(this.viewsService);
this.enabled = !!searchView && searchView.hasSearchResults();
}
export function collapseDeepestExpandedLevel(accessor: ServicesAccessor) {
run(): Promise<void> {
const searchView = getSearchView(this.viewsService);
if (searchView) {
const viewer = searchView.getControl();
/**
* one level to collapse so collapse everything. If FolderMatch, check if there are visible grandchildren,
* i.e. if Matches are returned by the navigator, and if so, collapse to them, otherwise collapse all levels.
*/
const navigator = viewer.navigate();
let node = navigator.first();
let collapseFileMatchLevel = false;
if (node instanceof FolderMatch) {
while (node = navigator.next()) {
if (node instanceof Match) {
collapseFileMatchLevel = true;
break;
}
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
const viewer = searchView.getControl();
/**
* one level to collapse so collapse everything. If FolderMatch, check if there are visible grandchildren,
* i.e. if Matches are returned by the navigator, and if so, collapse to them, otherwise collapse all levels.
*/
const navigator = viewer.navigate();
let node = navigator.first();
let collapseFileMatchLevel = false;
if (node instanceof FolderMatch) {
while (node = navigator.next()) {
if (node instanceof Match) {
collapseFileMatchLevel = true;
break;
}
}
if (collapseFileMatchLevel) {
node = navigator.first();
do {
if (node instanceof FileMatch) {
viewer.collapse(node);
}
} while (node = navigator.next());
} else {
viewer.collapseAll();
}
viewer.domFocus();
viewer.focusFirst();
}
return Promise.resolve(undefined);
}
}
export class ExpandAllAction extends Action {
static readonly ID: string = 'search.action.expandSearchResults';
static LABEL: string = nls.localize('ExpandAllAction.label', "Expand All");
constructor(id: string, label: string,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, 'search-action ' + ThemeIcon.asClassName(searchExpandAllIcon));
this.update();
}
update(): void {
const searchView = getSearchView(this.viewsService);
this.enabled = !!searchView && searchView.hasSearchResults();
}
run(): Promise<void> {
const searchView = getSearchView(this.viewsService);
if (searchView) {
const viewer = searchView.getControl();
viewer.expandAll();
viewer.domFocus();
viewer.focusFirst();
}
return Promise.resolve(undefined);
}
}
export class ToggleCollapseAndExpandAction extends Action {
static readonly ID: string = 'search.action.collapseOrExpandSearchResults';
static LABEL: string = nls.localize('ToggleCollapseAndExpandAction.label', "Toggle Collapse and Expand");
// Cache to keep from crawling the tree too often.
private action: CollapseDeepestExpandedLevelAction | ExpandAllAction | undefined;
constructor(id: string, label: string,
private collapseAction: CollapseDeepestExpandedLevelAction,
private expandAction: ExpandAllAction,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, collapseAction.class);
this.update();
}
update(): void {
const searchView = getSearchView(this.viewsService);
this.enabled = !!searchView && searchView.hasSearchResults();
this.onTreeCollapseStateChange();
}
onTreeCollapseStateChange() {
this.action = undefined;
this.determineAction();
}
private determineAction(): CollapseDeepestExpandedLevelAction | ExpandAllAction {
if (this.action !== undefined) { return this.action; }
this.action = this.isSomeCollapsible() ? this.collapseAction : this.expandAction;
this.class = this.action.class;
return this.action;
}
private isSomeCollapsible(): boolean {
const searchView = getSearchView(this.viewsService);
if (searchView) {
const viewer = searchView.getControl();
const navigator = viewer.navigate();
let node = navigator.first();
if (collapseFileMatchLevel) {
node = navigator.first();
do {
if (!viewer.isCollapsed(node)) {
return true;
if (node instanceof FileMatch) {
viewer.collapse(node);
}
} while (node = navigator.next());
}
return false;
}
async run(): Promise<void> {
await this.determineAction().run();
}
}
export class ClearSearchResultsAction extends Action {
static readonly ID: string = 'search.action.clearSearchResults';
static LABEL: string = nls.localize('ClearSearchResultsAction.label', "Clear Search Results");
constructor(id: string, label: string,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, 'search-action ' + ThemeIcon.asClassName(searchClearIcon));
this.update();
}
update(): void {
const searchView = getSearchView(this.viewsService);
this.enabled = !!searchView && (!searchView.allSearchFieldsClear() || searchView.hasSearchResults() || !searchView.allFilePatternFieldsClear());
}
run(): Promise<void> {
const searchView = getSearchView(this.viewsService);
if (searchView) {
searchView.clearSearchResults();
}
return Promise.resolve();
}
}
export class CancelSearchAction extends Action {
static readonly ID: string = 'search.action.cancelSearch';
static LABEL: string = nls.localize('CancelSearchAction.label', "Cancel Search");
constructor(id: string, label: string,
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label, 'search-action ' + ThemeIcon.asClassName(searchStopIcon));
this.update();
}
update(): void {
const searchView = getSearchView(this.viewsService);
this.enabled = !!searchView && searchView.isSlowSearch();
}
run(): Promise<void> {
const searchView = getSearchView(this.viewsService);
if (searchView) {
searchView.cancelSearch();
} else {
viewer.collapseAll();
}
return Promise.resolve(undefined);
viewer.domFocus();
viewer.focusFirst();
}
}
......
......@@ -8,9 +8,11 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
import { IAction, ActionRunner } from 'vs/base/common/actions';
import { ActionRunner, IAction } from 'vs/base/common/actions';
import { Delayer } from 'vs/base/common/async';
import { Color, RGBA } from 'vs/base/common/color';
import * as errors from 'vs/base/common/errors';
import { Event } from 'vs/base/common/event';
import { Iterable } from 'vs/base/common/iterator';
......@@ -20,10 +22,13 @@ import * as env from 'vs/base/common/platform';
import * as strings from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/searchview';
import { ICodeEditor, isCodeEditor, isDiffEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { getCodeEditor, ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { Selection } from 'vs/editor/common/core/selection';
import { CommonFindController } from 'vs/editor/contrib/find/findController';
import { MultiCursorSelectionController } from 'vs/editor/contrib/multicursor/multicursor';
import * as nls from 'vs/nls';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -32,53 +37,42 @@ import { IContextMenuService, IContextViewService } from 'vs/platform/contextvie
import { IConfirmation, IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { WorkbenchObjectTree, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { getSelectionKeyboardEvent, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IProgressService, IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, SearchSortOrder, SearchCompletionExitCode } from 'vs/workbench/services/search/common/search';
import { ISearchHistoryService, ISearchHistoryValues } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, listActiveSelectionForeground, foreground } from 'vs/platform/theme/common/colorRegistry';
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IProgress, IProgressService, IProgressStep } from 'vs/platform/progress/common/progress';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, foreground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { OpenFileFolderAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
import { ResourceLabels } from 'vs/workbench/browser/labels';
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
import { IEditorPane } from 'vs/workbench/common/editor';
import { Memento, MementoObject } from 'vs/workbench/common/memento';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { ExcludePatternInputWidget, PatternInputWidget } from 'vs/workbench/contrib/search/browser/patternInputWidget';
import { CancelSearchAction, ClearSearchResultsAction, CollapseDeepestExpandedLevelAction, RefreshAction, IFindInFilesArgs, appendKeyBindingLabel, ExpandAllAction, ToggleCollapseAndExpandAction } from 'vs/workbench/contrib/search/browser/searchActions';
import { appendKeyBindingLabel, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
import { searchDetailsIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { FileMatchRenderer, FolderMatchRenderer, MatchRenderer, SearchAccessibilityProvider, SearchDelegate, SearchDND } from 'vs/workbench/contrib/search/browser/searchResultsView';
import { ISearchWidgetOptions, SearchWidget } from 'vs/workbench/contrib/search/browser/searchWidget';
import * as Constants from 'vs/workbench/contrib/search/common/constants';
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
import { IReplaceService } from 'vs/workbench/contrib/search/common/replace';
import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search';
import { FileMatch, FileMatchOrMatch, IChangeEvent, ISearchWorkbenchService, Match, RenderableMatch, searchMatchComparer, SearchModel, SearchResult, FolderMatch, FolderMatchWithResource } from 'vs/workbench/contrib/search/common/searchModel';
import { getOutOfWorkspaceEditorResources, SearchStateKey, SearchUIState } from 'vs/workbench/contrib/search/common/search';
import { ISearchHistoryService, ISearchHistoryValues } from 'vs/workbench/contrib/search/common/searchHistoryService';
import { FileMatch, FileMatchOrMatch, FolderMatch, FolderMatchWithResource, IChangeEvent, ISearchWorkbenchService, Match, RenderableMatch, searchMatchComparer, SearchModel, SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
import { createEditorFromSearchResult } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions';
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IPreferencesService, ISettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, SearchCompletionExitCode, SearchSortOrder } from 'vs/workbench/services/search/common/search';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Memento, MementoObject } from 'vs/workbench/common/memento';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MultiCursorSelectionController } from 'vs/editor/contrib/multicursor/multicursor';
import { Selection } from 'vs/editor/common/core/selection';
import { Color, RGBA } from 'vs/base/common/color';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { OpenSearchEditorAction, createEditorFromSearchResult } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { searchDetailsIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
const $ = dom.$;
enum SearchUIState {
Idle,
Searching,
SlowSearch
}
export enum SearchViewPosition {
SideBar,
Panel
......@@ -112,12 +106,12 @@ export class SearchView extends ViewPane {
private hasSearchResultsKey: IContextKey<boolean>;
private lastFocusState: 'input' | 'tree' = 'input';
private state: SearchUIState = SearchUIState.Idle;
private searchStateKey: IContextKey<SearchUIState>;
private hasSearchPatternKey: IContextKey<boolean>;
private hasReplacePatternKey: IContextKey<boolean>;
private hasFilePatternKey: IContextKey<boolean>;
private hasSomeCollapsibleResultKey: IContextKey<boolean>;
private actions: Array<CollapseDeepestExpandedLevelAction | ClearSearchResultsAction | OpenSearchEditorAction> = [];
private toggleCollapseAction: ToggleCollapseAndExpandAction;
private cancelAction: CancelSearchAction;
private refreshAction: RefreshAction;
private contextMenu: IMenu | null = null;
private tree!: WorkbenchObjectTree<RenderableMatch>;
......@@ -138,7 +132,6 @@ export class SearchView extends ViewPane {
private delayedRefresh: Delayer<void>;
private changedWhileHidden: boolean = false;
private updatedActionsWhileHidden = false;
private searchWithoutFolderMessageElement: HTMLElement | undefined;
......@@ -194,6 +187,11 @@ export class SearchView extends ViewPane {
this.folderMatchFocused = Constants.FolderFocusKey.bindTo(this.contextKeyService);
this.hasSearchResultsKey = Constants.HasSearchResults.bindTo(this.contextKeyService);
this.matchFocused = Constants.MatchFocusKey.bindTo(this.contextKeyService);
this.searchStateKey = SearchStateKey.bindTo(this.contextKeyService);
this.hasSearchPatternKey = Constants.ViewHasSearchPatternKey.bindTo(this.contextKeyService);
this.hasReplacePatternKey = Constants.ViewHasReplacePatternKey.bindTo(this.contextKeyService);
this.hasFilePatternKey = Constants.ViewHasFilePatternKey.bindTo(this.contextKeyService);
this.hasSomeCollapsibleResultKey = Constants.ViewHasSomeCollapsibleKey.bindTo(this.contextKeyService);
// scoped
this.contextKeyService = this._register(this.contextKeyService.createScoped(this.container));
......@@ -232,19 +230,22 @@ export class SearchView extends ViewPane {
this.toggleCollapseStateDelayer = this._register(new Delayer<void>(100));
this.triggerQueryDelayer = this._register(new Delayer<void>(0));
const collapseDeepestExpandedLevelAction = this.instantiationService.createInstance(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL);
const expandAllAction = this.instantiationService.createInstance(ExpandAllAction, ExpandAllAction.ID, ExpandAllAction.LABEL);
this.treeAccessibilityProvider = this.instantiationService.createInstance(SearchAccessibilityProvider, this.viewModel);
}
this.actions = [
this._register(this.instantiationService.createInstance(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL)),
this._register(this.instantiationService.createInstance(OpenSearchEditorAction, OpenSearchEditorAction.ID, OpenSearchEditorAction.LABEL))
];
private get state(): SearchUIState {
return this.searchStateKey.get() ?? SearchUIState.Idle;
}
this.refreshAction = this._register(this.instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL));
this.cancelAction = this._register(this.instantiationService.createInstance(CancelSearchAction, CancelSearchAction.ID, CancelSearchAction.LABEL));
this.toggleCollapseAction = this._register(this.instantiationService.createInstance(ToggleCollapseAndExpandAction, ToggleCollapseAndExpandAction.ID, ToggleCollapseAndExpandAction.LABEL, collapseDeepestExpandedLevelAction, expandAllAction));
private set state(v: SearchUIState) {
this.searchStateKey.set(v);
}
this.treeAccessibilityProvider = this.instantiationService.createInstance(SearchAccessibilityProvider, this.viewModel);
/**
* Exposed for openSearchEditor TODO@JacksonKearl
*/
getInstantiationService(): IInstantiationService {
return this.instantiationService;
}
getContainer(): HTMLElement {
......@@ -322,8 +323,7 @@ export class SearchView extends ViewPane {
this.inputPatternIncludes.setValue(patternIncludes);
this.inputPatternIncludes.onSubmit(triggeredOnType => this.triggerQueryChange({ triggeredOnType, delay: this.searchConfig.searchOnTypeDebouncePeriod }));
this.inputPatternIncludes.onCancel(() => this.cancelSearch(false));
this._register(this.inputPatternIncludes.onCancel(() => this.cancelSearch(false)));
this.trackInputBox(this.inputPatternIncludes.inputFocusTracker, this.inputPatternIncludesFocused);
// excludes list
......@@ -338,11 +338,21 @@ export class SearchView extends ViewPane {
this.inputPatternExcludes.setValue(patternExclusions);
this.inputPatternExcludes.setUseExcludesAndIgnoreFiles(useExcludesAndIgnoreFiles);
this.inputPatternExcludes.onSubmit(triggeredOnType => this.triggerQueryChange({ triggeredOnType, delay: this.searchConfig.searchOnTypeDebouncePeriod }));
this.inputPatternExcludes.onCancel(() => this.cancelSearch(false));
this.inputPatternExcludes.onChangeIgnoreBox(() => this.triggerQueryChange());
this._register(this.inputPatternExcludes.onCancel(() => this.cancelSearch(false)));
this._register(this.inputPatternExcludes.onChangeIgnoreBox(() => this.triggerQueryChange()));
this.trackInputBox(this.inputPatternExcludes.inputFocusTracker, this.inputPatternExclusionsFocused);
const updateHasFilePatternKey = () => this.hasFilePatternKey.set(this.inputPatternIncludes.getValue().length > 0 || this.inputPatternExcludes.getValue().length > 0);
updateHasFilePatternKey();
const onFilePatternSubmit = (triggeredOnType: boolean) => {
this.triggerQueryChange({ triggeredOnType, delay: this.searchConfig.searchOnTypeDebouncePeriod });
if (triggeredOnType) {
updateHasFilePatternKey();
}
};
this._register(this.inputPatternIncludes.onSubmit(onFilePatternSubmit));
this._register(this.inputPatternExcludes.onSubmit(onFilePatternSubmit));
this.messagesElement = dom.append(this.container, $('.messages'));
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.showSearchWithoutFolderMessage();
......@@ -356,9 +366,6 @@ export class SearchView extends ViewPane {
this._register(this.viewModel.searchResult.onChange((event) => this.onSearchResultsChanged(event)));
this._register(this.searchWidget.searchInput.onInput(() => this.updateActions()));
this._register(this.searchWidget.replaceInput.onInput(() => this.updateActions()));
this._register(this.onDidChangeBodyVisibility(visible => this.onVisibilityChanged(visible)));
}
......@@ -370,13 +377,6 @@ export class SearchView extends ViewPane {
this.refreshAndUpdateCount();
this.changedWhileHidden = false;
}
if (this.updatedActionsWhileHidden) {
// The actions can only run or update their enablement when the view is visible,
// because they can only access the view when it's visible
this.updateActions();
this.updatedActionsWhileHidden = false;
}
} else {
// Reset last focus to input to preserve opening the viewlet always focusing the query editor.
this.lastFocusState = 'input';
......@@ -400,25 +400,6 @@ export class SearchView extends ViewPane {
return this.inputPatternExcludes;
}
/**
* Warning: a bit expensive due to updating the view title
*/
protected updateActions(): void {
if (!this.isVisible()) {
this.updatedActionsWhileHidden = true;
}
for (const action of this.actions) {
action.update();
}
this.refreshAction.update();
this.cancelAction.update();
this.toggleCollapseAction.update();
super.updateActions();
}
private createSearchWidget(container: HTMLElement): void {
const contentPattern = this.viewletState['query.contentPattern'] || '';
const replaceText = this.viewletState['query.replaceText'] || '';
......@@ -450,6 +431,14 @@ export class SearchView extends ViewPane {
this._register(this.searchWidget.onSearchCancel(({ focus }) => this.cancelSearch(focus)));
this._register(this.searchWidget.searchInput.onDidOptionChange(() => this.triggerQueryChange()));
const updateHasPatternKey = () => this.hasSearchPatternKey.set(this.searchWidget.searchInput.getValue().length > 0);
updateHasPatternKey();
this._register(this.searchWidget.searchInput.onDidChange(() => updateHasPatternKey()));
const updateHasReplacePatternKey = () => this.hasReplacePatternKey.set(this.searchWidget.getReplaceValue().length > 0);
updateHasReplacePatternKey();
this._register(this.searchWidget.replaceInput.inputBox.onDidChange(() => updateHasReplacePatternKey()));
this._register(this.searchWidget.onDidHeightChange(() => this.reLayout()));
this._register(this.searchWidget.onReplaceToggled(() => this.reLayout()));
......@@ -729,9 +718,10 @@ export class SearchView extends ViewPane {
}
}));
this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
this._register(this.tree.onDidChangeCollapseState(() =>
this.toggleCollapseStateDelayer.trigger(() => this.toggleCollapseAction.onTreeCollapseStateChange())
));
const updateHasSomeCollapsible = () => this.toggleCollapseStateDelayer.trigger(() => this.hasSomeCollapsibleResultKey.set(this.hasSomeCollapsible()));
updateHasSomeCollapsible();
this._register(this.viewModel.searchResult.onChange(() => updateHasSomeCollapsible()));
this._register(this.tree.onDidChangeCollapseState(() => updateHasSomeCollapsible()));
this._register(Event.debounce(this.tree.onDidOpen, (last, event) => event, 75, true)(options => {
if (options.element instanceof Match) {
......@@ -790,6 +780,19 @@ export class SearchView extends ViewPane {
});
}
private hasSomeCollapsible(): boolean {
const viewer = this.getControl();
const navigator = viewer.navigate();
let node = navigator.first();
do {
if (!viewer.isCollapsed(node)) {
return true;
}
} while (node = navigator.next());
return false;
}
selectNextMatch(): void {
if (!this.hasSearchResults()) {
return;
......@@ -1053,10 +1056,6 @@ export class SearchView extends ViewPane {
return this.tree;
}
isSlowSearch(): boolean {
return this.state === SearchUIState.SlowSearch;
}
allSearchFieldsClear(): boolean {
return this.searchWidget.getReplaceValue() === '' &&
this.searchWidget.searchInput.getValue() === '';
......@@ -1071,10 +1070,6 @@ export class SearchView extends ViewPane {
return !this.viewModel.searchResult.isEmpty();
}
hasSearchPattern(): boolean {
return this.searchWidget && this.searchWidget.searchInput.getValue().length > 0;
}
clearSearchResults(clearInput = true): void {
this.viewModel.searchResult.clear();
this.showEmptyStage(true);
......@@ -1088,7 +1083,6 @@ export class SearchView extends ViewPane {
this.searchWidget.clear();
}
this.viewModel.cancelSearch();
this.updateActions();
this.tree.ariaLabel = nls.localize('emptySearch', "Empty Search");
aria.status(nls.localize('ariaSearchResultsClearStatus', "The search results have been cleared"));
......@@ -1415,7 +1409,6 @@ export class SearchView extends ViewPane {
const slowTimer = setTimeout(() => {
this.state = SearchUIState.SlowSearch;
this.updateActions();
}, 2000);
const onComplete = (completed?: ISearchComplete) => {
......@@ -1438,9 +1431,7 @@ export class SearchView extends ViewPane {
this.viewModel.replaceString = this.searchWidget.getReplaceValue();
this.updateActions();
const hasResults = !this.viewModel.searchResult.isEmpty();
if (completed?.exit === SearchCompletionExitCode.NewSearchStarted) {
return;
}
......@@ -1521,7 +1512,6 @@ export class SearchView extends ViewPane {
if (errors.isPromiseCanceledError(e)) {
return onComplete(undefined);
} else {
this.updateActions();
progressComplete();
this.searchWidget.searchInput.showMessage({ content: e.message, type: MessageType.ERROR });
this.viewModel.searchResult.clear();
......@@ -1532,8 +1522,6 @@ export class SearchView extends ViewPane {
let visibleMatches = 0;
let updatedActionsForFileCount = false;
// Handle UI updates in an interval to show frequent progress and results
const uiRefreshHandle: any = setInterval(() => {
if (this.state === SearchUIState.Idle) {
......@@ -1547,11 +1535,6 @@ export class SearchView extends ViewPane {
visibleMatches = fileCount;
this.refreshAndUpdateCount();
}
if (fileCount > 0 && !updatedActionsForFileCount) {
updatedActionsForFileCount = true;
this.updateActions();
}
}, 100);
this.searchWidget.setReplaceAllActionState(false);
......@@ -1671,9 +1654,6 @@ export class SearchView extends ViewPane {
}
private showEmptyStage(forceHideMessages = false): void {
// disable 'result'-actions
this.updateActions();
const showingCancelled = (this.messagesElement.firstChild?.textContent?.indexOf(SEARCH_CANCELLED_MESSAGE) ?? -1) > -1;
// clean up ui
......@@ -1808,16 +1788,6 @@ export class SearchView extends ViewPane {
}
}
getActions(): IAction[] {
return [
this.state === SearchUIState.SlowSearch ?
this.cancelAction :
this.refreshAction,
...this.actions,
this.toggleCollapseAction
];
}
private get searchConfig(): ISearchConfigurationProperties {
return this.configurationService.getValue<ISearchConfigurationProperties>('search');
}
......
......@@ -11,7 +11,6 @@ export const FocusActiveEditorCommandId = 'search.action.focusActiveEditor';
export const FocusSearchFromResults = 'search.action.focusSearchFromResults';
export const OpenMatch = 'search.action.openResult';
export const OpenMatchToSide = 'search.action.openResultToSide';
export const CancelActionId = 'search.action.cancel';
export const RemoveActionId = 'search.action.remove';
export const CopyPathCommandId = 'search.action.copyPath';
export const CopyMatchCommandId = 'search.action.copyMatch';
......@@ -46,3 +45,7 @@ export const FileMatchOrFolderMatchWithResourceFocusKey = new RawContextKey<bool
export const FileFocusKey = new RawContextKey<boolean>('fileMatchFocus', false);
export const FolderFocusKey = new RawContextKey<boolean>('folderMatchFocus', false);
export const MatchFocusKey = new RawContextKey<boolean>('matchFocus', false);
export const ViewHasSearchPatternKey = new RawContextKey<boolean>('viewHasSearchPattern', false);
export const ViewHasReplacePatternKey = new RawContextKey<boolean>('viewHasReplacePattern', false);
export const ViewHasFilePatternKey = new RawContextKey<boolean>('viewHasFilePattern', false);
export const ViewHasSomeCollapsibleKey = new RawContextKey<boolean>('viewHasSomeCollapsibleResult', false);
......@@ -16,6 +16,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation
import { IFileService } from 'vs/platform/files/common/files';
import { IRange } from 'vs/editor/common/core/range';
import { isNumber } from 'vs/base/common/types';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
export interface IWorkspaceSymbol {
name: string;
......@@ -164,3 +165,11 @@ export function extractRangeFromFilter(filter: string, unless?: string[]): IFilt
return undefined;
}
export enum SearchUIState {
Idle,
Searching,
SlowSearch
}
export const SearchStateKey = new RawContextKey<SearchUIState>('searchState', SearchUIState.Idle);
......@@ -12,7 +12,7 @@ import { ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKe
import { localize } from 'vs/nls';
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
......@@ -24,14 +24,15 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchCo
import { ActiveEditorContext, Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
import { IViewsService } from 'vs/workbench/common/views';
import { getSearchView } from 'vs/workbench/contrib/search/browser/searchActions';
import { searchRefreshIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { searchNewEditorIcon, searchRefreshIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import * as SearchConstants from 'vs/workbench/contrib/search/common/constants';
import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { createEditorFromSearchResult, modifySearchEditorContextLinesCommand, openNewSearchEditor, selectAllSearchEditorMatchesCommand, toggleSearchEditorCaseSensitiveCommand, toggleSearchEditorContextLinesCommand, toggleSearchEditorRegexCommand, toggleSearchEditorWholeWordCommand } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions';
import { createEditorFromSearchResult, modifySearchEditorContextLinesCommand, openNewSearchEditor, openSearchEditor, selectAllSearchEditorMatchesCommand, toggleSearchEditorCaseSensitiveCommand, toggleSearchEditorContextLinesCommand, toggleSearchEditorRegexCommand, toggleSearchEditorWholeWordCommand } from 'vs/workbench/contrib/searchEditor/browser/searchEditorActions';
import { getOrMakeSearchEditorInput, SearchConfiguration, SearchEditorInput, SEARCH_EDITOR_EXT } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { parseSavedSearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { VIEW_ID } from 'vs/workbench/services/search/common/search';
const OpenInEditorCommandId = 'search.action.openInEditor';
......@@ -506,4 +507,25 @@ registerAction2(class extends Action2 {
selectAllSearchEditorMatchesCommand(accessor);
}
});
registerAction2(class OpenSearchEditorAction extends Action2 {
constructor() {
super({
id: SearchEditorConstants.OpenNewEditorCommandId,
title: localize('search.openNewEditor', "Open New Search Editor"),
category,
icon: searchNewEditorIcon,
f1: true,
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
order: 2,
when: ContextKeyEqualsExpr.create('view', VIEW_ID),
}]
});
}
run(accessor: ServicesAccessor, ...args: any[]) {
return openSearchEditor(accessor);
}
});
//#endregion
......@@ -3,34 +3,29 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Action } from 'vs/base/common/actions';
import { Schemas } from 'vs/base/common/network';
import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/searchEditor';
import { ICodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EditorsOrder } from 'vs/workbench/common/editor';
import { IViewsService } from 'vs/workbench/common/views';
import { getSearchView } from 'vs/workbench/contrib/search/browser/searchActions';
import { SearchResult } from 'vs/workbench/contrib/search/common/searchModel';
import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor';
import { OpenSearchEditorArgs } from 'vs/workbench/contrib/searchEditor/browser/searchEditor.contribution';
import { getOrMakeSearchEditorInput, SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { serializeSearchResultForEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search';
import { searchNewEditorIcon } from 'vs/workbench/contrib/search/browser/searchIcons';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { Schemas } from 'vs/base/common/network';
import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types';
import { OpenNewEditorCommandId } from 'vs/workbench/contrib/searchEditor/browser/constants';
import { OpenSearchEditorArgs } from 'vs/workbench/contrib/searchEditor/browser/searchEditor.contribution';
import { EditorsOrder } from 'vs/workbench/common/editor';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IViewsService } from 'vs/workbench/common/views';
import { getSearchView } from 'vs/workbench/contrib/search/browser/searchActions';
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { ISearchConfigurationProperties } from 'vs/workbench/services/search/common/search';
export const toggleSearchEditorCaseSensitiveCommand = (accessor: ServicesAccessor) => {
const editorService = accessor.get(IEditorService);
......@@ -80,41 +75,23 @@ export const selectAllSearchEditorMatchesCommand = (accessor: ServicesAccessor)
}
};
// Handler for the action bar entry in the search view.
export class OpenSearchEditorAction extends Action {
static readonly ID: string = OpenNewEditorCommandId;
static readonly LABEL = localize('search.openNewEditor', "Open New Search Editor");
constructor(id: string, label: string,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IViewsService private readonly viewsService: IViewsService,
) {
super(id, label, ThemeIcon.asClassName(searchNewEditorIcon));
}
update() {
// pass
}
get enabled(): boolean {
return true;
}
async run() {
const searchView = getSearchView(this.viewsService);
if (searchView) {
await this.instantiationService.invokeFunction(openNewSearchEditor, {
filesToInclude: searchView.searchIncludePattern.getValue(),
filesToExclude: searchView.searchExcludePattern.getValue(),
isRegexp: searchView.searchAndReplaceWidget.searchInput.getRegex(),
isCaseSensitive: searchView.searchAndReplaceWidget.searchInput.getCaseSensitive(),
matchWholeWord: searchView.searchAndReplaceWidget.searchInput.getWholeWords(),
useExcludeSettingsAndIgnoreFiles: searchView.searchExcludePattern.useExcludesAndIgnoreFiles(),
showIncludesExcludes: !!(searchView.searchIncludePattern.getValue() || searchView.searchExcludePattern.getValue() || !searchView.searchExcludePattern.useExcludesAndIgnoreFiles())
});
} else {
await this.instantiationService.invokeFunction(openNewSearchEditor);
}
export async function openSearchEditor(accessor: ServicesAccessor): Promise<void> {
const viewsService = accessor.get(IViewsService);
const searchView = getSearchView(viewsService);
if (searchView) {
const instantiationService = searchView.getInstantiationService();
await instantiationService.invokeFunction(openNewSearchEditor, {
filesToInclude: searchView.searchIncludePattern.getValue(),
filesToExclude: searchView.searchExcludePattern.getValue(),
isRegexp: searchView.searchAndReplaceWidget.searchInput.getRegex(),
isCaseSensitive: searchView.searchAndReplaceWidget.searchInput.getCaseSensitive(),
matchWholeWord: searchView.searchAndReplaceWidget.searchInput.getWholeWords(),
useExcludeSettingsAndIgnoreFiles: searchView.searchExcludePattern.useExcludesAndIgnoreFiles(),
showIncludesExcludes: !!(searchView.searchIncludePattern.getValue() || searchView.searchExcludePattern.getValue() || !searchView.searchExcludePattern.useExcludesAndIgnoreFiles())
});
} else {
const instantiationService = accessor.get(IInstantiationService);
await instantiationService.invokeFunction(openNewSearchEditor);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册