Merge from vscode e558dc6ea73a75bd69d7a0b485f0e7e4194c66bf (#6864)

This commit is contained in:
Anthony Dresser
2019-08-21 20:44:59 -07:00
committed by GitHub
parent d2ae0f0154
commit 985bfae8a0
107 changed files with 2260 additions and 814 deletions

View File

@@ -9,11 +9,12 @@ import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
import { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';
import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
import { Widget } from 'vs/base/browser/ui/widget';
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { Delayer } from 'vs/base/common/async';
import { Color } from 'vs/base/common/color';
import { onUnexpectedError } from 'vs/base/common/errors';
@@ -28,11 +29,12 @@ import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MA
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/browser/contextScopedHistoryWidget';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { INotificationService } from 'vs/platform/notification/common/notification';
export interface IFindController {
replace(): void;
@@ -48,7 +50,6 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind'
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_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
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");
@@ -59,14 +60,12 @@ const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
const FIND_WIDGET_INITIAL_WIDTH = 411;
const PART_WIDTH = 275;
const FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;
const REPLACE_INPUT_AREA_WIDTH = FIND_INPUT_AREA_WIDTH;
let MAX_MATCHES_COUNT_WIDTH = 69;
let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COUNT_WIDTH + 3 + 1) /** Match Results */ + 23 /** Button */ * 4 + 2/** sash */;
const FIND_INPUT_AREA_HEIGHT = 34; // The height of Find Widget when Replace Input is not visible.
const FIND_REPLACE_AREA_HEIGHT = 64; // The height of Find Widget when Replace Input is visible.
const FIND_INPUT_AREA_HEIGHT = 33; // The height of Find Widget when Replace Input is not visible.
const ctrlEnterReplaceAllWarningPromptedKey = 'ctrlEnterReplaceAll.windows.donotask';
export class FindWidgetViewZone implements IViewZone {
public readonly afterLineNumber: number;
@@ -84,6 +83,22 @@ export class FindWidgetViewZone implements IViewZone {
}
}
function stopPropagationForMultiLineUpwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
const isMultiline = !!value.match(/\n/);
if (textarea && isMultiline && textarea.selectionStart > 0) {
event.stopPropagation();
return;
}
}
function stopPropagationForMultiLineDownwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
const isMultiline = !!value.match(/\n/);
if (textarea && isMultiline && textarea.selectionEnd < textarea.value.length) {
event.stopPropagation();
return;
}
}
export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSashLayoutProvider {
private static readonly ID = 'editor.contrib.findWidget';
private readonly _codeEditor: ICodeEditor;
@@ -92,10 +107,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private readonly _contextViewProvider: IContextViewProvider;
private readonly _keybindingService: IKeybindingService;
private readonly _contextKeyService: IContextKeyService;
private readonly _storageService: IStorageService;
private readonly _notificationService: INotificationService;
private _domNode!: HTMLElement;
private _cachedHeight: number | null;
private _findInput!: FindInput;
private _replaceInputBox!: HistoryInputBox;
private _replaceInput!: ReplaceInput;
private _toggleReplaceBtn!: SimpleButton;
private _matchesCount!: HTMLElement;
@@ -103,13 +121,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _nextBtn!: SimpleButton;
private _toggleSelectionFind!: SimpleCheckbox;
private _closeBtn!: SimpleButton;
private _preserveCase!: Checkbox;
private _replaceBtn!: SimpleButton;
private _replaceAllBtn!: SimpleButton;
private _isVisible: boolean;
private _isReplaceVisible: boolean;
private _ignoreChangeEvent: boolean;
private _ctrlEnterReplaceAllWarningPrompted: boolean;
private readonly _findFocusTracker: dom.IFocusTracker;
private readonly _findInputFocused: IContextKey<boolean>;
@@ -129,7 +147,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
contextViewProvider: IContextViewProvider,
keybindingService: IKeybindingService,
contextKeyService: IContextKeyService,
themeService: IThemeService
themeService: IThemeService,
storageService: IStorageService,
notificationService: INotificationService,
) {
super();
this._codeEditor = codeEditor;
@@ -138,6 +158,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
this._contextViewProvider = contextViewProvider;
this._keybindingService = keybindingService;
this._contextKeyService = contextKeyService;
this._storageService = storageService;
this._notificationService = notificationService;
this._ctrlEnterReplaceAllWarningPrompted = !!storageService.getBoolean(ctrlEnterReplaceAllWarningPromptedKey, StorageScope.GLOBAL);
this._isVisible = false;
this._isReplaceVisible = false;
@@ -149,6 +173,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
this._buildDomNode();
this._updateButtons();
this._tryUpdateWidgetWidth();
this._findInput.inputBox.layout();
this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
if (e.readOnly) {
@@ -203,7 +228,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}));
this._replaceInputFocused = CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(contextKeyService);
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInputBox.inputElement));
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInput.inputBox.inputElement));
this._register(this._replaceFocusTracker.onDidFocus(() => {
this._replaceInputFocused.set(true);
this._updateSearchScope();
@@ -264,6 +289,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
if (e.searchString) {
if (this._state.searchString.indexOf('\n') >= 0) {
dom.addClass(this._domNode, 'multipleline');
} else {
dom.removeClass(this._domNode, 'multipleline');
}
try {
this._ignoreChangeEvent = true;
this._findInput.setValue(this._state.searchString);
@@ -273,7 +304,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
this._updateButtons();
}
if (e.replaceString) {
this._replaceInputBox.value = this._state.replaceString;
this._replaceInput.inputBox.value = this._state.replaceString;
}
if (e.isRevealed) {
if (this._state.isRevealed) {
@@ -286,8 +317,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
if (this._state.isReplaceRevealed) {
if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) {
this._isReplaceVisible = true;
this._replaceInputBox.width = this._findInput.inputBox.width;
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
this._updateButtons();
this._replaceInput.inputBox.layout();
}
} else {
if (this._isReplaceVisible) {
@@ -296,6 +328,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
}
}
if ((e.isRevealed || e.isReplaceRevealed) && (this._state.isRevealed || this._state.isReplaceRevealed)) {
if (this._tryUpdateHeight()) {
this._showViewZone();
}
}
if (e.isRegex) {
this._findInput.setRegex(this._state.isRegex);
}
@@ -337,7 +375,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
this._findInput.inputBox.addToHistory();
}
if (this._state.replaceString) {
this._replaceInputBox.addToHistory();
this._replaceInput.inputBox.addToHistory();
}
}
@@ -402,7 +440,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _updateButtons(): void {
this._findInput.setEnabled(this._isVisible);
this._replaceInputBox.setEnabled(this._isVisible && this._isReplaceVisible);
this._replaceInput.setEnabled(this._isVisible && this._isReplaceVisible);
this._updateToggleSelectionFindButton();
this._closeBtn.setEnabled(this._isVisible);
@@ -512,12 +550,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
this._codeEditor.changeViewZones((accessor) => {
if (this._state.isReplaceRevealed) {
viewZone.heightInPx = FIND_REPLACE_AREA_HEIGHT;
} else {
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
}
viewZone.heightInPx = this._getHeight();
this._viewZoneId = accessor.addZone(viewZone);
// scroll top adjust to make sure the editor doesn't scroll when adding viewzone at the beginning.
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + viewZone.heightInPx);
@@ -525,30 +558,47 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
private _showViewZone(adjustScroll: boolean = true) {
const viewZone = this._viewZone;
if (!this._isVisible || !viewZone) {
if (!this._isVisible) {
return;
}
const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop;
if (!addExtraSpaceOnTop) {
return;
}
if (this._viewZone === undefined) {
this._viewZone = new FindWidgetViewZone(0);
}
const viewZone = this._viewZone;
this._codeEditor.changeViewZones((accessor) => {
let scrollAdjustment = FIND_INPUT_AREA_HEIGHT;
if (this._viewZoneId !== undefined) {
if (this._state.isReplaceRevealed) {
viewZone.heightInPx = FIND_REPLACE_AREA_HEIGHT;
scrollAdjustment = FIND_REPLACE_AREA_HEIGHT - FIND_INPUT_AREA_HEIGHT;
} else {
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
scrollAdjustment = FIND_INPUT_AREA_HEIGHT - FIND_REPLACE_AREA_HEIGHT;
// the view zone already exists, we need to update the height
const newHeight = this._getHeight();
if (newHeight === viewZone.heightInPx) {
return;
}
accessor.removeZone(this._viewZoneId);
} else {
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
}
this._viewZoneId = accessor.addZone(viewZone);
if (adjustScroll) {
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
let scrollAdjustment = newHeight - viewZone.heightInPx;
viewZone.heightInPx = newHeight;
accessor.layoutZone(this._viewZoneId);
if (adjustScroll) {
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
}
return;
} else {
const scrollAdjustment = this._getHeight();
viewZone.heightInPx = scrollAdjustment;
this._viewZoneId = accessor.addZone(viewZone);
if (adjustScroll) {
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
}
}
});
}
@@ -584,8 +634,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder),
};
this._findInput.style(inputStyles);
this._replaceInputBox.style(inputStyles);
this._preserveCase.style(inputStyles);
this._replaceInput.style(inputStyles);
}
private _tryUpdateWidgetWidth() {
@@ -615,7 +664,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
if (widgetWidth > FIND_WIDGET_INITIAL_WIDTH) {
// as the widget is resized by users, we may need to change the max width of the widget as the editor width changes.
this._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;
this._replaceInputBox.inputElement.style.width = `${dom.getTotalWidth(this._findInput.inputBox.inputElement)}px`;
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
return;
}
}
@@ -639,13 +688,47 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
if (this._resized) {
let findInputWidth = dom.getTotalWidth(this._findInput.inputBox.inputElement);
this._findInput.inputBox.layout();
let findInputWidth = this._findInput.inputBox.width;
if (findInputWidth > 0) {
this._replaceInputBox.inputElement.style.width = `${findInputWidth}px`;
this._replaceInput.width = findInputWidth;
}
}
}
private _getHeight(): number {
let totalheight = 0;
// find input margin top
totalheight += 4;
// find input height
totalheight += this._findInput.inputBox.height + 2 /** input box border */;
if (this._isReplaceVisible) {
// replace input margin
totalheight += 4;
totalheight += this._replaceInput.inputBox.height + 2 /** input box border */;
}
// margin bottom
totalheight += 4;
return totalheight;
}
private _tryUpdateHeight(): boolean {
const totalHeight = this._getHeight();
if (this._cachedHeight !== null && this._cachedHeight === totalHeight) {
return false;
}
this._cachedHeight = totalHeight;
this._domNode.style.height = `${totalHeight}px`;
return true;
}
// ----- Public
public focusFindInput(): void {
@@ -655,9 +738,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
public focusReplaceInput(): void {
this._replaceInputBox.select();
this._replaceInput.select();
// Edge browser requires focus() in addition to select()
this._replaceInputBox.focus();
this._replaceInput.focus();
}
public highlightFindOptions(): void {
@@ -692,22 +775,25 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
private _onFindInputKeyDown(e: IKeyboardEvent): void {
if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) {
const inputElement = this._findInput.inputBox.inputElement;
const start = inputElement.selectionStart;
const end = inputElement.selectionEnd;
const content = inputElement.value;
if (e.equals(KeyCode.Enter)) {
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError);
e.preventDefault();
return;
}
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError);
e.preventDefault();
return;
if (start && end) {
const value = content.substr(0, start) + '\n' + content.substr(end);
this._findInput.inputBox.value = value;
inputElement.setSelectionRange(start + 1, start + 1);
this._findInput.inputBox.layout();
e.preventDefault();
return;
}
}
if (e.equals(KeyCode.Tab)) {
if (this._isReplaceVisible) {
this._replaceInputBox.focus();
this._replaceInput.focus();
} else {
this._findInput.focusOnCaseSensitive();
}
@@ -720,20 +806,43 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
e.preventDefault();
return;
}
if (e.equals(KeyCode.UpArrow)) {
return stopPropagationForMultiLineUpwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));
}
if (e.equals(KeyCode.DownArrow)) {
return stopPropagationForMultiLineDownwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));
}
}
private _onReplaceInputKeyDown(e: IKeyboardEvent): void {
if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) {
if (platform.isWindows && platform.isNative && !this._ctrlEnterReplaceAllWarningPrompted) {
// this is the first time when users press Ctrl + Enter to replace all
this._notificationService.info(
nls.localize('ctrlEnter.keybindingChanged',
'Ctrl+Enter now inserts line break instead of replacing all. You can modify the keybinding for editor.action.replaceAll to override this behavior.')
);
if (e.equals(KeyCode.Enter)) {
this._controller.replace();
e.preventDefault();
return;
}
this._ctrlEnterReplaceAllWarningPrompted = true;
this._storageService.store(ctrlEnterReplaceAllWarningPromptedKey, true, StorageScope.GLOBAL);
if (e.equals(KeyMod.CtrlCmd | KeyCode.Enter)) {
this._controller.replaceAll();
e.preventDefault();
return;
}
const inputElement = this._replaceInput.inputBox.inputElement;
const start = inputElement.selectionStart;
const end = inputElement.selectionEnd;
const content = inputElement.value;
if (start && end) {
const value = content.substr(0, start) + '\n' + content.substr(end);
this._replaceInput.inputBox.value = value;
inputElement.setSelectionRange(start + 1, start + 1);
this._replaceInput.inputBox.layout();
e.preventDefault();
return;
}
}
if (e.equals(KeyCode.Tab)) {
@@ -753,6 +862,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
e.preventDefault();
return;
}
if (e.equals(KeyCode.UpArrow)) {
return stopPropagationForMultiLineUpwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
}
if (e.equals(KeyCode.DownArrow)) {
return stopPropagationForMultiLineDownwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
}
}
// ----- sash
@@ -777,6 +894,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
private _buildDomNode(): void {
const flexibleHeight = true;
const flexibleWidth = true;
// Find input
this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, {
width: FIND_INPUT_AREA_WIDTH,
@@ -796,7 +915,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
} catch (e) {
return { content: e.message };
}
}
},
flexibleHeight,
flexibleWidth,
flexibleMaxHeight: 118
}, this._contextKeyService, true));
this._findInput.setRegex(!!this._state.isRegex);
this._findInput.setCaseSensitive(!!this._state.matchCase);
@@ -818,11 +940,24 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
this._register(this._findInput.onCaseSensitiveKeyDown((e) => {
if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
if (this._isReplaceVisible) {
this._replaceInputBox.focus();
this._replaceInput.focus();
e.preventDefault();
}
}
}));
this._register(this._findInput.onRegexKeyDown((e) => {
if (e.equals(KeyCode.Tab)) {
if (this._isReplaceVisible) {
this._replaceInput.focusOnPreserve();
e.preventDefault();
}
}
}));
this._register(this._findInput.inputBox.onDidHeightChange((e) => {
if (this._tryUpdateHeight()) {
this._showViewZone();
}
}));
if (platform.isLinux) {
this._register(this._findInput.onMouseDown((e) => this._onFindInputMouseDown(e)));
}
@@ -852,13 +987,16 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
let findPart = document.createElement('div');
findPart.className = 'find-part';
findPart.appendChild(this._findInput.domNode);
findPart.appendChild(this._matchesCount);
findPart.appendChild(this._prevBtn.domNode);
findPart.appendChild(this._nextBtn.domNode);
const actionsContainer = document.createElement('div');
actionsContainer.className = 'find-actions';
findPart.appendChild(actionsContainer);
actionsContainer.appendChild(this._matchesCount);
actionsContainer.appendChild(this._prevBtn.domNode);
actionsContainer.appendChild(this._nextBtn.domNode);
// Toggle selection button
this._toggleSelectionFind = this._register(new SimpleCheckbox({
parent: findPart,
parent: actionsContainer,
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
onChange: () => {
if (this._toggleSelectionFind.checked) {
@@ -898,34 +1036,45 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
}));
findPart.appendChild(this._closeBtn.domNode);
actionsContainer.appendChild(this._closeBtn.domNode);
// Replace input
let replaceInput = document.createElement('div');
replaceInput.className = 'replace-input';
replaceInput.style.width = REPLACE_INPUT_AREA_WIDTH + 'px';
this._replaceInputBox = this._register(new ContextScopedHistoryInputBox(replaceInput, undefined, {
ariaLabel: NLS_REPLACE_INPUT_LABEL,
this._replaceInput = this._register(new ContextScopedReplaceInput(null, undefined, {
label: NLS_REPLACE_INPUT_LABEL,
placeholder: NLS_REPLACE_INPUT_PLACEHOLDER,
history: []
}, this._contextKeyService));
this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e)));
this._register(this._replaceInputBox.onDidChange(() => {
this._state.change({ replaceString: this._replaceInputBox.value }, false);
history: [],
flexibleHeight,
flexibleWidth,
flexibleMaxHeight: 118
}, this._contextKeyService, true));
this._replaceInput.setPreserveCase(!!this._state.preserveCase);
this._register(this._replaceInput.onKeyDown((e) => this._onReplaceInputKeyDown(e)));
this._register(this._replaceInput.inputBox.onDidChange(() => {
this._state.change({ replaceString: this._replaceInput.inputBox.value }, false);
}));
this._preserveCase = this._register(new Checkbox({
actionClassName: 'monaco-preserve-case',
title: NLS_PRESERVE_CASE_LABEL,
isChecked: false,
this._register(this._replaceInput.inputBox.onDidHeightChange((e) => {
if (this._isReplaceVisible && this._tryUpdateHeight()) {
this._showViewZone();
}
}));
this._preserveCase.checked = !!this._state.preserveCase;
this._register(this._preserveCase.onChange(viaKeyboard => {
if (!viaKeyboard) {
this._state.change({ preserveCase: !this._state.preserveCase }, false);
this._replaceInputBox.focus();
this._register(this._replaceInput.onDidOptionChange(() => {
this._state.change({
preserveCase: this._replaceInput.getPreserveCase()
}, true);
}));
this._register(this._replaceInput.onPreserveCaseKeyDown((e) => {
if (e.equals(KeyCode.Tab)) {
if (this._prevBtn.isEnabled()) {
this._prevBtn.focus();
} else if (this._nextBtn.isEnabled()) {
this._nextBtn.focus();
} else if (this._toggleSelectionFind.isEnabled()) {
this._toggleSelectionFind.focus();
} else if (this._closeBtn.isEnabled()) {
this._closeBtn.focus();
}
e.preventDefault();
}
}));
@@ -953,17 +1102,16 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
}));
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = 'block';
controls.appendChild(this._preserveCase.domNode);
replaceInput.appendChild(controls);
let replacePart = document.createElement('div');
replacePart.className = 'replace-part';
replacePart.appendChild(replaceInput);
replacePart.appendChild(this._replaceBtn.domNode);
replacePart.appendChild(this._replaceAllBtn.domNode);
replacePart.appendChild(this._replaceInput.domNode);
const replaceActionsContainer = document.createElement('div');
replaceActionsContainer.className = 'replace-actions';
replacePart.appendChild(replaceActionsContainer);
replaceActionsContainer.appendChild(this._replaceBtn.domNode);
replaceActionsContainer.appendChild(this._replaceAllBtn.domNode);
// Toggle replace button
this._toggleReplaceBtn = this._register(new SimpleButton({
@@ -972,7 +1120,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
onTrigger: () => {
this._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);
if (this._isReplaceVisible) {
this._replaceInputBox.width = this._findInput.inputBox.width;
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
this._replaceInput.inputBox.layout();
}
this._showViewZone();
}
@@ -1015,9 +1164,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
return;
}
this._domNode.style.width = `${width}px`;
this._findInput.inputBox.width = inputBoxWidth;
if (this._isReplaceVisible) {
this._replaceInputBox.width = inputBoxWidth;
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
}
this._findInput.inputBox.layout();
this._tryUpdateHeight();
}));
}
@@ -1077,6 +1230,10 @@ class SimpleCheckbox extends Widget {
return this._domNode;
}
public isEnabled(): boolean {
return (this._domNode.tabIndex >= 0);
}
public get checked(): boolean {
return this._checkbox.checked;
}
@@ -1086,7 +1243,7 @@ class SimpleCheckbox extends Widget {
}
public focus(): void {
this._checkbox.focus();
this._domNode.focus();
}
private enable(): void {
@@ -1245,4 +1402,11 @@ registerThemingParticipant((theme, collector) => {
if (inputActiveBackground) {
collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`);
}
// This rule is used to override the outline color for synthetic-focus find input.
const focusOutline = theme.getColor(focusBorder);
if (focusOutline) {
collector.addRule(`.monaco-workbench .monaco-editor .find-widget .monaco-inputbox.synthetic-focus { outline-color: ${focusOutline}; }`);
}
});