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

'use strict';

import 'vs/css!./findWidget';
A
Alex Dima 已提交
9
import * as nls from 'vs/nls';
J
Johannes Rieken 已提交
10 11
import { onUnexpectedError } from 'vs/base/common/errors';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
A
Alex Dima 已提交
12 13
import * as strings from 'vs/base/common/strings';
import * as dom from 'vs/base/browser/dom';
J
Johannes Rieken 已提交
14 15
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
16
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
J
Johannes Rieken 已提交
17 18
import { IMessage as InputBoxMessage, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { Widget } from 'vs/base/browser/ui/widget';
R
rebornix 已提交
19
import { Sash, IHorizontalSashLayoutProvider, ISashEvent } from 'vs/base/browser/ui/sash/sash';
J
Johannes Rieken 已提交
20
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
21
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
J
Johannes Rieken 已提交
22 23 24 25 26
import { FIND_IDS, MATCHES_LIMIT } from 'vs/editor/contrib/find/common/findModel';
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/common/findState';
import { Range } from 'vs/editor/common/core/range';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { CONTEXT_FIND_INPUT_FOCUSSED } from 'vs/editor/contrib/find/common/findController';
27
import { ITheme, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
28
import { Color } from 'vs/base/common/color';
29
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
30
import { editorFindRangeHighlight, editorFindMatch, editorFindMatchHighlight, activeContrastBorder, contrastBorder, inputBackground, editorWidgetBackground, inputActiveOptionBorder, widgetShadow, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorBorder, errorForeground } from 'vs/platform/theme/common/colorRegistry';
31

E
Erich Gamma 已提交
32 33 34 35 36
export interface IFindController {
	replace(): void;
	replaceAll(): void;
}

37 38 39 40 41 42 43 44 45 46 47
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find");
const NLS_PREVIOUS_MATCH_BTN_LABEL = nls.localize('label.previousMatchButton', "Previous match");
const NLS_NEXT_MATCH_BTN_LABEL = nls.localize('label.nextMatchButton', "Next match");
const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind', "Find in selection");
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace");
const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace");
const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace");
const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All");
const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode");
A
Alex Dima 已提交
48
const NLS_MATCHES_COUNT_LIMIT_TITLE = nls.localize('title.matchesCountLimit', "Only the first 999 results are highlighted, but all find operations work on the entire text.");
49
const NLS_MATCHES_LOCATION = nls.localize('label.matchesLocation', "{0} of {1}");
I
isidor 已提交
50
const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
51

52 53
let MAX_MATCHES_COUNT_WIDTH = 69;

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
export class FindWidgetViewZone implements IViewZone {

	public afterLineNumber: number;
	public heightInPx: number;
	public suppressMouseDown: boolean;
	public domNode: HTMLElement;

	constructor(afterLineNumber: number) {
		this.afterLineNumber = afterLineNumber;

		this.heightInPx = 34;
		this.suppressMouseDown = false;
		this.domNode = document.createElement('div');
		this.domNode.className = 'dock-find-viewzone';
	}
}

R
rebornix 已提交
71 72 73

export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSashLayoutProvider {

E
Erich Gamma 已提交
74 75 76 77 78

	private static ID = 'editor.contrib.findWidget';
	private static PART_WIDTH = 275;
	private static FIND_INPUT_AREA_WIDTH = FindWidget.PART_WIDTH - 54;
	private static REPLACE_INPUT_AREA_WIDTH = FindWidget.FIND_INPUT_AREA_WIDTH;
79 80
	private static FIND_INPUT_AREA_HEIGHT = 34; // The height of Find Widget when Replace Input is not visible.
	private static FIND_REPLACE_AREA_HEIGHT = 64; // The height of Find Widget when Replace Input is  visible.
E
Erich Gamma 已提交
81

A
Alex Dima 已提交
82
	private _codeEditor: ICodeEditor;
A
Alex Dima 已提交
83
	private _state: FindReplaceState;
E
Erich Gamma 已提交
84
	private _controller: IFindController;
A
Alex Dima 已提交
85
	private _contextViewProvider: IContextViewProvider;
86
	private _keybindingService: IKeybindingService;
E
Erich Gamma 已提交
87

A
Alex Dima 已提交
88 89 90
	private _domNode: HTMLElement;
	private _findInput: FindInput;
	private _replaceInputBox: InputBox;
E
Erich Gamma 已提交
91

A
Alex Dima 已提交
92
	private _toggleReplaceBtn: SimpleButton;
93
	private _matchesCount: HTMLElement;
A
Alex Dima 已提交
94 95
	private _prevBtn: SimpleButton;
	private _nextBtn: SimpleButton;
96
	private _toggleSelectionFind: SimpleCheckbox;
A
Alex Dima 已提交
97 98 99
	private _closeBtn: SimpleButton;
	private _replaceBtn: SimpleButton;
	private _replaceAllBtn: SimpleButton;
E
Erich Gamma 已提交
100

A
Alex Dima 已提交
101 102
	private _isVisible: boolean;
	private _isReplaceVisible: boolean;
E
Erich Gamma 已提交
103

104
	private _focusTracker: dom.IFocusTracker;
S
Sandeep Somavarapu 已提交
105
	private _findInputFocussed: IContextKey<boolean>;
106 107
	private _viewZone: FindWidgetViewZone;
	private _viewZoneId: number;
108

R
rebornix 已提交
109 110
	private _resizeSash: Sash;

111
	constructor(
A
Alex Dima 已提交
112
		codeEditor: ICodeEditor,
A
Alex Dima 已提交
113 114 115
		controller: IFindController,
		state: FindReplaceState,
		contextViewProvider: IContextViewProvider,
S
Sandeep Somavarapu 已提交
116
		keybindingService: IKeybindingService,
117 118
		contextKeyService: IContextKeyService,
		themeService: IThemeService
119
	) {
A
Alex Dima 已提交
120
		super();
E
Erich Gamma 已提交
121 122
		this._codeEditor = codeEditor;
		this._controller = controller;
A
Alex Dima 已提交
123
		this._state = state;
E
Erich Gamma 已提交
124
		this._contextViewProvider = contextViewProvider;
125
		this._keybindingService = keybindingService;
E
Erich Gamma 已提交
126 127 128 129

		this._isVisible = false;
		this._isReplaceVisible = false;

A
Alex Dima 已提交
130
		this._register(this._state.addChangeListener((e) => this._onStateChanged(e)));
E
Erich Gamma 已提交
131 132

		this._buildDomNode();
R
rebornix 已提交
133
		this._resizeSash = new Sash(this._domNode, this, { orientation: 0 });
R
rebornix 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
		let data: { startX: number; };
		let originalWidth = 411;
		this._register(this._resizeSash.addListener('start', (e: ISashEvent) => {
			data = {
				startX: e.startX,
			};
			originalWidth = dom.getTotalWidth(this._domNode);
		}));

		this._register(this._resizeSash.addListener('end', () => {
			data = undefined;
		}));

		this._register(this._resizeSash.addListener('change', (evt: ISashEvent) => {
			if (data) {
R
rebornix 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
				let reducedFindWidget = false;
				let narrowFindWidget = false;
				let collapsedFindWidget = false;
				let width = originalWidth + data.startX - evt.currentX;
				if (width < 411) {
					reducedFindWidget = true;
			}
				if (width < 411 - 69) {
					narrowFindWidget = true;
				}
				if (width < 265) {
					collapsedFindWidget = true;
				}
				dom.toggleClass(this._domNode, 'collapsed-find-widget', collapsedFindWidget);
				dom.toggleClass(this._domNode, 'narrow-find-widget', narrowFindWidget);
				dom.toggleClass(this._domNode, 'reduced-find-widget', reducedFindWidget);
				this._domNode.style.width = `${width}px`;
				// this._findInput.setWidth(FindWidget.FIND_INPUT_AREA_WIDTH + Math.max(0, data.startX - evt.currentX));
R
rebornix 已提交
167 168
			}
		}));
169
		this._updateButtons();
E
Erich Gamma 已提交
170

171 172
		let checkEditorWidth = () => {
			let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width;
R
rebornix 已提交
173
			let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth;
174 175 176
			let collapsedFindWidget = false;
			let reducedFindWidget = false;
			let narrowFindWidget = false;
R
rebornix 已提交
177 178
			let widgetWidth = Math.max(411, dom.getTotalWidth(this._domNode)) - 69;
			if (widgetWidth + 28 >= editorWidth + 50) {
179 180
				collapsedFindWidget = true;
			}
R
rebornix 已提交
181
			if (widgetWidth + 28 >= editorWidth) {
182 183
				narrowFindWidget = true;
			}
R
rebornix 已提交
184
			if (widgetWidth + MAX_MATCHES_COUNT_WIDTH + 28 + minimapWidth >= editorWidth) {
185 186 187 188
				reducedFindWidget = true;
			}
			dom.toggleClass(this._domNode, 'collapsed-find-widget', collapsedFindWidget);
			dom.toggleClass(this._domNode, 'narrow-find-widget', narrowFindWidget);
R
rebornix 已提交
189
			dom.toggleClass(this._domNode, 'reduced-find-widget', reducedFindWidget);
R
rebornix 已提交
190 191 192 193 194 195 196 197
			if (collapsedFindWidget) {
				this._domNode.style.maxWidth = '111px';
			} else if (narrowFindWidget) {
				this._domNode.style.maxWidth = '257px';
			} else {
				this._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;
			}

198 199 200
		};
		checkEditorWidth();

J
Johannes Rieken 已提交
201
		this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
202
			if (e.readOnly) {
203 204 205 206 207 208
				if (this._codeEditor.getConfiguration().readOnly) {
					// Hide replace part if editor becomes read only
					this._state.change({ isReplaceRevealed: false }, false);
				}
				this._updateButtons();
			}
209 210 211
			if (e.layoutInfo) {
				checkEditorWidth();
			}
212
		}));
A
Alex Dima 已提交
213
		this._register(this._codeEditor.onDidChangeCursorSelection(() => {
214 215
			if (this._isVisible) {
				this._updateToggleSelectionFindButton();
216 217
			}
		}));
S
Sandeep Somavarapu 已提交
218
		this._findInputFocussed = CONTEXT_FIND_INPUT_FOCUSSED.bindTo(contextKeyService);
219 220
		this._focusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement));
		this._focusTracker.addFocusListener(() => {
S
Sandeep Somavarapu 已提交
221
			this._findInputFocussed.set(true);
222 223 224 225 226 227 228 229 230 231 232 233

			if (this._toggleSelectionFind.checked) {
				let selection = this._codeEditor.getSelection();
				if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
					selection = selection.setEndPosition(selection.endLineNumber - 1, 1);
				}
				let currentMatch = this._state.currentMatch;
				if (selection.startLineNumber !== selection.endLineNumber) {
					if (!Range.equalsRange(selection, currentMatch)) {
						// Reseed find scope
						this._state.change({ searchScope: selection }, true);
					}
234 235 236
				}
			}
		});
S
Sandeep Somavarapu 已提交
237 238 239
		this._focusTracker.addBlurListener(() => {
			this._findInputFocussed.set(false);
		});
240

A
Alex Dima 已提交
241
		this._codeEditor.addOverlayWidget(this);
242
		this._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line.
243 244 245

		this._applyTheme(themeService.getTheme());
		this._register(themeService.onThemeChange(this._applyTheme.bind(this)));
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

		this._register(this._codeEditor.onDidChangeModel((e) => {
			if (!this._isVisible) {
				return;
			}

			if (this._viewZoneId === undefined) {
				return;
			}

			this._codeEditor.changeViewZones((accessor) => {
				accessor.removeZone(this._viewZoneId);
				this._viewZoneId = undefined;
			});
		}));

		this._register(this._codeEditor.onDidScrollChange((e) => {
			this._layoutViewZone();
		}));
E
Erich Gamma 已提交
265 266 267 268 269 270 271 272 273 274 275 276
	}

	// ----- IOverlayWidget API

	public getId(): string {
		return FindWidget.ID;
	}

	public getDomNode(): HTMLElement {
		return this._domNode;
	}

A
Alex Dima 已提交
277
	public getPosition(): IOverlayWidgetPosition {
E
Erich Gamma 已提交
278 279
		if (this._isVisible) {
			return {
A
Alex Dima 已提交
280
				preference: OverlayWidgetPositionPreference.TOP_RIGHT_CORNER
E
Erich Gamma 已提交
281 282 283 284 285
			};
		}
		return null;
	}

A
Alex Dima 已提交
286
	// ----- React to state changes
E
Erich Gamma 已提交
287

J
Johannes Rieken 已提交
288
	private _onStateChanged(e: FindReplaceStateChangedEvent): void {
A
Alex Dima 已提交
289 290
		if (e.searchString) {
			this._findInput.setValue(this._state.searchString);
291
			this._updateButtons();
A
Alex Dima 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304
		}
		if (e.replaceString) {
			this._replaceInputBox.value = this._state.replaceString;
		}
		if (e.isRevealed) {
			if (this._state.isRevealed) {
				this._reveal(true);
			} else {
				this._hide(true);
			}
		}
		if (e.isReplaceRevealed) {
			if (this._state.isReplaceRevealed) {
305 306 307 308
				if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) {
					this._isReplaceVisible = true;
					this._updateButtons();
				}
A
Alex Dima 已提交
309
			} else {
310 311 312 313
				if (this._isReplaceVisible) {
					this._isReplaceVisible = false;
					this._updateButtons();
				}
A
Alex Dima 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326
			}
		}
		if (e.isRegex) {
			this._findInput.setRegex(this._state.isRegex);
		}
		if (e.wholeWord) {
			this._findInput.setWholeWords(this._state.wholeWord);
		}
		if (e.matchCase) {
			this._findInput.setCaseSensitive(this._state.matchCase);
		}
		if (e.searchScope) {
			if (this._state.searchScope) {
327
				this._toggleSelectionFind.checked = true;
A
Alex Dima 已提交
328
			} else {
329
				this._toggleSelectionFind.checked = false;
A
Alex Dima 已提交
330 331 332
			}
			this._updateToggleSelectionFindButton();
		}
333
		if (e.searchString || e.matchesCount || e.matchesPosition) {
A
Alex Dima 已提交
334
			let showRedOutline = (this._state.searchString.length > 0 && this._state.matchesCount === 0);
A
Alex Dima 已提交
335
			dom.toggleClass(this._domNode, 'no-results', showRedOutline);
A
Alex Dima 已提交
336

337 338
			this._updateMatchesCount();
		}
339 340 341
		if (e.searchString || e.currentMatch) {
			this._layoutViewZone();
		}
342 343 344
	}

	private _updateMatchesCount(): void {
345
		this._matchesCount.style.minWidth = MAX_MATCHES_COUNT_WIDTH + 'px';
346 347 348 349 350
		if (this._state.matchesCount >= MATCHES_LIMIT) {
			this._matchesCount.title = NLS_MATCHES_COUNT_LIMIT_TITLE;
		} else {
			this._matchesCount.title = '';
		}
A
Alex Dima 已提交
351

352 353 354 355 356 357
		// remove previous content
		if (this._matchesCount.firstChild) {
			this._matchesCount.removeChild(this._matchesCount.firstChild);
		}

		let label: string;
358
		if (this._state.matchesCount > 0) {
J
Johannes Rieken 已提交
359
			let matchesCount: string = String(this._state.matchesCount);
A
Alex Dima 已提交
360 361 362
			if (this._state.matchesCount >= MATCHES_LIMIT) {
				matchesCount += '+';
			}
J
Johannes Rieken 已提交
363
			let matchesPosition: string = String(this._state.matchesPosition);
364 365 366
			if (matchesPosition === '0') {
				matchesPosition = '?';
			}
A
Alex Dima 已提交
367
			label = strings.format(NLS_MATCHES_LOCATION, matchesPosition, matchesCount);
368
		} else {
369
			label = NLS_NO_RESULTS;
E
Erich Gamma 已提交
370
		}
371
		this._matchesCount.appendChild(document.createTextNode(label));
372 373

		MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth);
E
Erich Gamma 已提交
374 375
	}

376 377 378 379
	// ----- actions

	/**
	 * If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find').
380
	 * If 'selection find' is OFF we enable the button only if there is a selection.
381 382 383
	 */
	private _updateToggleSelectionFindButton(): void {
		let selection = this._codeEditor.getSelection();
384
		let isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false;
385 386
		let isChecked = this._toggleSelectionFind.checked;

387
		this._toggleSelectionFind.setEnabled(this._isVisible && (isChecked || isSelection));
388 389 390 391 392 393 394 395 396 397 398 399 400 401
	}

	private _updateButtons(): void {
		this._findInput.setEnabled(this._isVisible);
		this._replaceInputBox.setEnabled(this._isVisible && this._isReplaceVisible);
		this._updateToggleSelectionFindButton();
		this._closeBtn.setEnabled(this._isVisible);

		let findInputIsNonEmpty = (this._state.searchString.length > 0);
		this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty);
		this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty);
		this._replaceBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
		this._replaceAllBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);

A
Alex Dima 已提交
402
		dom.toggleClass(this._domNode, 'replaceToggled', this._isReplaceVisible);
403 404 405 406 407 408 409 410
		this._toggleReplaceBtn.toggleClass('collapse', !this._isReplaceVisible);
		this._toggleReplaceBtn.toggleClass('expand', this._isReplaceVisible);
		this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);

		let canReplace = !this._codeEditor.getConfiguration().readOnly;
		this._toggleReplaceBtn.setEnabled(this._isVisible && canReplace);
	}

J
Johannes Rieken 已提交
411
	private _reveal(animate: boolean): void {
412 413 414
		if (!this._isVisible) {
			this._isVisible = true;

R
rebornix 已提交
415 416 417 418 419 420 421
			let selection = this._codeEditor.getSelection();
			let isSelection = selection ? (selection.startLineNumber !== selection.endLineNumber || selection.startColumn !== selection.endColumn) : false;
			if (isSelection && this._codeEditor.getConfiguration().contribInfo.find.autoFindInSelection) {
				this._toggleSelectionFind.checked = true;
			} else {
				this._toggleSelectionFind.checked = false;
			}
422 423 424
			this._updateButtons();

			setTimeout(() => {
A
Alex Dima 已提交
425
				dom.addClass(this._domNode, 'visible');
426
				if (!animate) {
A
Alex Dima 已提交
427
					dom.addClass(this._domNode, 'noanimation');
428
					setTimeout(() => {
A
Alex Dima 已提交
429
						dom.removeClass(this._domNode, 'noanimation');
430 431 432 433
					}, 200);
				}
			}, 0);
			this._codeEditor.layoutOverlayWidget(this);
434
			this._showViewZone();
435 436 437
		}
	}

J
Johannes Rieken 已提交
438
	private _hide(focusTheEditor: boolean): void {
439 440 441 442 443
		if (this._isVisible) {
			this._isVisible = false;

			this._updateButtons();

A
Alex Dima 已提交
444
			dom.removeClass(this._domNode, 'visible');
445 446 447 448
			if (focusTheEditor) {
				this._codeEditor.focus();
			}
			this._codeEditor.layoutOverlayWidget(this);
449 450 451 452 453 454 455 456 457 458 459 460 461
			this._codeEditor.changeViewZones((accessor) => {
				if (this._viewZoneId !== undefined) {
					accessor.removeZone(this._viewZoneId);
					this._viewZoneId = undefined;
					this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() - this._viewZone.heightInPx);
				}
			});
		}
	}

	private _layoutViewZone() {
		if (!this._isVisible) {
			return;
462
		}
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502

		if (this._viewZoneId !== undefined) {
			return;
		}

		this._codeEditor.changeViewZones((accessor) => {
			if (this._state.isReplaceRevealed) {
				this._viewZone.heightInPx = FindWidget.FIND_REPLACE_AREA_HEIGHT;
			} else {
				this._viewZone.heightInPx = FindWidget.FIND_INPUT_AREA_HEIGHT;
			}

			this._viewZoneId = accessor.addZone(this._viewZone);
			this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + this._viewZone.heightInPx);
		});
	}

	private _showViewZone() {
		if (!this._isVisible) {
			return;
		}

		this._codeEditor.changeViewZones((accessor) => {
			let scrollAdjustment = FindWidget.FIND_INPUT_AREA_HEIGHT;

			if (this._viewZoneId !== undefined) {
				if (this._state.isReplaceRevealed) {
					this._viewZone.heightInPx = FindWidget.FIND_REPLACE_AREA_HEIGHT;
					scrollAdjustment = FindWidget.FIND_REPLACE_AREA_HEIGHT - FindWidget.FIND_INPUT_AREA_HEIGHT;
				} else {
					this._viewZone.heightInPx = FindWidget.FIND_INPUT_AREA_HEIGHT;
					scrollAdjustment = FindWidget.FIND_INPUT_AREA_HEIGHT - FindWidget.FIND_REPLACE_AREA_HEIGHT;
				}
				accessor.removeZone(this._viewZoneId);
			} else {
				this._viewZone.heightInPx = FindWidget.FIND_INPUT_AREA_HEIGHT;
			}
			this._viewZoneId = accessor.addZone(this._viewZone);
			this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
		});
503 504
	}

505
	private _applyTheme(theme: ITheme) {
506 507 508 509
		let inputStyles: IFindInputStyles = {
			inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
			inputBackground: theme.getColor(inputBackground),
			inputForeground: theme.getColor(inputForeground),
510
			inputBorder: theme.getColor(inputBorder),
B
Benjamin Pasero 已提交
511 512 513 514 515 516
			inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground),
			inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder),
			inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground),
			inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder),
			inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground),
			inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder)
517
		};
518
		this._findInput.style(inputStyles);
519
		this._replaceInputBox.style(inputStyles);
520 521
	}

E
Erich Gamma 已提交
522 523
	// ----- Public

524 525 526 527 528 529 530 531 532 533 534 535
	public focusFindInput(): void {
		this._findInput.select();
		// Edge browser requires focus() in addition to select()
		this._findInput.focus();
	}

	public focusReplaceInput(): void {
		this._replaceInputBox.select();
		// Edge browser requires focus() in addition to select()
		this._replaceInputBox.focus();
	}

536 537 538 539
	public highlightFindOptions(): void {
		this._findInput.highlightFindOptions();
	}

J
Johannes Rieken 已提交
540
	private _onFindInputKeyDown(e: IKeyboardEvent): void {
E
Erich Gamma 已提交
541

A
Alex Dima 已提交
542 543 544 545 546
		if (e.equals(KeyCode.Enter)) {
			this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().done(null, onUnexpectedError);
			e.preventDefault();
			return;
		}
547

A
Alex Dima 已提交
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
		if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
			this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().done(null, onUnexpectedError);
			e.preventDefault();
			return;
		}

		if (e.equals(KeyCode.Tab)) {
			if (this._isReplaceVisible) {
				this._replaceInputBox.focus();
			} else {
				this._findInput.focusOnCaseSensitive();
			}
			e.preventDefault();
			return;
		}

		if (e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)) {
			this._codeEditor.focus();
			e.preventDefault();
			return;
E
Erich Gamma 已提交
568 569 570
		}
	}

J
Johannes Rieken 已提交
571
	private _onReplaceInputKeyDown(e: IKeyboardEvent): void {
E
Erich Gamma 已提交
572

A
Alex Dima 已提交
573 574 575 576 577
		if (e.equals(KeyCode.Enter)) {
			this._controller.replace();
			e.preventDefault();
			return;
		}
E
Erich Gamma 已提交
578

A
Alex Dima 已提交
579 580 581 582 583
		if (e.equals(KeyMod.CtrlCmd | KeyCode.Enter)) {
			this._controller.replaceAll();
			e.preventDefault();
			return;
		}
584

A
Alex Dima 已提交
585 586 587 588 589
		if (e.equals(KeyCode.Tab)) {
			this._findInput.focusOnCaseSensitive();
			e.preventDefault();
			return;
		}
590

A
Alex Dima 已提交
591 592 593 594 595
		if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
			this._findInput.focus();
			e.preventDefault();
			return;
		}
596

A
Alex Dima 已提交
597 598 599 600
		if (e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)) {
			this._codeEditor.focus();
			e.preventDefault();
			return;
E
Erich Gamma 已提交
601 602 603
		}
	}

R
rebornix 已提交
604 605 606 607 608 609 610 611 612 613 614
	// ----- sash
	public getHorizontalSashTop(sash: Sash): number {
		return 0;
	}
	public getHorizontalSashLeft?(sash: Sash): number {
		return 0;
	}
	public getHorizontalSashWidth?(sash: Sash): number {
		return 500;
	}

A
Alex Dima 已提交
615
	// ----- initialization
E
Erich Gamma 已提交
616

J
Johannes Rieken 已提交
617
	private _keybindingLabelFor(actionId: string): string {
618
		let kb = this._keybindingService.lookupKeybinding(actionId);
B
Benjamin Pasero 已提交
619
		if (!kb) {
620 621
			return '';
		}
622
		return ` (${kb.getLabel()})`;
623 624
	}

E
Erich Gamma 已提交
625 626
	private _buildFindPart(): HTMLElement {
		// Find input
A
Alex Dima 已提交
627
		this._findInput = this._register(new FindInput(null, this._contextViewProvider, {
E
Erich Gamma 已提交
628
			width: FindWidget.FIND_INPUT_AREA_WIDTH,
629 630
			label: NLS_FIND_INPUT_LABEL,
			placeholder: NLS_FIND_INPUT_PLACEHOLDER,
A
Alex Dima 已提交
631 632 633
			appendCaseSensitiveLabel: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),
			appendWholeWordsLabel: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),
			appendRegexLabel: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),
J
Johannes Rieken 已提交
634
			validation: (value: string): InputBoxMessage => {
E
Erich Gamma 已提交
635 636 637 638 639 640 641
				if (value.length === 0) {
					return null;
				}
				if (!this._findInput.getRegex()) {
					return null;
				}
				try {
A
tslint  
Alex Dima 已提交
642
					/* tslint:disable:no-unused-expression */
A
tslint  
Alex Dima 已提交
643
					new RegExp(value);
A
tslint  
Alex Dima 已提交
644
					/* tslint:enable:no-unused-expression */
E
Erich Gamma 已提交
645 646 647 648 649
					return null;
				} catch (e) {
					return { content: e.message };
				}
			}
A
Alex Dima 已提交
650
		}));
651 652 653
		this._findInput.setRegex(!!this._state.isRegex);
		this._findInput.setCaseSensitive(!!this._state.matchCase);
		this._findInput.setWholeWords(!!this._state.wholeWord);
A
Alex Dima 已提交
654
		this._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e)));
655 656 657
		this._register(this._findInput.onInput(() => {
			this._state.change({ searchString: this._findInput.getValue() }, true);
		}));
A
Alex Dima 已提交
658
		this._register(this._findInput.onDidOptionChange(() => {
A
Alex Dima 已提交
659 660 661 662 663
			this._state.change({
				isRegex: this._findInput.getRegex(),
				wholeWord: this._findInput.getWholeWords(),
				matchCase: this._findInput.getCaseSensitive()
			}, true);
A
Alex Dima 已提交
664
		}));
665
		this._register(this._findInput.onCaseSensitiveKeyDown((e) => {
A
Alexandru Dima 已提交
666
			if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
667 668 669 670 671 672
				if (this._isReplaceVisible) {
					this._replaceInputBox.focus();
					e.preventDefault();
				}
			}
		}));
E
Erich Gamma 已提交
673

674 675 676 677
		this._matchesCount = document.createElement('div');
		this._matchesCount.className = 'matchesCount';
		this._updateMatchesCount();

E
Erich Gamma 已提交
678
		// Previous button
A
Alex Dima 已提交
679
		this._prevBtn = this._register(new SimpleButton({
A
Alex Dima 已提交
680
			label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),
A
Alex Dima 已提交
681 682
			className: 'previous',
			onTrigger: () => {
A
Alex Dima 已提交
683
				this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().done(null, onUnexpectedError);
A
Alex Dima 已提交
684
			},
J
Johannes Rieken 已提交
685
			onKeyDown: (e) => { }
A
Alex Dima 已提交
686
		}));
E
Erich Gamma 已提交
687 688

		// Next button
A
Alex Dima 已提交
689
		this._nextBtn = this._register(new SimpleButton({
A
Alex Dima 已提交
690
			label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),
A
Alex Dima 已提交
691 692
			className: 'next',
			onTrigger: () => {
A
Alex Dima 已提交
693
				this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().done(null, onUnexpectedError);
A
Alex Dima 已提交
694
			},
J
Johannes Rieken 已提交
695
			onKeyDown: (e) => { }
A
Alex Dima 已提交
696
		}));
E
Erich Gamma 已提交
697

A
Alex Dima 已提交
698
		let findPart = document.createElement('div');
E
Erich Gamma 已提交
699 700
		findPart.className = 'find-part';
		findPart.appendChild(this._findInput.domNode);
701
		findPart.appendChild(this._matchesCount);
E
Erich Gamma 已提交
702 703 704 705
		findPart.appendChild(this._prevBtn.domNode);
		findPart.appendChild(this._nextBtn.domNode);

		// Toggle selection button
706 707
		this._toggleSelectionFind = this._register(new SimpleCheckbox({
			parent: findPart,
R
rebornix 已提交
708
			title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
709 710
			onChange: () => {
				if (this._toggleSelectionFind.checked) {
711
					let selection = this._codeEditor.getSelection();
712
					if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
713 714
						selection = selection.setEndPosition(selection.endLineNumber - 1, 1);
					}
715 716 717
					if (!selection.isEmpty()) {
						this._state.change({ searchScope: selection }, true);
					}
718 719 720
				} else {
					this._state.change({ searchScope: null }, true);
				}
E
Erich Gamma 已提交
721 722 723 724
			}
		}));

		// Close button
A
Alex Dima 已提交
725
		this._closeBtn = this._register(new SimpleButton({
A
Alex Dima 已提交
726
			label: NLS_CLOSE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.CloseFindWidgetCommand),
A
Alex Dima 已提交
727 728
			className: 'close-fw',
			onTrigger: () => {
729
				this._state.change({ isRevealed: false, searchScope: null }, false);
A
Alex Dima 已提交
730 731
			},
			onKeyDown: (e) => {
A
Alexandru Dima 已提交
732
				if (e.equals(KeyCode.Tab)) {
A
Alex Dima 已提交
733
					if (this._isReplaceVisible) {
734 735 736 737 738
						if (this._replaceBtn.isEnabled()) {
							this._replaceBtn.focus();
						} else {
							this._codeEditor.focus();
						}
A
Alex Dima 已提交
739 740
						e.preventDefault();
					}
A
Alex Dima 已提交
741
				}
E
Erich Gamma 已提交
742
			}
A
Alex Dima 已提交
743
		}));
E
Erich Gamma 已提交
744 745 746 747 748 749 750 751

		findPart.appendChild(this._closeBtn.domNode);

		return findPart;
	}

	private _buildReplacePart(): HTMLElement {
		// Replace input
A
Alex Dima 已提交
752
		let replaceInput = document.createElement('div');
E
Erich Gamma 已提交
753 754
		replaceInput.className = 'replace-input';
		replaceInput.style.width = FindWidget.REPLACE_INPUT_AREA_WIDTH + 'px';
A
Alex Dima 已提交
755
		this._replaceInputBox = this._register(new InputBox(replaceInput, null, {
756 757
			ariaLabel: NLS_REPLACE_INPUT_LABEL,
			placeholder: NLS_REPLACE_INPUT_PLACEHOLDER
A
Alex Dima 已提交
758
		}));
E
Erich Gamma 已提交
759

A
Alex Dima 已提交
760 761
		this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e)));
		this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'input', (e) => {
762 763
			this._state.change({ replaceString: this._replaceInputBox.value }, false);
		}));
E
Erich Gamma 已提交
764 765

		// Replace one button
A
Alex Dima 已提交
766
		this._replaceBtn = this._register(new SimpleButton({
767
			label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),
A
Alex Dima 已提交
768 769 770 771
			className: 'replace',
			onTrigger: () => {
				this._controller.replace();
			},
A
Alex Dima 已提交
772
			onKeyDown: (e) => {
A
Alexandru Dima 已提交
773
				if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
A
Alex Dima 已提交
774 775 776 777 778
					this._closeBtn.focus();
					e.preventDefault();
				}
			}
		}));
E
Erich Gamma 已提交
779 780

		// Replace all button
A
Alex Dima 已提交
781
		this._replaceAllBtn = this._register(new SimpleButton({
782
			label: NLS_REPLACE_ALL_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceAllAction),
A
Alex Dima 已提交
783 784 785 786
			className: 'replace-all',
			onTrigger: () => {
				this._controller.replaceAll();
			},
J
Johannes Rieken 已提交
787
			onKeyDown: (e) => { }
A
Alex Dima 已提交
788
		}));
E
Erich Gamma 已提交
789

A
Alex Dima 已提交
790
		let replacePart = document.createElement('div');
E
Erich Gamma 已提交
791 792 793 794 795 796 797 798 799 800
		replacePart.className = 'replace-part';
		replacePart.appendChild(replaceInput);
		replacePart.appendChild(this._replaceBtn.domNode);
		replacePart.appendChild(this._replaceAllBtn.domNode);

		return replacePart;
	}

	private _buildDomNode(): void {
		// Find part
A
Alex Dima 已提交
801
		let findPart = this._buildFindPart();
E
Erich Gamma 已提交
802 803

		// Replace part
A
Alex Dima 已提交
804
		let replacePart = this._buildReplacePart();
E
Erich Gamma 已提交
805 806

		// Toggle replace button
A
Alex Dima 已提交
807
		this._toggleReplaceBtn = this._register(new SimpleButton({
A
Alex Dima 已提交
808 809 810
			label: NLS_TOGGLE_REPLACE_MODE_BTN_LABEL,
			className: 'toggle left',
			onTrigger: () => {
811
				this._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);
812
				this._showViewZone();
A
Alex Dima 已提交
813
			},
J
Johannes Rieken 已提交
814
			onKeyDown: (e) => { }
A
Alex Dima 已提交
815
		}));
E
Erich Gamma 已提交
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
		this._toggleReplaceBtn.toggleClass('expand', this._isReplaceVisible);
		this._toggleReplaceBtn.toggleClass('collapse', !this._isReplaceVisible);
		this._toggleReplaceBtn.setExpanded(this._isReplaceVisible);

		// Widget
		this._domNode = document.createElement('div');
		this._domNode.className = 'editor-widget find-widget';
		this._domNode.setAttribute('aria-hidden', 'false');

		this._domNode.appendChild(this._toggleReplaceBtn.domNode);
		this._domNode.appendChild(findPart);
		this._domNode.appendChild(replacePart);
	}
}

831 832 833 834 835 836 837
interface ISimpleCheckboxOpts {
	parent: HTMLElement;
	title: string;
	onChange: () => void;
}

class SimpleCheckbox extends Widget {
A
Alex Dima 已提交
838 839

	private static _COUNTER = 0;
E
Erich Gamma 已提交
840

841
	private _opts: ISimpleCheckboxOpts;
A
Alex Dima 已提交
842 843 844
	private _domNode: HTMLElement;
	private _checkbox: HTMLInputElement;
	private _label: HTMLLabelElement;
E
Erich Gamma 已提交
845

J
Johannes Rieken 已提交
846
	constructor(opts: ISimpleCheckboxOpts) {
A
Alex Dima 已提交
847
		super();
848 849
		this._opts = opts;

E
Erich Gamma 已提交
850 851
		this._domNode = document.createElement('div');
		this._domNode.className = 'monaco-checkbox';
852
		this._domNode.title = this._opts.title;
853
		this._domNode.tabIndex = 0;
E
Erich Gamma 已提交
854 855 856 857

		this._checkbox = document.createElement('input');
		this._checkbox.type = 'checkbox';
		this._checkbox.className = 'checkbox';
858
		this._checkbox.id = 'checkbox-' + SimpleCheckbox._COUNTER++;
859
		this._checkbox.tabIndex = -1;
E
Erich Gamma 已提交
860

A
Alex Dima 已提交
861 862
		this._label = document.createElement('label');
		this._label.className = 'label';
E
Erich Gamma 已提交
863
		// Connect the label and the checkbox. Checkbox will get checked when the label recieves a click.
A
Alex Dima 已提交
864
		this._label.htmlFor = this._checkbox.id;
865
		this._label.tabIndex = -1;
E
Erich Gamma 已提交
866 867

		this._domNode.appendChild(this._checkbox);
A
Alex Dima 已提交
868
		this._domNode.appendChild(this._label);
E
Erich Gamma 已提交
869

870 871 872 873 874
		this._opts.parent.appendChild(this._domNode);

		this.onchange(this._checkbox, (e) => {
			this._opts.onChange();
		});
E
Erich Gamma 已提交
875 876 877 878 879 880
	}

	public get domNode(): HTMLElement {
		return this._domNode;
	}

881 882 883 884
	public get checked(): boolean {
		return this._checkbox.checked;
	}

J
Johannes Rieken 已提交
885
	public set checked(newValue: boolean) {
886
		this._checkbox.checked = newValue;
E
Erich Gamma 已提交
887 888 889 890 891 892
	}

	public focus(): void {
		this._checkbox.focus();
	}

893
	private enable(): void {
E
Erich Gamma 已提交
894 895 896
		this._checkbox.removeAttribute('disabled');
	}

897
	private disable(): void {
E
Erich Gamma 已提交
898 899
		this._checkbox.disabled = true;
	}
900

J
Johannes Rieken 已提交
901
	public setEnabled(enabled: boolean): void {
902 903
		if (enabled) {
			this.enable();
904
			this.domNode.tabIndex = 0;
905 906
		} else {
			this.disable();
907
			this.domNode.tabIndex = -1;
908 909
		}
	}
E
Erich Gamma 已提交
910 911
}

A
Alex Dima 已提交
912 913 914
interface ISimpleButtonOpts {
	label: string;
	className: string;
J
Johannes Rieken 已提交
915 916
	onTrigger: () => void;
	onKeyDown: (e: IKeyboardEvent) => void;
A
Alex Dima 已提交
917
}
E
Erich Gamma 已提交
918

A
Alex Dima 已提交
919
class SimpleButton extends Widget {
E
Erich Gamma 已提交
920

A
Alex Dima 已提交
921 922
	private _opts: ISimpleButtonOpts;
	private _domNode: HTMLElement;
E
Erich Gamma 已提交
923

J
Johannes Rieken 已提交
924
	constructor(opts: ISimpleButtonOpts) {
A
Alex Dima 已提交
925
		super();
A
Alex Dima 已提交
926
		this._opts = opts;
E
Erich Gamma 已提交
927 928

		this._domNode = document.createElement('div');
A
Alex Dima 已提交
929
		this._domNode.title = this._opts.label;
A
Alex Dima 已提交
930
		this._domNode.tabIndex = 0;
A
Alex Dima 已提交
931
		this._domNode.className = 'button ' + this._opts.className;
E
Erich Gamma 已提交
932
		this._domNode.setAttribute('role', 'button');
A
Alex Dima 已提交
933
		this._domNode.setAttribute('aria-label', this._opts.label);
E
Erich Gamma 已提交
934

A
Alex Dima 已提交
935
		this.onclick(this._domNode, (e) => {
A
Alex Dima 已提交
936
			this._opts.onTrigger();
E
Erich Gamma 已提交
937
			e.preventDefault();
A
Alex Dima 已提交
938 939
		});
		this.onkeydown(this._domNode, (e) => {
A
Alexandru Dima 已提交
940
			if (e.equals(KeyCode.Space) || e.equals(KeyCode.Enter)) {
A
Alex Dima 已提交
941
				this._opts.onTrigger();
E
Erich Gamma 已提交
942 943 944
				e.preventDefault();
				return;
			}
A
Alex Dima 已提交
945
			this._opts.onKeyDown(e);
A
Alex Dima 已提交
946
		});
E
Erich Gamma 已提交
947 948 949 950 951 952
	}

	public get domNode(): HTMLElement {
		return this._domNode;
	}

953 954 955 956
	public isEnabled(): boolean {
		return (this._domNode.tabIndex >= 0);
	}

E
Erich Gamma 已提交
957 958 959 960
	public focus(): void {
		this._domNode.focus();
	}

J
Johannes Rieken 已提交
961
	public setEnabled(enabled: boolean): void {
A
Alex Dima 已提交
962
		dom.toggleClass(this._domNode, 'disabled', !enabled);
E
Erich Gamma 已提交
963 964 965 966
		this._domNode.setAttribute('aria-disabled', String(!enabled));
		this._domNode.tabIndex = enabled ? 0 : -1;
	}

J
Johannes Rieken 已提交
967
	public setExpanded(expanded: boolean): void {
968
		this._domNode.setAttribute('aria-expanded', String(!!expanded));
E
Erich Gamma 已提交
969 970
	}

J
Johannes Rieken 已提交
971
	public toggleClass(className: string, shouldHaveIt: boolean): void {
A
Alex Dima 已提交
972
		dom.toggleClass(this._domNode, className, shouldHaveIt);
E
Erich Gamma 已提交
973 974
	}
}
975

976 977 978 979 980
// theming

registerThemingParticipant((theme, collector) => {
	function addBackgroundColorRule(selector: string, color: Color): void {
		if (color) {
981
			collector.addRule(`.monaco-editor ${selector} { background-color: ${color}; }`);
982
		}
983
	}
984 985

	addBackgroundColorRule('.findMatch', theme.getColor(editorFindMatchHighlight));
986
	addBackgroundColorRule('.currentFindMatch', theme.getColor(editorFindMatch));
987 988
	addBackgroundColorRule('.findScope', theme.getColor(editorFindRangeHighlight));

989
	let widgetBackground = theme.getColor(editorWidgetBackground);
990 991
	addBackgroundColorRule('.find-widget', widgetBackground);

992 993
	let widgetShadowColor = theme.getColor(widgetShadow);
	if (widgetShadowColor) {
994
		collector.addRule(`.monaco-editor .find-widget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
995 996
	}

997
	let hcOutline = theme.getColor(activeContrastBorder);
998
	if (hcOutline) {
999 1000 1001
		collector.addRule(`.monaco-editor .findScope { border: 1px dashed ${hcOutline.transparent(0.4)}; }`);
		collector.addRule(`.monaco-editor .currentFindMatch { border: 2px solid ${hcOutline}; padding: 1px; -moz-box-sizing: border-box; box-sizing: border-box; }`);
		collector.addRule(`.monaco-editor .findMatch { border: 1px dotted ${hcOutline}; -moz-box-sizing: border-box; box-sizing: border-box; }`);
1002
	}
1003
	let hcBorder = theme.getColor(contrastBorder);
1004
	if (hcBorder) {
1005 1006 1007 1008 1009 1010
		collector.addRule(`.monaco-editor .find-widget { border: 2px solid ${hcBorder}; }`);
	}

	let error = theme.getColor(errorForeground);
	if (error) {
		collector.addRule(`.monaco-editor .find-widget.no-results .matchesCount { color: ${error}; }`);
1011 1012 1013
	}
});