mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-21 04:20:11 -04:00
Merge from vscode e558dc6ea73a75bd69d7a0b485f0e7e4194c66bf (#6864)
This commit is contained in:
@@ -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}; }`);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user