search.contribution.ts 29.6 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/search.contribution';
7
import { Registry } from 'vs/platform/registry/common/platform';
S
Sandeep Somavarapu 已提交
8
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
9
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
S
Sandeep Somavarapu 已提交
10
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
11
import * as nls from 'vs/nls';
12
import { TPromise } from 'vs/base/common/winjs.base';
I
isidor 已提交
13
import { Action } from 'vs/base/common/actions';
R
Rob Lourens 已提交
14
import * as objects from 'vs/base/common/objects';
15
import * as platform from 'vs/base/common/platform';
I
isidor 已提交
16
import { ExplorerFolderContext, ExplorerRootContext } from 'vs/workbench/parts/files/common/files';
17
import { SyncActionDescriptor, MenuRegistry, MenuId, ICommandAction } from 'vs/platform/actions/common/actions';
B
Benjamin Pasero 已提交
18
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
O
Oleg Mihailik 已提交
19
import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions } from 'vs/workbench/browser/quickopen';
20
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
J
Johannes Rieken 已提交
21
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
J
Johannes Rieken 已提交
22
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
23
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
24
import { getSelectionSearchString } from 'vs/editor/contrib/find/findController';
B
Benjamin Pasero 已提交
25
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
J
Johannes Rieken 已提交
26
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
S
Sandeep Somavarapu 已提交
27
import { ITree } from 'vs/base/parts/tree/browser/tree';
28
import * as Constants from 'vs/workbench/parts/search/common/constants';
29 30
import { registerContributions as replaceContributions } from 'vs/workbench/parts/search/browser/replaceContributions';
import { registerContributions as searchWidgetContributions } from 'vs/workbench/parts/search/browser/searchWidget';
31
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
32
import { ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/findModel';
S
Sandeep Somavarapu 已提交
33
import { ISearchWorkbenchService, SearchWorkbenchService } from 'vs/workbench/parts/search/common/searchModel';
34
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
I
isidor 已提交
35
import { SearchView } from 'vs/workbench/parts/search/browser/searchView';
B
Benjamin Pasero 已提交
36
import { defaultQuickOpenContextKey } from 'vs/workbench/browser/parts/quickopen/quickopen';
37 38
import { OpenSymbolHandler } from 'vs/workbench/parts/search/browser/openSymbolHandler';
import { OpenAnythingHandler } from 'vs/workbench/parts/search/browser/openAnythingHandler';
39
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
40
import { getWorkspaceSymbols } from 'vs/workbench/parts/search/common/search';
I
isidor 已提交
41
import { illegalArgument } from 'vs/base/common/errors';
I
isidor 已提交
42
import { WorkbenchListFocusContextKey, IListService } from 'vs/platform/list/browser/listService';
43
import { URI } from 'vs/base/common/uri';
I
isidor 已提交
44 45 46
import { relative } from 'path';
import { dirname } from 'vs/base/common/resources';
import { ResourceContextKey } from 'vs/workbench/common/resources';
I
isidor 已提交
47
import { IFileService } from 'vs/platform/files/common/files';
48
import { distinct } from 'vs/base/common/arrays';
49
import { getMultiSelectedResources } from 'vs/workbench/parts/files/browser/files';
50
import { Schemas } from 'vs/base/common/network';
I
isidor 已提交
51
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
52
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
53
import { openSearchView, getSearchView, ReplaceAllInFolderAction, ReplaceAllAction, CloseReplaceAction, FocusNextSearchResultAction, FocusPreviousSearchResultAction, ReplaceInFilesAction, FindInFilesAction, toggleCaseSensitiveCommand, toggleRegexCommand, CollapseDeepestExpandedLevelAction, toggleWholeWordCommand, RemoveAction, ReplaceAction, ClearSearchResultsAction, copyPathCommand, copyMatchCommand, copyAllCommand, clearHistoryCommand, FocusNextInputAction, FocusPreviousInputAction, RefreshAction, focusSearchListCommand, OpenSearchViewletAction } from 'vs/workbench/parts/search/browser/searchActions';
54
import { VIEW_ID, ISearchConfigurationProperties } from 'vs/platform/search/common/search';
55 56 57
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { SearchViewLocationUpdater } from 'vs/workbench/parts/search/browser/searchViewLocationUpdater';
58
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
59
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
60

S
Sandeep Somavarapu 已提交
61
registerSingleton(ISearchWorkbenchService, SearchWorkbenchService);
62 63
replaceContributions();
searchWidgetContributions();
E
Erich Gamma 已提交
64

65 66
const category = nls.localize('search', "Search");

A
Alex Dima 已提交
67
KeybindingsRegistry.registerCommandAndKeybindingRule({
E
Erich Gamma 已提交
68
	id: 'workbench.action.search.toggleQueryDetails',
69
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
70
	when: Constants.SearchViewVisibleKey,
E
Erich Gamma 已提交
71
	primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_J,
72
	handler: accessor => {
73 74 75 76
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
		if (searchView) {
			searchView.toggleQueryDetails();
		}
E
Erich Gamma 已提交
77 78 79
	}
});

S
Sandeep Somavarapu 已提交
80 81
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.FocusSearchFromResults,
82
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
83
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.FirstMatchFocusKey),
84
	primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
S
Sandeep Somavarapu 已提交
85
	handler: (accessor, args: any) => {
86
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
87
		searchView.focusPreviousInputBox();
S
Sandeep Somavarapu 已提交
88 89 90 91 92
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.OpenMatchToSide,
93
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
94
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.FileMatchOrMatchFocusKey),
S
Sandeep Somavarapu 已提交
95 96 97 98 99
	primary: KeyMod.CtrlCmd | KeyCode.Enter,
	mac: {
		primary: KeyMod.WinCtrl | KeyCode.Enter
	},
	handler: (accessor, args: any) => {
100
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
101 102
		const tree: ITree = searchView.getControl();
		searchView.open(tree.getFocus(), false, true, true);
S
Sandeep Somavarapu 已提交
103 104 105 106 107
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.CancelActionId,
108
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
109
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, WorkbenchListFocusContextKey),
S
Sandeep Somavarapu 已提交
110 111
	primary: KeyCode.Escape,
	handler: (accessor, args: any) => {
112
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
113
		searchView.cancelSearch();
S
Sandeep Somavarapu 已提交
114 115 116 117 118
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.RemoveActionId,
119
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
120
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.FileMatchOrMatchFocusKey),
S
Sandeep Somavarapu 已提交
121 122 123 124 125
	primary: KeyCode.Delete,
	mac: {
		primary: KeyMod.CtrlCmd | KeyCode.Backspace,
	},
	handler: (accessor, args: any) => {
126
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
127
		const tree: ITree = searchView.getControl();
128
		accessor.get(IInstantiationService).createInstance(RemoveAction, tree, tree.getFocus(), searchView).run();
S
Sandeep Somavarapu 已提交
129 130 131 132 133
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.ReplaceActionId,
134
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
135
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.ReplaceActiveKey, Constants.MatchFocusKey),
136
	primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.KEY_1,
S
Sandeep Somavarapu 已提交
137
	handler: (accessor, args: any) => {
138
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
139
		const tree: ITree = searchView.getControl();
140
		accessor.get(IInstantiationService).createInstance(ReplaceAction, tree, tree.getFocus(), searchView).run();
S
Sandeep Somavarapu 已提交
141 142 143 144 145
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.ReplaceAllInFileActionId,
146
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
147
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.ReplaceActiveKey, Constants.FileFocusKey),
148 149
	primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.KEY_1,
	secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter],
S
Sandeep Somavarapu 已提交
150
	handler: (accessor, args: any) => {
151
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
152
		const tree: ITree = searchView.getControl();
153
		accessor.get(IInstantiationService).createInstance(ReplaceAllAction, tree, tree.getFocus(), searchView).run();
S
Sandeep Somavarapu 已提交
154 155 156
	}
});

157 158
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.ReplaceAllInFolderActionId,
159
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
160
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.ReplaceActiveKey, Constants.FolderFocusKey),
161 162
	primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.KEY_1,
	secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter],
163
	handler: (accessor, args: any) => {
164
		const searchView = getSearchView(accessor.get(IViewletService), accessor.get(IPanelService));
165
		const tree: ITree = searchView.getControl();
166
		accessor.get(IInstantiationService).createInstance(ReplaceAllInFolderAction, tree, tree.getFocus()).run();
167 168 169
	}
});

S
Sandeep Somavarapu 已提交
170 171
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.CloseReplaceWidgetActionId,
172
	weight: KeybindingWeight.WorkbenchContrib,
I
isidor 已提交
173
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.ReplaceInputBoxFocusedKey),
S
Sandeep Somavarapu 已提交
174 175
	primary: KeyCode.Escape,
	handler: (accessor, args: any) => {
176
		accessor.get(IInstantiationService).createInstance(CloseReplaceAction, Constants.CloseReplaceWidgetActionId, '').run();
S
Sandeep Somavarapu 已提交
177 178 179
	}
});

180 181
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: FocusNextInputAction.ID,
182
	weight: KeybindingWeight.WorkbenchContrib,
183
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.InputBoxFocusedKey),
184
	primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
185 186 187 188 189 190 191
	handler: (accessor, args: any) => {
		accessor.get(IInstantiationService).createInstance(FocusNextInputAction, FocusNextInputAction.ID, '').run();
	}
});

KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: FocusPreviousInputAction.ID,
192
	weight: KeybindingWeight.WorkbenchContrib,
193
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.InputBoxFocusedKey, Constants.SearchInputBoxFocusedKey.toNegated()),
194
	primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
195 196 197 198 199
	handler: (accessor, args: any) => {
		accessor.get(IInstantiationService).createInstance(FocusPreviousInputAction, FocusPreviousInputAction.ID, '').run();
	}
});

R
Rob Lourens 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.ReplaceActionId,
		title: ReplaceAction.LABEL
	},
	when: ContextKeyExpr.and(Constants.ReplaceActiveKey, Constants.MatchFocusKey),
	group: 'search',
	order: 1
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.ReplaceAllInFolderActionId,
		title: ReplaceAllInFolderAction.LABEL
	},
	when: ContextKeyExpr.and(Constants.ReplaceActiveKey, Constants.FolderFocusKey),
	group: 'search',
	order: 1
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.ReplaceAllInFileActionId,
		title: ReplaceAllAction.LABEL
	},
	when: ContextKeyExpr.and(Constants.ReplaceActiveKey, Constants.FileFocusKey),
	group: 'search',
	order: 1
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.RemoveActionId,
		title: RemoveAction.LABEL
	},
	when: Constants.FileMatchOrMatchFocusKey,
	group: 'search',
	order: 2
});

R
Rob Lourens 已提交
240 241
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.CopyMatchCommandId,
242
	weight: KeybindingWeight.WorkbenchContrib,
R
Rob Lourens 已提交
243 244 245 246 247 248 249 250 251 252 253 254
	when: Constants.FileMatchOrMatchFocusKey,
	primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
	handler: copyMatchCommand
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.CopyMatchCommandId,
		title: nls.localize('copyMatchLabel', "Copy")
	},
	when: Constants.FileMatchOrMatchFocusKey,
	group: 'search_2',
R
Rob Lourens 已提交
255
	order: 1
R
Rob Lourens 已提交
256 257
});

258 259
KeybindingsRegistry.registerCommandAndKeybindingRule({
	id: Constants.CopyPathCommandId,
260
	weight: KeybindingWeight.WorkbenchContrib,
261
	when: Constants.FileMatchOrFolderMatchFocusKey,
262 263 264 265 266 267 268 269 270 271 272 273
	primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C,
	win: {
		primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_C
	},
	handler: copyPathCommand
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.CopyPathCommandId,
		title: nls.localize('copyPathLabel', "Copy Path")
	},
274
	when: Constants.FileMatchOrFolderMatchFocusKey,
R
Rob Lourens 已提交
275
	group: 'search_2',
R
Rob Lourens 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
	order: 2
});

MenuRegistry.appendMenuItem(MenuId.SearchContext, {
	command: {
		id: Constants.CopyAllCommandId,
		title: nls.localize('copyAllLabel', "Copy All")
	},
	when: Constants.HasSearchResults,
	group: 'search_2',
	order: 3
});

CommandsRegistry.registerCommand({
	id: Constants.CopyAllCommandId,
	handler: copyAllCommand
292 293
});

294 295 296 297 298 299 300 301 302 303 304 305 306
CommandsRegistry.registerCommand({
	id: Constants.ClearSearchHistoryCommandId,
	handler: clearHistoryCommand
});

const clearSearchHistoryLabel = nls.localize('clearSearchHistoryLabel', "Clear Search History");
const ClearSearchHistoryCommand: ICommandAction = {
	id: Constants.ClearSearchHistoryCommandId,
	title: clearSearchHistoryLabel,
	category
};
MenuRegistry.addCommand(ClearSearchHistoryCommand);

307 308 309 310 311 312 313 314 315 316 317 318
CommandsRegistry.registerCommand({
	id: Constants.ToggleSearchViewPositionCommandId,
	handler: (accessor) => {
		const configurationService = accessor.get(IConfigurationService);
		const currentValue = configurationService.getValue<ISearchConfigurationProperties>('search').location;
		const toggleValue = currentValue === 'sidebar' ? 'panel' : 'sidebar';

		configurationService.updateValue('search.location', toggleValue);
	}
});

const toggleSearchViewPositionLabel = nls.localize('toggleSearchViewPositionLabel', "Toggle Search View Position");
319 320 321 322 323 324
const ToggleSearchViewPositionCommand: ICommandAction = {
	id: Constants.ToggleSearchViewPositionCommandId,
	title: toggleSearchViewPositionLabel,
	category
};
MenuRegistry.addCommand(ToggleSearchViewPositionCommand);
325
MenuRegistry.appendMenuItem(MenuId.SearchContext, {
326
	command: ToggleSearchViewPositionCommand,
327
	when: Constants.SearchViewVisibleKey,
R
Rob Lourens 已提交
328
	group: 'search_9',
329
	order: 1
330 331
});

Y
Yogesh 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344
CommandsRegistry.registerCommand({
	id: Constants.FocusSearchListCommandID,
	handler: focusSearchListCommand
});

const focusSearchListCommandLabel = nls.localize('focusSearchListCommandLabel', "Focus List");
const FocusSearchListCommand: ICommandAction = {
	id: Constants.FocusSearchListCommandID,
	title: focusSearchListCommandLabel,
	category
};
MenuRegistry.addCommand(FocusSearchListCommand);

I
isidor 已提交
345 346 347 348 349 350
const FIND_IN_FOLDER_ID = 'filesExplorer.findInFolder';
CommandsRegistry.registerCommand({
	id: FIND_IN_FOLDER_ID,
	handler: (accessor, resource?: URI) => {
		const listService = accessor.get(IListService);
		const viewletService = accessor.get(IViewletService);
351
		const panelService = accessor.get(IPanelService);
I
isidor 已提交
352
		const fileService = accessor.get(IFileService);
353
		const resources = getMultiSelectedResources(resource, listService, accessor.get(IEditorService));
I
isidor 已提交
354

355
		return openSearchView(viewletService, panelService, true).then(searchView => {
356 357 358 359 360 361 362 363 364 365
			if (resources && resources.length) {
				return fileService.resolveFiles(resources.map(resource => ({ resource }))).then(results => {
					const folders: URI[] = [];

					results.forEach(result => {
						if (result.success) {
							folders.push(result.stat.isDirectory ? result.stat.resource : dirname(result.stat.resource));
						}
					});

366
					searchView.searchInFolders(distinct(folders, folder => folder.toString()), (from, to) => relative(from, to));
367
				});
368
			}
369 370

			return void 0;
I
isidor 已提交
371
		});
I
isidor 已提交
372 373
	}
});
E
Erich Gamma 已提交
374

R
Rob Lourens 已提交
375 376 377 378 379 380 381
CommandsRegistry.registerCommand({
	id: ClearSearchResultsAction.ID,
	handler: (accessor, args: any) => {
		accessor.get(IInstantiationService).createInstance(ClearSearchResultsAction, ClearSearchResultsAction.ID, '').run();
	}
});

382 383 384 385 386 387 388
CommandsRegistry.registerCommand({
	id: RefreshAction.ID,
	handler: (accessor, args: any) => {
		accessor.get(IInstantiationService).createInstance(RefreshAction, RefreshAction.ID, '').run();
	}
});

I
isidor 已提交
389 390 391
const FIND_IN_WORKSPACE_ID = 'filesExplorer.findInWorkspace';
CommandsRegistry.registerCommand({
	id: FIND_IN_WORKSPACE_ID,
I
isidor 已提交
392
	handler: (accessor) => {
393 394
		return openSearchView(accessor.get(IViewletService), accessor.get(IPanelService), true).then(searchView => {
			searchView.searchInFolders(null, (from, to) => relative(from, to));
I
isidor 已提交
395 396 397
		});
	}
});
E
Erich Gamma 已提交
398

I
isidor 已提交
399
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
I
isidor 已提交
400 401
	group: '4_search',
	order: 10,
I
isidor 已提交
402 403 404 405
	command: {
		id: FIND_IN_FOLDER_ID,
		title: nls.localize('findInFolder', "Find in Folder...")
	},
406
	when: ContextKeyExpr.and(ExplorerFolderContext, ResourceContextKey.Scheme.isEqualTo(Schemas.file)) // todo@remote
I
isidor 已提交
407
});
E
Erich Gamma 已提交
408

I
isidor 已提交
409
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
I
isidor 已提交
410 411
	group: '4_search',
	order: 10,
I
isidor 已提交
412 413 414 415 416 417
	command: {
		id: FIND_IN_WORKSPACE_ID,
		title: nls.localize('findInWorkspace', "Find in Workspace...")
	},
	when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext.toNegated())
});
E
Erich Gamma 已提交
418 419


420
class ShowAllSymbolsAction extends Action {
421 422 423
	static readonly ID = 'workbench.action.showAllSymbols';
	static readonly LABEL = nls.localize('showTriggerActions', "Go to Symbol in Workspace...");
	static readonly ALL_SYMBOLS_PREFIX = '#';
E
Erich Gamma 已提交
424

425 426 427 428 429 430 431 432 433 434
	constructor(
		actionId: string, actionLabel: string,
		@IQuickOpenService private quickOpenService: IQuickOpenService,
		@ICodeEditorService private editorService: ICodeEditorService) {
		super(actionId, actionLabel);
		this.enabled = !!this.quickOpenService;
	}

	public run(context?: any): TPromise<void> {

435
		let prefix = ShowAllSymbolsAction.ALL_SYMBOLS_PREFIX;
436
		let inputSelection: { start: number; end: number; } = void 0;
437 438
		let editor = this.editorService.getFocusedCodeEditor();
		const word = editor && getSelectionSearchString(editor);
439 440 441 442
		if (word) {
			prefix = prefix + word;
			inputSelection = { start: 1, end: word.length + 1 };
		}
E
Erich Gamma 已提交
443

444 445 446
		this.quickOpenService.show(prefix, { inputSelection });

		return TPromise.as(null);
E
Erich Gamma 已提交
447 448 449
	}
}

450
// Register View in Viewlet and Panel area
451 452
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor(
	SearchView,
453
	VIEW_ID,
454 455
	nls.localize('name', "Search"),
	'search',
456
	1
457
));
I
isidor 已提交
458 459

Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
460
	SearchView,
461
	VIEW_ID,
E
Erich Gamma 已提交
462 463 464 465 466
	nls.localize('name', "Search"),
	'search',
	10
));

467
// Register view location updater
468
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SearchViewLocationUpdater, LifecyclePhase.Restoring);
469

S
Sandeep Somavarapu 已提交
470
// Actions
B
Benjamin Pasero 已提交
471
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
E
Erich Gamma 已提交
472

473 474
// Show Search and Find in Files are redundant, but we can't break keybindings by removing one. So it's the same action, same keybinding, registered to different IDs.
// Show Search 'when' is redundant but if the two conflict with exactly the same keybinding and 'when' clause, then they can show up as "unbound" - #51780
B
Benjamin Pasero 已提交
475
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenSearchViewletAction, VIEW_ID, OpenSearchViewletAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, Constants.SearchViewVisibleKey.toNegated()), 'View: Show Search', nls.localize('view', "View"));
476
registry.registerWorkbenchAction(new SyncActionDescriptor(FindInFilesAction, Constants.FindInFilesActionId, nls.localize('findInFiles', "Find in Files"), { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }), 'Find in Files', category);
477 478 479 480 481 482 483 484
MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, {
	group: '4_find_global',
	command: {
		id: Constants.FindInFilesActionId,
		title: nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files")
	},
	order: 1
});
485

486 487
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextSearchResultAction, FocusNextSearchResultAction.ID, FocusNextSearchResultAction.LABEL, { primary: KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Next Search Result', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousSearchResultAction, FocusPreviousSearchResultAction.ID, FocusPreviousSearchResultAction.LABEL, { primary: KeyMod.Shift | KeyCode.F4 }, ContextKeyExpr.and(Constants.HasSearchResults)), 'Focus Previous Search Result', category);
488

489
registry.registerWorkbenchAction(new SyncActionDescriptor(ReplaceInFilesAction, ReplaceInFilesAction.ID, ReplaceInFilesAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H }), 'Replace in Files', category);
490 491 492 493 494 495 496 497
MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, {
	group: '4_find_global',
	command: {
		id: ReplaceInFilesAction.ID,
		title: nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files")
	},
	order: 2
});
S
Sandeep Somavarapu 已提交
498

R
Rob Lourens 已提交
499
KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({
R
Rob Lourens 已提交
500
	id: Constants.ToggleCaseSensitiveCommandId,
501
	weight: KeybindingWeight.WorkbenchContrib,
S
Sandeep Somavarapu 已提交
502
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.SearchViewFocusedKey, Constants.FileMatchOrFolderMatchFocusKey.toNegated()),
503
	handler: toggleCaseSensitiveCommand
R
Rob Lourens 已提交
504 505 506
}, ToggleCaseSensitiveKeybinding));

KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({
R
Rob Lourens 已提交
507
	id: Constants.ToggleWholeWordCommandId,
508
	weight: KeybindingWeight.WorkbenchContrib,
S
Sandeep Somavarapu 已提交
509
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.SearchViewFocusedKey),
510
	handler: toggleWholeWordCommand
R
Rob Lourens 已提交
511 512 513
}, ToggleWholeWordKeybinding));

KeybindingsRegistry.registerCommandAndKeybindingRule(objects.assign({
R
Rob Lourens 已提交
514
	id: Constants.ToggleRegexCommandId,
515
	weight: KeybindingWeight.WorkbenchContrib,
S
Sandeep Somavarapu 已提交
516
	when: ContextKeyExpr.and(Constants.SearchViewVisibleKey, Constants.SearchViewFocusedKey),
517
	handler: toggleRegexCommand
R
Rob Lourens 已提交
518
}, ToggleRegexKeybinding));
S
Sandeep Somavarapu 已提交
519

520
registry.registerWorkbenchAction(new SyncActionDescriptor(CollapseDeepestExpandedLevelAction, CollapseDeepestExpandedLevelAction.ID, CollapseDeepestExpandedLevelAction.LABEL), 'Search: Collapse All', category);
521 522
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ShowAllSymbolsAction.ID, ShowAllSymbolsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...');

R
Rob Lourens 已提交
523 524 525
registry.registerWorkbenchAction(new SyncActionDescriptor(RefreshAction, RefreshAction.ID, RefreshAction.LABEL), 'Search: Refresh', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearSearchResultsAction, ClearSearchResultsAction.ID, ClearSearchResultsAction.LABEL), 'Search: Clear', category);

S
Sandeep Somavarapu 已提交
526

E
Erich Gamma 已提交
527
// Register Quick Open Handler
B
Benjamin Pasero 已提交
528
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerDefaultQuickOpenHandler(
E
Erich Gamma 已提交
529
	new QuickOpenHandlerDescriptor(
530 531
		OpenAnythingHandler,
		OpenAnythingHandler.ID,
E
Erich Gamma 已提交
532
		'',
533
		defaultQuickOpenContextKey,
B
Benjamin Pasero 已提交
534
		nls.localize('openAnythingHandlerDescription', "Go to File")
E
Erich Gamma 已提交
535 536 537
	)
);

B
Benjamin Pasero 已提交
538
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
539
	new QuickOpenHandlerDescriptor(
540 541
		OpenSymbolHandler,
		OpenSymbolHandler.ID,
542
		ShowAllSymbolsAction.ALL_SYMBOLS_PREFIX,
543
		'inWorkspaceSymbolsPicker',
544 545
		[
			{
546
				prefix: ShowAllSymbolsAction.ALL_SYMBOLS_PREFIX,
547
				needsEditor: false,
B
Benjamin Pasero 已提交
548
				description: nls.localize('openSymbolDescriptionNormal', "Go to Symbol in Workspace")
549 550 551 552 553
			}
		]
	)
);

E
Erich Gamma 已提交
554
// Configuration
B
Benjamin Pasero 已提交
555
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
E
Erich Gamma 已提交
556
configurationRegistry.registerConfiguration({
557 558 559 560 561
	id: 'search',
	order: 13,
	title: nls.localize('searchConfigurationTitle', "Search"),
	type: 'object',
	properties: {
E
Erich Gamma 已提交
562
		'search.exclude': {
563
			type: 'object',
564
			markdownDescription: nls.localize('exclude', "Configure glob patterns for excluding files and folders in searches. Inherits all glob patterns from the `#files.exclude#` setting. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)."),
565 566 567
			default: { '**/node_modules': true, '**/bower_components': true },
			additionalProperties: {
				anyOf: [
E
Erich Gamma 已提交
568
					{
569 570
						type: 'boolean',
						description: nls.localize('exclude.boolean', "The glob pattern to match file paths against. Set to true or false to enable or disable the pattern."),
E
Erich Gamma 已提交
571 572
					},
					{
573 574 575 576 577 578 579
						type: 'object',
						properties: {
							when: {
								type: 'string', // expression ({ "**/*.js": { "when": "$(basename).js" } })
								pattern: '\\w*\\$\\(basename\\)\\w*',
								default: '$(basename).ext',
								description: nls.localize('exclude.when', 'Additional check on the siblings of a matching file. Use $(basename) as variable for the matching file name.')
E
Erich Gamma 已提交
580 581 582 583
							}
						}
					}
				]
S
Sandeep Somavarapu 已提交
584
			},
585
			scope: ConfigurationScope.RESOURCE
586
		},
587
		'search.useRipgrep': {
588
			type: 'boolean',
589 590
			description: nls.localize('useRipgrep', "Deprecated. This setting now falls back on \"search.usePCRE2\"."),
			deprecationMessage: nls.localize('useRipgrepDeprecated', "Deprecated. Consider \"search.usePCRE2\" for advanced regex feature support."),
591
			default: true
592
		},
593 594 595 596 597 598
		'search.disableRipgrep': {
			type: 'boolean',
			description: nls.localize('disableRipgrep', "Deprecated. Controls whether to use ripgrep in text and file search."),
			deprecationMessage: nls.localize('disableRipgrepDeprecated', "Deprecated. Consider \"search.usePCRE2\" for advanced regex feature support."),
			default: false
		},
599
		'search.useIgnoreFiles': {
600
			type: 'boolean',
601
			markdownDescription: nls.localize('useIgnoreFiles', "Controls whether to use `.gitignore` and `.ignore` files when searching for files."),
602 603
			default: true,
			scope: ConfigurationScope.RESOURCE
604
		},
P
pkoushik 已提交
605 606 607 608
		'search.useGlobalIgnoreFiles': {
			type: 'boolean',
			markdownDescription: nls.localize('useGlobalIgnoreFiles', "Controls whether to use global `.gitignore` and `.ignore` files when searching for files."),
			default: false,
P
pkoushik 已提交
609
			scope: ConfigurationScope.RESOURCE
P
pkoushik 已提交
610
		},
611
		'search.quickOpen.includeSymbols': {
612
			type: 'boolean',
613
			description: nls.localize('search.quickOpen.includeSymbols', "Whether to include results from a global symbol search in the file results for Quick Open."),
614
			default: false
615
		},
B
Benjamin Pasero 已提交
616 617 618 619 620
		'search.quickOpen.includeHistory': {
			type: 'boolean',
			description: nls.localize('search.quickOpen.includeHistory', "Whether to include results from recently opened files in the file results for Quick Open."),
			default: true
		},
621
		'search.followSymlinks': {
622 623 624
			type: 'boolean',
			description: nls.localize('search.followSymlinks', "Controls whether to follow symlinks while searching."),
			default: true
625 626
		},
		'search.smartCase': {
627
			type: 'boolean',
628
			description: nls.localize('search.smartCase', "Search case-insensitively if the pattern is all lowercase, otherwise, search case-sensitively."),
629
			default: false
630 631
		},
		'search.globalFindClipboard': {
632 633
			type: 'boolean',
			default: false,
I
isidor 已提交
634
			description: nls.localize('search.globalFindClipboard', "Controls whether the search view should read or modify the shared find clipboard on macOS."),
635 636 637
			included: platform.isMacintosh
		},
		'search.location': {
638
			type: 'string',
639 640
			enum: ['sidebar', 'panel'],
			default: 'sidebar',
641
			description: nls.localize('search.location', "Controls whether the search will be shown as a view in the sidebar or as a panel in the panel area for more horizontal space."),
N
Nil 已提交
642
		},
R
Rob Lourens 已提交
643
		'search.collapseResults': {
N
Nil 已提交
644
			type: 'string',
R
Rob Lourens 已提交
645 646 647 648 649 650
			enum: ['auto', 'alwaysCollapse', 'alwaysExpand'],
			enumDescriptions: [
				'Files with less than 10 results are expanded. Others are collapsed.',
				'',
				''
			],
N
Nil 已提交
651
			default: 'auto',
R
Rob Lourens 已提交
652
			description: nls.localize('search.collapseAllResults', "Controls whether the search results will be collapsed or expanded."),
653 654 655 656
		},
		'search.useReplacePreview': {
			type: 'boolean',
			default: true,
657
			description: nls.localize('search.useReplacePreview', "Controls whether to open Replace Preview when selecting or replacing a match."),
658 659 660 661 662
		},
		'search.showLineNumbers': {
			type: 'boolean',
			default: false,
			description: nls.localize('search.showLineNumbers', "Controls whether to show line numbers for search results."),
663 664 665 666 667 668 669 670 671 672 673
		},
		'searchRipgrep.enable': {
			type: 'boolean',
			default: false,
			deprecationMessage: nls.localize('search.searchRipgrepEnableDeprecated', "Deprecated. Use \"search.runInExtensionHost\" instead"),
			description: nls.localize('search.searchRipgrepEnable', "Whether to run search in the extension host")
		},
		'search.runInExtensionHost': {
			type: 'boolean',
			default: false,
			description: nls.localize('search.searchRipgrepEnable', "Whether to run search in the extension host")
R
Rob Lourens 已提交
674 675 676 677 678
		},
		'search.usePCRE2': {
			type: 'boolean',
			default: false,
			description: nls.localize('search.usePCRE2', "Whether to use the PCRE2 regex engine in text search. This enables using some advaned regex features like lookbehind and backreferences.")
679
		}
E
Erich Gamma 已提交
680
	}
J
Johannes Rieken 已提交
681
});
682

683
registerLanguageCommand('_executeWorkspaceSymbolProvider', function (accessor, args: { query: string; }) {
684 685 686 687 688 689
	let { query } = args;
	if (typeof query !== 'string') {
		throw illegalArgument();
	}
	return getWorkspaceSymbols(query);
});
690 691 692 693 694 695 696 697 698 699 700

// View menu

MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
	group: '3_views',
	command: {
		id: VIEW_ID,
		title: nls.localize({ key: 'miViewSearch', comment: ['&& denotes a mnemonic'] }, "&&Search")
	},
	order: 2
});
701 702 703 704 705 706 707 708 709 710 711

// Go to menu

MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
	group: 'z_go_to',
	command: {
		id: 'workbench.action.showAllSymbols',
		title: nls.localize({ key: 'miGotoSymbolInWorkspace', comment: ['&& denotes a mnemonic'] }, "Go to Symbol in &&Workspace...")
	},
	order: 3
});