searchEditor.ts 21.3 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6 7
import * as DOM from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
8
import { Delayer } from 'vs/base/common/async';
9 10
import { CancellationToken } from 'vs/base/common/cancellation';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
11
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
12 13 14 15
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/searchEditor';
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
import type { IEditorOptions } from 'vs/editor/common/config/editorOptions';
16
import { Range } from 'vs/editor/common/core/range';
J
Jackson Kearl 已提交
17
import { TrackedRangeStickiness } from 'vs/editor/common/model';
18
import { IModelService } from 'vs/editor/common/services/modelService';
19
import { ReferencesController } from 'vs/editor/contrib/gotoSymbol/peek/referencesController';
20 21
import { localize } from 'vs/nls';
import { ICommandService } from 'vs/platform/commands/common/commands';
22
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
23
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
24 25 26
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
27
import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress';
28 29
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
30 31
import { inputBorder, registerColor, searchEditorFindMatch, searchEditorFindMatchBorder } from 'vs/platform/theme/common/colorRegistry';
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
32
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
33 34
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
35
import { EditorOptions } from 'vs/workbench/common/editor';
36 37
import { ExcludePatternInputWidget, PatternInputWidget } from 'vs/workbench/contrib/search/browser/patternInputWidget';
import { SearchWidget } from 'vs/workbench/contrib/search/browser/searchWidget';
38
import { InputBoxFocusedKey } from 'vs/workbench/contrib/search/common/constants';
39 40
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
import { getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search';
J
Jackson Kearl 已提交
41
import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel';
42
import { InSearchEditor } from 'vs/workbench/contrib/searchEditor/browser/constants';
43 44 45
import type { SearchConfiguration, SearchEditorInput } from 'vs/workbench/contrib/searchEditor/browser/searchEditorInput';
import { extractSearchQuery, serializeSearchConfiguration, serializeSearchResultForEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization';
import { IPatternInfo, ISearchConfigurationProperties, ITextQuery } from 'vs/workbench/services/search/common/search';
46 47

const RESULT_LINE_REGEX = /^(\s+)(\d+)(:| )(\s+)(.*)$/;
48
const FILE_LINE_REGEX = /^(\S.*):$/;
49 50 51 52 53 54 55 56 57 58 59 60

export class SearchEditor extends BaseEditor {
	static readonly ID: string = 'workbench.editor.searchEditor';

	private queryEditorWidget!: SearchWidget;
	private searchResultEditor!: CodeEditorWidget;
	private queryEditorContainer!: HTMLElement;
	private dimension?: DOM.Dimension;
	private inputPatternIncludes!: PatternInputWidget;
	private inputPatternExcludes!: ExcludePatternInputWidget;
	private includesExcludesContainer!: HTMLElement;
	private toggleQueryDetailsButton!: HTMLElement;
61
	private messageBox!: HTMLElement;
62 63 64

	private runSearchDelayer = new Delayer(300);
	private pauseSearching: boolean = false;
65
	private showingIncludesExcludes: boolean = false;
66 67
	private inSearchEditorContextKey: IContextKey<boolean>;
	private inputFocusContextKey: IContextKey<boolean>;
68
	private searchOperation: LongRunningOperation;
J
Jackson Kearl 已提交
69
	private searchHistoryDelayer: Delayer<void>;
70
	private messageDisposables: IDisposable[] = [];
71 72 73 74 75 76 77 78 79 80 81 82

	constructor(
		@ITelemetryService telemetryService: ITelemetryService,
		@IThemeService themeService: IThemeService,
		@IStorageService storageService: IStorageService,
		@IModelService private readonly modelService: IModelService,
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
		@ILabelService private readonly labelService: ILabelService,
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IContextViewService private readonly contextViewService: IContextViewService,
		@ICommandService private readonly commandService: ICommandService,
83
		@IContextKeyService readonly contextKeyService: IContextKeyService,
84
		@IEditorProgressService readonly progressService: IEditorProgressService,
85 86
	) {
		super(SearchEditor.ID, telemetryService, themeService, storageService);
87 88
		this.inSearchEditorContextKey = InSearchEditor.bindTo(contextKeyService);
		this.inputFocusContextKey = InputBoxFocusedKey.bindTo(contextKeyService);
89
		this.searchOperation = this._register(new LongRunningOperation(progressService));
J
Jackson Kearl 已提交
90
		this.searchHistoryDelayer = new Delayer<void>(2000);
91 92 93 94 95
	}

	createEditor(parent: HTMLElement) {
		DOM.addClass(parent, 'search-editor');

96 97 98
		this.createQueryEditor(parent);
		this.createResultsEditor(parent);
	}
99

100 101
	private createQueryEditor(parent: HTMLElement) {
		this.queryEditorContainer = DOM.append(parent, DOM.$('.query-container'));
102 103 104
		this.queryEditorWidget = this._register(this.instantiationService.createInstance(SearchWidget, this.queryEditorContainer, { _hideReplaceToggle: true, showContextToggle: true }));
		this._register(this.queryEditorWidget.onReplaceToggled(() => this.reLayout()));
		this._register(this.queryEditorWidget.onDidHeightChange(() => this.reLayout()));
J
Jackson Kearl 已提交
105 106 107
		this.queryEditorWidget.onSearchSubmit(() => this.runSearch(true, true)); // onSearchSubmit has an internal delayer, so skip over ours.
		this.queryEditorWidget.searchInput.onDidOptionChange(() => this.runSearch(false));
		this.queryEditorWidget.onDidToggleContext(() => this.runSearch(false));
108 109 110

		// Includes/Excludes Dropdown
		this.includesExcludesContainer = DOM.append(this.queryEditorContainer, DOM.$('.includes-excludes'));
111

112 113 114 115
		// // Toggle query details button
		this.toggleQueryDetailsButton = DOM.append(this.includesExcludesContainer, DOM.$('.expand.codicon.codicon-ellipsis', { tabindex: 0, role: 'button', title: localize('moreSearch', "Toggle Search Details") }));
		this._register(DOM.addDisposableListener(this.toggleQueryDetailsButton, DOM.EventType.CLICK, e => {
			DOM.EventHelper.stop(e);
116
			this.toggleIncludesExcludes();
117 118 119 120 121
		}));
		this._register(DOM.addDisposableListener(this.toggleQueryDetailsButton, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
			const event = new StandardKeyboardEvent(e);
			if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
				DOM.EventHelper.stop(e);
122
				this.toggleIncludesExcludes();
123 124 125 126 127 128 129
			}
		}));
		this._register(DOM.addDisposableListener(this.toggleQueryDetailsButton, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
			const event = new StandardKeyboardEvent(e);
			if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
				if (this.queryEditorWidget.isReplaceActive()) {
					this.queryEditorWidget.focusReplaceAllAction();
130 131
				}
				else {
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
					this.queryEditorWidget.isReplaceShown() ? this.queryEditorWidget.replaceInput.focusOnPreserve() : this.queryEditorWidget.focusRegexAction();
				}
				DOM.EventHelper.stop(e);
			}
		}));

		// // Includes
		const folderIncludesList = DOM.append(this.includesExcludesContainer, DOM.$('.file-types.includes'));
		const filesToIncludeTitle = localize('searchScope.includes', "files to include");
		DOM.append(folderIncludesList, DOM.$('h4', undefined, filesToIncludeTitle));
		this.inputPatternIncludes = this._register(this.instantiationService.createInstance(PatternInputWidget, folderIncludesList, this.contextViewService, {
			ariaLabel: localize('label.includes', 'Search Include Patterns'),
		}));
		this.inputPatternIncludes.onSubmit(_triggeredOnType => this.runSearch());

		// // Excludes
		const excludesList = DOM.append(this.includesExcludesContainer, DOM.$('.file-types.excludes'));
		const excludesTitle = localize('searchScope.excludes', "files to exclude");
		DOM.append(excludesList, DOM.$('h4', undefined, excludesTitle));
		this.inputPatternExcludes = this._register(this.instantiationService.createInstance(ExcludePatternInputWidget, excludesList, this.contextViewService, {
			ariaLabel: localize('label.excludes', 'Search Exclude Patterns'),
		}));
		this.inputPatternExcludes.onSubmit(_triggeredOnType => this.runSearch());
		this.inputPatternExcludes.onChangeIgnoreBox(() => this.runSearch());
156 157 158

		[this.queryEditorWidget.searchInput, this.inputPatternIncludes, this.inputPatternExcludes].map(input =>
			this._register(attachInputBoxStyler(input, this.themeService, { inputBorder: searchEditorTextInputBorder })));
159 160 161 162 163 164 165 166 167 168 169 170

		// Messages
		this.messageBox = DOM.append(this.queryEditorContainer, DOM.$('.messages'));
	}


	private toggleRunAgainMessage(show: boolean) {
		DOM.clearNode(this.messageBox);
		dispose(this.messageDisposables);
		this.messageDisposables = [];

		if (show) {
J
Naming  
Jackson Kearl 已提交
171
			const runAgainLink = DOM.append(this.messageBox, DOM.$('a.pointer.prominent.message', {}, localize('runSearch', "Run Search")));
172 173 174 175 176
			this.messageDisposables.push(DOM.addDisposableListener(runAgainLink, DOM.EventType.CLICK, async () => {
				await this.runSearch(true, true);
				this.toggleRunAgainMessage(false);
			}));
		}
177
	}
178

179
	private createResultsEditor(parent: HTMLElement) {
180
		const searchResultContainer = DOM.append(parent, DOM.$('.search-results'));
181 182 183 184 185 186 187 188
		const getSearchEditorOptions = () => this.configurationService.getValue<IEditorOptions>('editor', { overrideIdentifier: 'search-result' });
		const configuration: IEditorOptions = getSearchEditorOptions();
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('editor')) {
				this.searchResultEditor.updateOptions(getSearchEditorOptions());
			}
		}));

189 190 191 192 193 194 195 196 197 198 199 200
		const options: ICodeEditorWidgetOptions = {};
		this.searchResultEditor = this._register(this.instantiationService.createInstance(CodeEditorWidget, searchResultContainer, configuration, options));
		this.searchResultEditor.onMouseUp(e => {

			if (e.event.detail === 2) {
				const behaviour = this.configurationService.getValue<ISearchConfigurationProperties>('search').searchEditorPreview.doubleClickBehaviour;
				const position = e.target.position;
				if (position && behaviour !== 'selectWord') {
					const line = this.searchResultEditor.getModel()?.getLineContent(position.lineNumber) ?? '';
					if (line.match(RESULT_LINE_REGEX)) {
						this.searchResultEditor.setSelection(Range.fromPositions(position));
						this.commandService.executeCommand(behaviour === 'goToLocation' ? 'editor.action.goToDeclaration' : 'editor.action.openDeclarationToTheSide');
201 202 203
					} else if (line.match(FILE_LINE_REGEX)) {
						this.searchResultEditor.setSelection(Range.fromPositions(position));
						this.commandService.executeCommand('editor.action.peekDefinition');
204 205 206 207
					}
				}
			}
		});
208

J
Jackson Kearl 已提交
209
		this._register(this.onDidBlur(() => this.saveViewState()));
J
Jackson Kearl 已提交
210

211 212
		this._register(this.searchResultEditor.onKeyDown(e => e.keyCode === KeyCode.Escape && this.queryEditorWidget.searchInput.focus()));

213
		this._register(this.searchResultEditor.onDidChangeModelContent(() => this.getInput()?.setDirty(true)));
214 215 216 217 218 219 220 221

		[this.queryEditorWidget.searchInputFocusTracker, this.queryEditorWidget.replaceInputFocusTracker, this.inputPatternExcludes.inputFocusTracker, this.inputPatternIncludes.inputFocusTracker]
			.map(tracker => {
				this._register(tracker.onDidFocus(() => setTimeout(() => this.inputFocusContextKey.set(true), 0)));
				this._register(tracker.onDidBlur(() => this.inputFocusContextKey.set(false)));
			});
	}

J
Jackson Kearl 已提交
222 223 224 225 226

	getControl() {
		return this.searchResultEditor;
	}

J
Jackson Kearl 已提交
227
	focus() {
J
Jackson Kearl 已提交
228 229 230 231 232 233
		const input = this.getInput();
		if (input && input.viewState && input.viewState.focused === 'editor') {
			this.searchResultEditor.focus();
		} else {
			this.queryEditorWidget.focus();
		}
J
Jackson Kearl 已提交
234 235
	}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
	focusNextInput() {
		if (this.queryEditorWidget.searchInputHasFocus()) {
			if (this.showingIncludesExcludes) {
				this.inputPatternIncludes.focus();
			} else {
				this.searchResultEditor.focus();
			}
		} else if (this.inputPatternIncludes.inputHasFocus()) {
			this.inputPatternExcludes.focus();
		} else if (this.inputPatternExcludes.inputHasFocus()) {
			this.searchResultEditor.focus();
		} else if (this.searchResultEditor.hasWidgetFocus()) {
			// pass
		}
	}

	focusPrevInput() {
		if (this.queryEditorWidget.searchInputHasFocus()) {
			this.searchResultEditor.focus(); // wrap
		} else if (this.inputPatternIncludes.inputHasFocus()) {
			this.queryEditorWidget.searchInput.focus();
		} else if (this.inputPatternExcludes.inputHasFocus()) {
			this.inputPatternIncludes.focus();
		} else if (this.searchResultEditor.hasWidgetFocus()) {
J
Jackson Kearl 已提交
260
			// unreachable.
261
		}
262 263
	}

264 265
	toggleWholeWords() {
		this.queryEditorWidget.searchInput.setWholeWords(!this.queryEditorWidget.searchInput.getWholeWords());
J
Jackson Kearl 已提交
266
		this.runSearch(false);
267 268 269 270
	}

	toggleRegex() {
		this.queryEditorWidget.searchInput.setRegex(!this.queryEditorWidget.searchInput.getRegex());
J
Jackson Kearl 已提交
271
		this.runSearch(false);
272 273 274 275
	}

	toggleCaseSensitive() {
		this.queryEditorWidget.searchInput.setCaseSensitive(!this.queryEditorWidget.searchInput.getCaseSensitive());
J
Jackson Kearl 已提交
276
		this.runSearch(false);
277 278
	}

279 280 281 282
	toggleContextLines() {
		this.queryEditorWidget.toggleContextLines();
	}

283 284 285 286
	toggleQueryDetails() {
		this.toggleIncludesExcludes();
	}

J
Jackson Kearl 已提交
287
	async runSearch(resetCursor = true, instant = false) {
288
		if (!this.pauseSearching) {
289
			await this.runSearchDelayer.trigger(async () => {
J
Jackson Kearl 已提交
290 291 292 293 294
				await this.doRunSearch();
				if (resetCursor) {
					this.searchResultEditor.setSelection(new Range(1, 1, 1, 1));
				}
			}, instant ? 0 : undefined);
295 296 297 298 299 300
		}
	}

	private async doRunSearch() {
		const startInput = this.input;

J
Jackson Kearl 已提交
301 302 303 304 305 306
		this.searchHistoryDelayer.trigger(() => {
			this.queryEditorWidget.searchInput.onSearchSubmit();
			this.inputPatternExcludes.onSearchSubmit();
			this.inputPatternIncludes.onSearchSubmit();
		});

307 308 309 310 311 312 313 314
		const config: SearchConfiguration = {
			caseSensitive: this.queryEditorWidget.searchInput.getCaseSensitive(),
			contextLines: this.queryEditorWidget.contextLines(),
			excludes: this.inputPatternExcludes.getValue(),
			includes: this.inputPatternIncludes.getValue(),
			query: this.queryEditorWidget.searchInput.getValue(),
			regexp: this.queryEditorWidget.searchInput.getRegex(),
			wholeWord: this.queryEditorWidget.searchInput.getWholeWords(),
315 316
			useIgnores: this.inputPatternExcludes.useExcludesAndIgnoreFiles(),
			showIncludesExcludes: this.showingIncludesExcludes
317 318
		};

319 320
		if (!config.query) { return; }

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
		const content: IPatternInfo = {
			pattern: config.query,
			isRegExp: config.regexp,
			isCaseSensitive: config.caseSensitive,
			isWordMatch: config.wholeWord,
		};

		const options: ITextQueryBuilderOptions = {
			_reason: 'searchEditor',
			extraFileResources: this.instantiationService.invokeFunction(getOutOfWorkspaceEditorResources),
			maxResults: 10000,
			disregardIgnoreFiles: !config.useIgnores,
			disregardExcludeSettings: !config.useIgnores,
			excludePattern: config.excludes,
			includePattern: config.includes,
			previewOptions: {
				matchLines: 1,
				charsPerLine: 1000
			},
			afterContext: config.contextLines,
			beforeContext: config.contextLines,
			isSmartCase: this.configurationService.getValue<ISearchConfigurationProperties>('search').smartCase,
			expandPatterns: true
		};

		const folderResources = this.contextService.getWorkspace().folders;
		let query: ITextQuery;
		try {
			const queryBuilder = this.instantiationService.createInstance(QueryBuilder);
			query = queryBuilder.text(content, folderResources.map(folder => folder.uri), options);
		}
		catch (err) {
			return;
		}
		const searchModel = this.instantiationService.createInstance(SearchModel);
356 357
		this.searchOperation.start(500);
		await searchModel.search(query).finally(() => this.searchOperation.stop());
J
Jackson Kearl 已提交
358 359
		const input = this.getInput();
		if (!input || input !== startInput) {
360 361 362 363
			searchModel.dispose();
			return;
		}

364 365
		const controller = ReferencesController.get(this.searchResultEditor);
		controller.closeWidget(false);
366
		const labelFormatter = (uri: URI): string => this.labelService.getUriLabel(uri, { relative: true });
367
		const results = serializeSearchResultForEditor(searchModel.searchResult, config.includes, config.excludes, config.contextLines, labelFormatter, false);
J
Jackson Kearl 已提交
368
		const { header, body } = await input.getModels();
369 370
		this.modelService.updateModel(body, results.text);
		header.setValue(serializeSearchConfiguration(config));
371

J
Jackson Kearl 已提交
372 373 374
		input.setDirty(input.resource.scheme !== 'search-editor');
		input.setHighlights(results.matchRanges.map(range =>
			({ range, options: { className: 'searchEditorFindMatch', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } })));
375

376 377 378 379 380 381 382 383
		searchModel.dispose();
	}

	layout(dimension: DOM.Dimension) {
		this.dimension = dimension;
		this.reLayout();
	}

384 385 386 387 388 389 390 391
	getSelected() {
		const selection = this.searchResultEditor.getSelection();
		if (selection) {
			return this.searchResultEditor.getModel()?.getValueInRange(selection) ?? '';
		}
		return '';
	}

392 393 394 395 396 397 398 399 400
	private reLayout() {
		if (this.dimension) {
			this.queryEditorWidget.setWidth(this.dimension.width - 28 /* container margin */);
			this.searchResultEditor.layout({ height: this.dimension.height - DOM.getTotalHeight(this.queryEditorContainer), width: this.dimension.width });
			this.inputPatternExcludes.setWidth(this.dimension.width - 28 /* container margin */);
			this.inputPatternIncludes.setWidth(this.dimension.width - 28 /* container margin */);
		}
	}

J
Jackson Kearl 已提交
401 402 403 404
	private getInput(): SearchEditorInput | undefined {
		return this._input as SearchEditorInput;
	}

405
	async setInput(newInput: SearchEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
J
Jackson Kearl 已提交
406 407
		this.saveViewState();

408
		await super.setInput(newInput, options, token);
409
		this.inSearchEditorContextKey.set(true);
410

411
		const { body, header } = await newInput.getModels();
412

413
		this.searchResultEditor.setModel(body);
414
		this.pauseSearching = true;
415

416
		const config = extractSearchQuery(header);
417
		this.toggleRunAgainMessage(body.getLineCount() === 1 && body.getValue() === '' && config.query !== '');
418 419 420 421 422 423 424 425 426 427

		this.queryEditorWidget.setValue(config.query, true);
		this.queryEditorWidget.searchInput.setCaseSensitive(config.caseSensitive);
		this.queryEditorWidget.searchInput.setRegex(config.regexp);
		this.queryEditorWidget.searchInput.setWholeWords(config.wholeWord);
		this.queryEditorWidget.setContextLines(config.contextLines);
		this.inputPatternExcludes.setValue(config.excludes);
		this.inputPatternIncludes.setValue(config.includes);
		this.inputPatternExcludes.setUseExcludesAndIgnoreFiles(config.useIgnores);
		this.toggleIncludesExcludes(config.showIncludesExcludes);
428

J
Jackson Kearl 已提交
429
		this.restoreViewState();
430 431 432
		this.pauseSearching = false;
	}

433
	private toggleIncludesExcludes(_shouldShow?: boolean): void {
434
		const cls = 'expanded';
435
		const shouldShow = _shouldShow ?? !DOM.hasClass(this.includesExcludesContainer, cls);
436 437 438 439 440 441 442 443 444

		if (shouldShow) {
			this.toggleQueryDetailsButton.setAttribute('aria-expanded', 'true');
			DOM.addClass(this.includesExcludesContainer, cls);
		} else {
			this.toggleQueryDetailsButton.setAttribute('aria-expanded', 'false');
			DOM.removeClass(this.includesExcludesContainer, cls);
		}

445 446
		this.showingIncludesExcludes = DOM.hasClass(this.includesExcludesContainer, cls);

447 448 449 450 451 452
		this.reLayout();
	}

	getModel() {
		return this.searchResultEditor.getModel();
	}
453

J
Jackson Kearl 已提交
454 455 456 457 458 459
	private saveViewState() {
		const input = this.getInput();
		if (!input) { return; }

		if (this.searchResultEditor.hasWidgetFocus()) {
			const viewState = this.searchResultEditor.saveViewState();
460 461 462
			if (viewState) {
				input.viewState = { focused: 'editor', state: viewState };
			}
J
Jackson Kearl 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
		} else {
			input.viewState = { focused: 'input' };
		}
	}

	private restoreViewState() {
		const input = this.getInput();
		if (input && input.viewState && input.viewState.focused === 'editor') {
			this.searchResultEditor.restoreViewState(input.viewState.state);
			this.searchResultEditor.focus();
		} else {
			this.queryEditorWidget.focus();
		}
	}

478
	clearInput() {
J
Jackson Kearl 已提交
479
		this.saveViewState();
480
		super.clearInput();
481 482
		this.inSearchEditorContextKey.set(false);
	}
483
}
484 485 486 487 488 489 490 491 492

registerThemingParticipant((theme, collector) => {
	collector.addRule(`.monaco-editor .searchEditorFindMatch { background-color: ${theme.getColor(searchEditorFindMatch)}; }`);

	const findMatchHighlightBorder = theme.getColor(searchEditorFindMatchBorder);
	if (findMatchHighlightBorder) {
		collector.addRule(`.monaco-editor .searchEditorFindMatch { border: 1px ${theme.type === 'hc' ? 'dotted' : 'solid'} ${findMatchHighlightBorder}; box-sizing: border-box; }`);
	}
});
493 494

export const searchEditorTextInputBorder = registerColor('searchEditor.textInputBorder', { dark: inputBorder, light: inputBorder, hc: inputBorder }, localize('textInputBoxBorder', "Search editor text input box border."));