mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-01 01:20:31 -04:00
Merge from master
This commit is contained in:
@@ -2,30 +2,31 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { registerEditorContribution, registerEditorAction, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleWholeWordKeybinding, ToggleSearchScopeKeybinding, CONTEXT_FIND_WIDGET_VISIBLE } from 'vs/editor/contrib/find/findModel';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { FindWidget, IFindController } from 'vs/editor/contrib/find/findWidget';
|
||||
import { EditorAction, EditorCommand, ServicesAccessor, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_FIND_WIDGET_VISIBLE, FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleSearchScopeKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/findModel';
|
||||
import { FindOptionsWidget } from 'vs/editor/contrib/find/findOptionsWidget';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { FindWidget, IFindController } from 'vs/editor/contrib/find/findWidget';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
const SEARCH_STRING_MAX_LENGTH = 524288;
|
||||
|
||||
export function getSelectionSearchString(editor: ICodeEditor): string {
|
||||
let selection = editor.getSelection();
|
||||
@@ -38,7 +39,9 @@ export function getSelectionSearchString(editor: ICodeEditor): string {
|
||||
return wordAtPosition.word;
|
||||
}
|
||||
} else {
|
||||
return editor.getModel().getValueInRange(selection);
|
||||
if (editor.getModel().getValueLengthInRange(selection) < SEARCH_STRING_MAX_LENGTH) {
|
||||
return editor.getModel().getValueInRange(selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +60,7 @@ export interface IFindStartOptions {
|
||||
seedSearchStringFromGlobalClipboard: boolean;
|
||||
shouldFocus: FindStartFocusAction;
|
||||
shouldAnimate: boolean;
|
||||
updateSearchScope: boolean;
|
||||
}
|
||||
|
||||
export class CommonFindController extends Disposable implements editorCommon.IEditorContribution {
|
||||
@@ -68,8 +72,9 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
protected _state: FindReplaceState;
|
||||
protected _updateHistoryDelayer: Delayer<void>;
|
||||
private _model: FindModelBoundToEditorModel;
|
||||
protected _storageService: IStorageService;
|
||||
private _storageService: IStorageService;
|
||||
private _clipboardService: IClipboardService;
|
||||
protected readonly _contextKeyService: IContextKeyService;
|
||||
|
||||
public static get(editor: ICodeEditor): CommonFindController {
|
||||
return editor.getContribution<CommonFindController>(CommonFindController.ID);
|
||||
@@ -84,6 +89,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._findWidgetVisible = CONTEXT_FIND_WIDGET_VISIBLE.bindTo(contextKeyService);
|
||||
this._contextKeyService = contextKeyService;
|
||||
this._storageService = storageService;
|
||||
this._clipboardService = clipboardService;
|
||||
|
||||
@@ -113,6 +119,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
});
|
||||
}
|
||||
}));
|
||||
@@ -170,6 +177,10 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
}, false);
|
||||
}
|
||||
|
||||
public isFindInputFocused(): boolean {
|
||||
return CONTEXT_FIND_INPUT_FOCUSED.getValue(this._contextKeyService);
|
||||
}
|
||||
|
||||
public getState(): FindReplaceState {
|
||||
return this._state;
|
||||
}
|
||||
@@ -184,14 +195,23 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
|
||||
public toggleCaseSensitive(): void {
|
||||
this._state.change({ matchCase: !this._state.matchCase }, false);
|
||||
if (!this._state.isRevealed) {
|
||||
this.highlightFindOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public toggleWholeWords(): void {
|
||||
this._state.change({ wholeWord: !this._state.wholeWord }, false);
|
||||
if (!this._state.isRevealed) {
|
||||
this.highlightFindOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public toggleRegex(): void {
|
||||
this._state.change({ isRegex: !this._state.isRegex }, false);
|
||||
if (!this._state.isRevealed) {
|
||||
this.highlightFindOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public toggleSearchScope(): void {
|
||||
@@ -200,7 +220,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
} else {
|
||||
let selection = this._editor.getSelection();
|
||||
if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, 1);
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, this._editor.getModel().getLineMaxColumn(selection.endLineNumber - 1));
|
||||
}
|
||||
if (!selection.isEmpty()) {
|
||||
this._state.change({ searchScope: selection }, true);
|
||||
@@ -256,6 +276,12 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
stateChanges.isReplaceRevealed = false;
|
||||
}
|
||||
|
||||
if (opts.updateSearchScope) {
|
||||
let currentSelection = this._editor.getSelection();
|
||||
if (!currentSelection.isEmpty()) {
|
||||
stateChanges.searchScope = currentSelection;
|
||||
}
|
||||
}
|
||||
|
||||
this._state.change(stateChanges, false);
|
||||
|
||||
@@ -337,7 +363,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IContextKeyService _contextKeyService: IContextKeyService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@@ -351,6 +377,11 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
this._createFindWidget();
|
||||
}
|
||||
|
||||
if (!this._widget.getPosition() && this._editor.getConfiguration().contribInfo.find.autoFindInSelection) {
|
||||
// not visible yet so we need to set search scope if `editor.find.autoFindInSelection` is `true`
|
||||
opts.updateSearchScope = true;
|
||||
}
|
||||
|
||||
super._start(opts);
|
||||
|
||||
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
|
||||
@@ -407,7 +438,8 @@ export class StartFindAction extends EditorAction {
|
||||
seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection,
|
||||
seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.globalFindClipboard,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -423,7 +455,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: null,
|
||||
primary: null,
|
||||
primary: 0,
|
||||
mac: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_E,
|
||||
},
|
||||
@@ -440,7 +472,8 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
seedSearchStringFromSelection: true,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: true
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
|
||||
controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
@@ -456,7 +489,8 @@ export abstract class MatchFindAction extends EditorAction {
|
||||
seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection,
|
||||
seedSearchStringFromGlobalClipboard: true,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -525,7 +559,8 @@ export abstract class SelectionMatchFindAction extends EditorAction {
|
||||
seedSearchStringFromSelection: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
this._run(controller);
|
||||
}
|
||||
@@ -606,22 +641,31 @@ export class StartFindReplaceAction extends EditorAction {
|
||||
|
||||
let controller = CommonFindController.get(editor);
|
||||
let currentSelection = editor.getSelection();
|
||||
// we only seed search string from selection when the current selection is single line and not empty.
|
||||
let seedSearchStringFromSelection = !currentSelection.isEmpty() &&
|
||||
currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection;
|
||||
let oldSearchString = controller.getState().searchString;
|
||||
// if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input
|
||||
// is still empty, so we should focus the Find Input instead of Replace Input.
|
||||
let shouldFocus = (!!oldSearchString || seedSearchStringFromSelection) ?
|
||||
let findInputFocused = controller.isFindInputFocused();
|
||||
// we only seed search string from selection when the current selection is single line and not empty,
|
||||
// + the find input is not focused
|
||||
let seedSearchStringFromSelection = !currentSelection.isEmpty()
|
||||
&& currentSelection.startLineNumber === currentSelection.endLineNumber && editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection
|
||||
&& !findInputFocused;
|
||||
/*
|
||||
* if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input is still empty, so we should focus the Find Input instead of Replace Input.
|
||||
|
||||
* findInputFocused true -> seedSearchStringFromSelection false, FocusReplaceInput
|
||||
* findInputFocused false, seedSearchStringFromSelection true FocusReplaceInput
|
||||
* findInputFocused false seedSearchStringFromSelection false FocusFindInput
|
||||
*/
|
||||
let shouldFocus = (findInputFocused || seedSearchStringFromSelection) ?
|
||||
FindStartFocusAction.FocusReplaceInput : FindStartFocusAction.FocusFindInput;
|
||||
|
||||
|
||||
if (controller) {
|
||||
controller.start({
|
||||
forceRevealReplace: true,
|
||||
seedSearchStringFromSelection: seedSearchStringFromSelection,
|
||||
seedSearchStringFromGlobalClipboard: editor.getConfiguration().contribInfo.find.seedSearchStringFromSelection,
|
||||
shouldFocus: shouldFocus,
|
||||
shouldAnimate: true
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,28 +2,27 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { FindMatch, IModelDecorationsChangeAccessor, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IModelDecorationsChangeAccessor, FindMatch, IModelDeltaDecoration, TrackedRangeStickiness, OverviewRulerLane } from 'vs/editor/common/model';
|
||||
|
||||
export class FindDecorations implements IDisposable {
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _editor: IActiveCodeEditor;
|
||||
private _decorations: string[];
|
||||
private _overviewRulerApproximateDecorations: string[];
|
||||
private _findScopeDecorationId: string;
|
||||
private _rangeHighlightDecorationId: string;
|
||||
private _highlightedDecorationId: string;
|
||||
private _findScopeDecorationId: string | null;
|
||||
private _rangeHighlightDecorationId: string | null;
|
||||
private _highlightedDecorationId: string | null;
|
||||
private _startPosition: Position;
|
||||
|
||||
constructor(editor: ICodeEditor) {
|
||||
constructor(editor: IActiveCodeEditor) {
|
||||
this._editor = editor;
|
||||
this._decorations = [];
|
||||
this._overviewRulerApproximateDecorations = [];
|
||||
@@ -36,13 +35,11 @@ export class FindDecorations implements IDisposable {
|
||||
public dispose(): void {
|
||||
this._editor.deltaDecorations(this._allDecorations(), []);
|
||||
|
||||
this._editor = null;
|
||||
this._decorations = [];
|
||||
this._overviewRulerApproximateDecorations = [];
|
||||
this._findScopeDecorationId = null;
|
||||
this._rangeHighlightDecorationId = null;
|
||||
this._highlightedDecorationId = null;
|
||||
this._startPosition = null;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
@@ -57,7 +54,7 @@ export class FindDecorations implements IDisposable {
|
||||
return this._decorations.length;
|
||||
}
|
||||
|
||||
public getFindScope(): Range {
|
||||
public getFindScope(): Range | null {
|
||||
if (this._findScopeDecorationId) {
|
||||
return this._editor.getModel().getDecorationRange(this._findScopeDecorationId);
|
||||
}
|
||||
@@ -93,8 +90,8 @@ export class FindDecorations implements IDisposable {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public setCurrentFindMatch(nextMatch: Range): number {
|
||||
let newCurrentDecorationId: string = null;
|
||||
public setCurrentFindMatch(nextMatch: Range | null): number {
|
||||
let newCurrentDecorationId: string | null = null;
|
||||
let matchPosition = 0;
|
||||
if (nextMatch) {
|
||||
for (let i = 0, len = this._decorations.length; i < len; i++) {
|
||||
@@ -122,7 +119,7 @@ export class FindDecorations implements IDisposable {
|
||||
this._rangeHighlightDecorationId = null;
|
||||
}
|
||||
if (newCurrentDecorationId !== null) {
|
||||
let rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId);
|
||||
let rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId)!;
|
||||
if (rng.startLineNumber !== rng.endLineNumber && rng.endColumn === 1) {
|
||||
let lineBeforeEnd = rng.endLineNumber - 1;
|
||||
let lineBeforeEndMaxColumn = this._editor.getModel().getLineMaxColumn(lineBeforeEnd);
|
||||
@@ -136,7 +133,7 @@ export class FindDecorations implements IDisposable {
|
||||
return matchPosition;
|
||||
}
|
||||
|
||||
public set(findMatches: FindMatch[], findScope: Range): void {
|
||||
public set(findMatches: FindMatch[], findScope: Range | null): void {
|
||||
this._editor.changeDecorations((accessor) => {
|
||||
|
||||
let findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION;
|
||||
@@ -208,7 +205,7 @@ export class FindDecorations implements IDisposable {
|
||||
});
|
||||
}
|
||||
|
||||
public matchBeforePosition(position: Position): Range {
|
||||
public matchBeforePosition(position: Position): Range | null {
|
||||
if (this._decorations.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -230,7 +227,7 @@ export class FindDecorations implements IDisposable {
|
||||
return this._editor.getModel().getDecorationRange(this._decorations[this._decorations.length - 1]);
|
||||
}
|
||||
|
||||
public matchAfterPosition(position: Position): Range {
|
||||
public matchAfterPosition(position: Position): Range | null {
|
||||
if (this._decorations.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -272,7 +269,6 @@ export class FindDecorations implements IDisposable {
|
||||
showIfCollapsed: true,
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
darkColor: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
position: OverviewRulerLane.Center
|
||||
}
|
||||
});
|
||||
@@ -283,7 +279,6 @@ export class FindDecorations implements IDisposable {
|
||||
showIfCollapsed: true,
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
darkColor: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
position: OverviewRulerLane.Center
|
||||
}
|
||||
});
|
||||
@@ -298,7 +293,6 @@ export class FindDecorations implements IDisposable {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
darkColor: themeColorFromId(overviewRulerFindMatchForeground),
|
||||
position: OverviewRulerLane.Center
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,27 +2,26 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern';
|
||||
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { FindDecorations } from './findDecorations';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent } from './findState';
|
||||
import { ReplaceAllCommand } from './replaceAllCommand';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference, FindMatch, ITextModel } from 'vs/editor/common/model';
|
||||
import { SearchParams } from 'vs/editor/common/model/textModelSearch';
|
||||
import { FindDecorations } from 'vs/editor/contrib/find/findDecorations';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
||||
import { ReplaceAllCommand } from 'vs/editor/contrib/find/replaceAllCommand';
|
||||
import { ReplacePattern, parseReplaceString } from 'vs/editor/contrib/find/replacePattern';
|
||||
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ITextModel, FindMatch, EndOfLinePreference } from 'vs/editor/common/model';
|
||||
|
||||
export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('findWidgetVisible', false);
|
||||
export const CONTEXT_FIND_WIDGET_NOT_VISIBLE: ContextKeyExpr = CONTEXT_FIND_WIDGET_VISIBLE.toNegated();
|
||||
@@ -70,7 +69,7 @@ const RESEARCH_DELAY = 240;
|
||||
|
||||
export class FindModelBoundToEditorModel {
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _editor: IActiveCodeEditor;
|
||||
private _state: FindReplaceState;
|
||||
private _toDispose: IDisposable[];
|
||||
private _decorations: FindDecorations;
|
||||
@@ -80,7 +79,7 @@ export class FindModelBoundToEditorModel {
|
||||
private _updateDecorationsScheduler: RunOnceScheduler;
|
||||
private _isDisposed: boolean;
|
||||
|
||||
constructor(editor: ICodeEditor, state: FindReplaceState) {
|
||||
constructor(editor: IActiveCodeEditor, state: FindReplaceState) {
|
||||
this._editor = editor;
|
||||
this._state = state;
|
||||
this._toDispose = [];
|
||||
@@ -159,19 +158,17 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
private static _getSearchRange(model: ITextModel, findScope: Range): Range {
|
||||
let searchRange = model.getFullModelRange();
|
||||
|
||||
private static _getSearchRange(model: ITextModel, findScope: Range | null): Range {
|
||||
// If we have set now or before a find scope, use it for computing the search range
|
||||
if (findScope) {
|
||||
searchRange = searchRange.intersectRanges(findScope);
|
||||
return findScope;
|
||||
}
|
||||
|
||||
return searchRange;
|
||||
return model.getFullModelRange();
|
||||
}
|
||||
|
||||
private research(moveCursor: boolean, newFindScope?: Range): void {
|
||||
let findScope: Range = null;
|
||||
private research(moveCursor: boolean, newFindScope?: Range | null): void {
|
||||
let findScope: Range | null = null;
|
||||
if (typeof newFindScope !== 'undefined') {
|
||||
findScope = newFindScope;
|
||||
} else {
|
||||
@@ -179,8 +176,12 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
if (findScope !== null) {
|
||||
if (findScope.startLineNumber !== findScope.endLineNumber) {
|
||||
// multiline find scope => expand to line starts / ends
|
||||
findScope = new Range(findScope.startLineNumber, 1, findScope.endLineNumber, this._editor.getModel().getLineMaxColumn(findScope.endLineNumber));
|
||||
if (findScope.endColumn === 1) {
|
||||
findScope = new Range(findScope.startLineNumber, 1, findScope.endLineNumber - 1, this._editor.getModel().getLineMaxColumn(findScope.endLineNumber - 1));
|
||||
} else {
|
||||
// multiline find scope => expand to line starts / ends
|
||||
findScope = new Range(findScope.startLineNumber, 1, findScope.endLineNumber, this._editor.getModel().getLineMaxColumn(findScope.endLineNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
if (!prevMatch) {
|
||||
// there is precisely one match and selection is on top of it
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isRecursed && !searchRange.containsRange(prevMatch.range)) {
|
||||
@@ -355,7 +356,7 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
private _getNextMatch(after: Position, captureMatches: boolean, forceMove: boolean, isRecursed: boolean = false): FindMatch {
|
||||
private _getNextMatch(after: Position, captureMatches: boolean, forceMove: boolean, isRecursed: boolean = false): FindMatch | null {
|
||||
if (this._cannotFind()) {
|
||||
return null;
|
||||
}
|
||||
@@ -435,7 +436,7 @@ export class FindModelBoundToEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
private _findMatches(findScope: Range, captureMatches: boolean, limitResultCount: number): FindMatch[] {
|
||||
private _findMatches(findScope: Range | null, captureMatches: boolean, limitResultCount: number): FindMatch[] {
|
||||
let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope);
|
||||
return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches, limitResultCount);
|
||||
}
|
||||
@@ -494,7 +495,7 @@ export class FindModelBoundToEditorModel {
|
||||
this._executeEditorCommand('replaceAll', command);
|
||||
}
|
||||
|
||||
private _regularReplaceAll(findScope: Range): void {
|
||||
private _regularReplaceAll(findScope: Range | null): void {
|
||||
const replacePattern = this._getReplacePattern();
|
||||
// Get all the ranges (even more than the highlighted ones)
|
||||
let matches = this._findMatches(findScope, replacePattern.hasReplacementPatterns, Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
|
||||
@@ -3,18 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { CaseSensitiveCheckbox, RegexCheckbox, WholeWordsCheckbox } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { FIND_IDS } from 'vs/editor/contrib/find/findModel';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { CaseSensitiveCheckbox, WholeWordsCheckbox, RegexCheckbox } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { inputActiveOptionBorder, editorWidgetBackground, contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
export class FindOptionsWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
@@ -190,17 +188,17 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let widgetBackground = theme.getColor(editorWidgetBackground);
|
||||
const widgetBackground = theme.getColor(editorWidgetBackground);
|
||||
if (widgetBackground) {
|
||||
collector.addRule(`.monaco-editor .findOptionsWidget { background-color: ${widgetBackground}; }`);
|
||||
}
|
||||
|
||||
let widgetShadowColor = theme.getColor(widgetShadow);
|
||||
const widgetShadowColor = theme.getColor(widgetShadow);
|
||||
if (widgetShadowColor) {
|
||||
collector.addRule(`.monaco-editor .findOptionsWidget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
|
||||
}
|
||||
|
||||
let hcBorder = theme.getColor(contrastBorder);
|
||||
const hcBorder = theme.getColor(contrastBorder);
|
||||
if (hcBorder) {
|
||||
collector.addRule(`.monaco-editor .findOptionsWidget { border: 2px solid ${hcBorder}; }`);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
@@ -66,10 +65,10 @@ export class FindReplaceState implements IDisposable {
|
||||
private _wholeWordOverride: FindOptionOverride;
|
||||
private _matchCase: boolean;
|
||||
private _matchCaseOverride: FindOptionOverride;
|
||||
private _searchScope: Range;
|
||||
private _searchScope: Range | null;
|
||||
private _matchesPosition: number;
|
||||
private _matchesCount: number;
|
||||
private _currentMatch: Range;
|
||||
private _currentMatch: Range | null;
|
||||
private readonly _onFindReplaceStateChange: Emitter<FindReplaceStateChangedEvent>;
|
||||
|
||||
public get searchString(): string { return this._searchString; }
|
||||
@@ -84,10 +83,10 @@ export class FindReplaceState implements IDisposable {
|
||||
public get actualWholeWord(): boolean { return this._wholeWord; }
|
||||
public get actualMatchCase(): boolean { return this._matchCase; }
|
||||
|
||||
public get searchScope(): Range { return this._searchScope; }
|
||||
public get searchScope(): Range | null { return this._searchScope; }
|
||||
public get matchesPosition(): number { return this._matchesPosition; }
|
||||
public get matchesCount(): number { return this._matchesCount; }
|
||||
public get currentMatch(): Range { return this._currentMatch; }
|
||||
public get currentMatch(): Range | null { return this._currentMatch; }
|
||||
public get onFindReplaceStateChange(): Event<FindReplaceStateChangedEvent> { return this._onFindReplaceStateChange.event; }
|
||||
|
||||
constructor() {
|
||||
@@ -111,7 +110,7 @@ export class FindReplaceState implements IDisposable {
|
||||
public dispose(): void {
|
||||
}
|
||||
|
||||
public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range): void {
|
||||
public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void {
|
||||
let changeEvent: FindReplaceStateChangedEvent = {
|
||||
moveCursor: false,
|
||||
updateHistory: false,
|
||||
|
||||
@@ -36,13 +36,7 @@
|
||||
height: 34px; /* find input height */
|
||||
overflow: hidden;
|
||||
line-height: 19px;
|
||||
|
||||
-webkit-transition: top 200ms linear;
|
||||
-o-transition: top 200ms linear;
|
||||
-moz-transition: top 200ms linear;
|
||||
-ms-transition: top 200ms linear;
|
||||
transition: top 200ms linear;
|
||||
|
||||
padding: 0 4px;
|
||||
}
|
||||
/* Find widget when replace is toggled on */
|
||||
@@ -253,7 +247,7 @@
|
||||
|
||||
/* COLLAPSED (SMALLER THAN NARROW) */
|
||||
.monaco-editor .find-widget.collapsed-find-widget {
|
||||
max-width: 111px !important;
|
||||
max-width: 170px !important;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget.collapsed-find-widget .button.previous,
|
||||
@@ -264,10 +258,6 @@
|
||||
display:none;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget.collapsed-find-widget > .find-part .monaco-inputbox > .wrapper > .input {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.monaco-editor .findMatch {
|
||||
-webkit-animation-duration: 0;
|
||||
-webkit-animation-name: inherit !important;
|
||||
|
||||
@@ -3,36 +3,34 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./findWidget';
|
||||
import * as nls from 'vs/nls';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
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 { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
||||
import { IMessage as InputBoxMessage, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Sash, IHorizontalSashLayoutProvider, ISashEvent, Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { FIND_IDS, MATCHES_LIMIT, CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITheme, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { editorFindRangeHighlight, editorFindMatch, editorFindMatchHighlight, contrastBorder, inputBackground, editorWidgetBackground, inputActiveOptionBorder, widgetShadow, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorBorder, errorForeground, editorWidgetBorder, editorFindMatchBorder, editorFindMatchHighlightBorder, editorFindRangeHighlightBorder, editorWidgetResizeBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MATCHES_LIMIT } from 'vs/editor/contrib/find/findModel';
|
||||
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, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget';
|
||||
|
||||
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
replaceAll(): void;
|
||||
@@ -106,6 +104,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
private _isVisible: boolean;
|
||||
private _isReplaceVisible: boolean;
|
||||
private _ignoreChangeEvent: boolean;
|
||||
|
||||
private _findFocusTracker: dom.IFocusTracker;
|
||||
private _findInputFocused: IContextKey<boolean>;
|
||||
@@ -137,8 +136,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
this._isVisible = false;
|
||||
this._isReplaceVisible = false;
|
||||
this._ignoreChangeEvent = false;
|
||||
|
||||
this._updateHistoryDelayer = new Delayer<void>(500);
|
||||
this._register(toDisposable(() => this._updateHistoryDelayer.cancel()));
|
||||
this._register(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));
|
||||
this._buildDomNode();
|
||||
this._updateButtons();
|
||||
@@ -155,7 +156,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
if (e.layoutInfo) {
|
||||
this._tryUpdateWidgetWidth();
|
||||
}
|
||||
|
||||
if (e.accessibilitySupport) {
|
||||
this.updateAccessibilitySupport();
|
||||
}
|
||||
}));
|
||||
this.updateAccessibilitySupport();
|
||||
this._register(this._codeEditor.onDidChangeCursorSelection(() => {
|
||||
if (this._isVisible) {
|
||||
this._updateToggleSelectionFindButton();
|
||||
@@ -196,15 +202,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._applyTheme(themeService.getTheme());
|
||||
this._register(themeService.onThemeChange(this._applyTheme.bind(this)));
|
||||
|
||||
this._register(this._codeEditor.onDidChangeModel((e) => {
|
||||
this._register(this._codeEditor.onDidChangeModel(() => {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._viewZoneId === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._codeEditor.changeViewZones((accessor) => {
|
||||
accessor.removeZone(this._viewZoneId);
|
||||
this._viewZoneId = undefined;
|
||||
@@ -248,7 +252,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
|
||||
if (e.searchString) {
|
||||
this._findInput.setValue(this._state.searchString);
|
||||
try {
|
||||
this._ignoreChangeEvent = true;
|
||||
this._findInput.setValue(this._state.searchString);
|
||||
} finally {
|
||||
this._ignoreChangeEvent = false;
|
||||
}
|
||||
this._updateButtons();
|
||||
}
|
||||
if (e.replaceString) {
|
||||
@@ -256,7 +265,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
}
|
||||
if (e.isRevealed) {
|
||||
if (this._state.isRevealed) {
|
||||
this._reveal(true);
|
||||
this._reveal();
|
||||
} else {
|
||||
this._hide(true);
|
||||
}
|
||||
@@ -297,6 +306,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
dom.toggleClass(this._domNode, 'no-results', showRedOutline);
|
||||
|
||||
this._updateMatchesCount();
|
||||
this._updateButtons();
|
||||
}
|
||||
if (e.searchString || e.currentMatch) {
|
||||
this._layoutViewZone();
|
||||
@@ -372,8 +382,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._closeBtn.setEnabled(this._isVisible);
|
||||
|
||||
let findInputIsNonEmpty = (this._state.searchString.length > 0);
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty);
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty);
|
||||
let matchesCount = this._state.matchesCount ? true : false;
|
||||
this._prevBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._nextBtn.setEnabled(this._isVisible && findInputIsNonEmpty && matchesCount);
|
||||
this._replaceBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
this._replaceAllBtn.setEnabled(this._isVisible && this._isReplaceVisible && findInputIsNonEmpty);
|
||||
|
||||
@@ -386,7 +397,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._toggleReplaceBtn.setEnabled(this._isVisible && canReplace);
|
||||
}
|
||||
|
||||
private _reveal(animate: boolean): void {
|
||||
private _reveal(): void {
|
||||
if (!this._isVisible) {
|
||||
this._isVisible = true;
|
||||
|
||||
@@ -404,6 +415,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
dom.addClass(this._domNode, 'visible');
|
||||
this._domNode.setAttribute('aria-hidden', 'false');
|
||||
}, 0);
|
||||
|
||||
// validate query again as it's being dismissed when we hide the find widget.
|
||||
setTimeout(() => {
|
||||
this._findInput.validate();
|
||||
}, 200);
|
||||
|
||||
this._codeEditor.layoutOverlayWidget(this);
|
||||
|
||||
let adjustEditorScrollTop = true;
|
||||
@@ -441,6 +458,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
|
||||
dom.removeClass(this._domNode, 'visible');
|
||||
this._domNode.setAttribute('aria-hidden', 'true');
|
||||
this._findInput.clearMessage();
|
||||
if (focusTheEditor) {
|
||||
this._codeEditor.focus();
|
||||
}
|
||||
@@ -512,10 +530,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
inputForeground: theme.getColor(inputForeground),
|
||||
inputBorder: theme.getColor(inputBorder),
|
||||
inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground),
|
||||
inputValidationInfoForeground: theme.getColor(inputValidationInfoForeground),
|
||||
inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder),
|
||||
inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground),
|
||||
inputValidationWarningForeground: theme.getColor(inputValidationWarningForeground),
|
||||
inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder),
|
||||
inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground),
|
||||
inputValidationErrorForeground: theme.getColor(inputValidationErrorForeground),
|
||||
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder)
|
||||
};
|
||||
this._findInput.style(inputStyles);
|
||||
@@ -591,7 +612,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
if (this._toggleSelectionFind.checked) {
|
||||
let selection = this._codeEditor.getSelection();
|
||||
if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, 1);
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, this._codeEditor.getModel().getLineMaxColumn(selection.endLineNumber - 1));
|
||||
}
|
||||
let currentMatch = this._state.currentMatch;
|
||||
if (selection.startLineNumber !== selection.endLineNumber) {
|
||||
@@ -613,13 +634,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
private _onFindInputKeyDown(e: IKeyboardEvent): void {
|
||||
|
||||
if (e.equals(KeyCode.Enter)) {
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().done(null, onUnexpectedError);
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(null, onUnexpectedError);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().done(null, onUnexpectedError);
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(null, onUnexpectedError);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
@@ -675,13 +696,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
}
|
||||
|
||||
// ----- sash
|
||||
public getHorizontalSashTop(sash: Sash): number {
|
||||
public getHorizontalSashTop(_sash: Sash): number {
|
||||
return 0;
|
||||
}
|
||||
public getHorizontalSashLeft?(sash: Sash): number {
|
||||
public getHorizontalSashLeft?(_sash: Sash): number {
|
||||
return 0;
|
||||
}
|
||||
public getHorizontalSashWidth?(sash: Sash): number {
|
||||
public getHorizontalSashWidth?(_sash: Sash): number {
|
||||
return 500;
|
||||
}
|
||||
|
||||
@@ -720,12 +741,15 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
return { content: e.message };
|
||||
}
|
||||
}
|
||||
}, this._contextKeyService));
|
||||
}, this._contextKeyService, true));
|
||||
this._findInput.setRegex(!!this._state.isRegex);
|
||||
this._findInput.setCaseSensitive(!!this._state.matchCase);
|
||||
this._findInput.setWholeWords(!!this._state.wholeWord);
|
||||
this._register(this._findInput.onKeyDown((e) => this._onFindInputKeyDown(e)));
|
||||
this._register(this._findInput.inputBox.onDidChange(() => {
|
||||
if (this._ignoreChangeEvent) {
|
||||
return;
|
||||
}
|
||||
this._state.change({ searchString: this._findInput.getValue() }, true);
|
||||
}));
|
||||
this._register(this._findInput.onDidOptionChange(() => {
|
||||
@@ -756,7 +780,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
label: NLS_PREVIOUS_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.PreviousMatchFindAction),
|
||||
className: 'previous',
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().done(null, onUnexpectedError);
|
||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(null, onUnexpectedError);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -765,7 +789,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
label: NLS_NEXT_MATCH_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.NextMatchFindAction),
|
||||
className: 'next',
|
||||
onTrigger: () => {
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().done(null, onUnexpectedError);
|
||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(null, onUnexpectedError);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -784,7 +808,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
if (this._toggleSelectionFind.checked) {
|
||||
let selection = this._codeEditor.getSelection();
|
||||
if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, 1);
|
||||
selection = selection.setEndPosition(selection.endLineNumber - 1, this._codeEditor.getModel().getLineMaxColumn(selection.endLineNumber - 1));
|
||||
}
|
||||
if (!selection.isEmpty()) {
|
||||
this._state.change({ searchScope: selection }, true);
|
||||
@@ -832,8 +856,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
history: []
|
||||
}, this._contextKeyService));
|
||||
|
||||
|
||||
this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e)));
|
||||
this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'input', (e) => {
|
||||
this._register(this._replaceInputBox.onDidChange(() => {
|
||||
this._state.change({ replaceString: this._replaceInputBox.value }, false);
|
||||
}));
|
||||
|
||||
@@ -912,7 +937,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._resized = false;
|
||||
let originalWidth = FIND_WIDGET_INITIAL_WIDTH;
|
||||
|
||||
this._register(this._resizeSash.onDidStart((e: ISashEvent) => {
|
||||
this._register(this._resizeSash.onDidStart(() => {
|
||||
originalWidth = dom.getTotalWidth(this._domNode);
|
||||
}));
|
||||
|
||||
@@ -936,6 +961,11 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private updateAccessibilitySupport(): void {
|
||||
const value = this._codeEditor.getConfiguration().accessibilitySupport;
|
||||
this._findInput.setFocusInputOnOptionClick(value !== platform.AccessibilitySupport.Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISimpleCheckboxOpts {
|
||||
@@ -979,7 +1009,7 @@ class SimpleCheckbox extends Widget {
|
||||
|
||||
this._opts.parent.appendChild(this._domNode);
|
||||
|
||||
this.onchange(this._checkbox, (e) => {
|
||||
this.onchange(this._checkbox, () => {
|
||||
this._opts.onChange();
|
||||
});
|
||||
}
|
||||
@@ -1142,4 +1172,8 @@ registerThemingParticipant((theme, collector) => {
|
||||
}
|
||||
}
|
||||
|
||||
const inputActiveBorder = theme.getColor(inputActiveOptionBorder);
|
||||
if (inputActiveBorder) {
|
||||
collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { border: 1px solid ${inputActiveBorder.toString()}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
|
||||
@@ -5,47 +5,57 @@
|
||||
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
const enum ReplacePatternKind {
|
||||
StaticValue = 0,
|
||||
DynamicPieces = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigned when the replace pattern is entirely static.
|
||||
*/
|
||||
class StaticValueReplacePattern {
|
||||
public readonly kind = ReplacePatternKind.StaticValue;
|
||||
constructor(public readonly staticValue: string) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigned when the replace pattern has replacemend patterns.
|
||||
*/
|
||||
class DynamicPiecesReplacePattern {
|
||||
public readonly kind = ReplacePatternKind.DynamicPieces;
|
||||
constructor(public readonly pieces: ReplacePiece[]) { }
|
||||
}
|
||||
|
||||
export class ReplacePattern {
|
||||
|
||||
public static fromStaticValue(value: string): ReplacePattern {
|
||||
return new ReplacePattern([ReplacePiece.staticValue(value)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigned when the replace pattern is entirely static.
|
||||
*/
|
||||
private readonly _staticValue: string;
|
||||
private readonly _state: StaticValueReplacePattern | DynamicPiecesReplacePattern;
|
||||
|
||||
public get hasReplacementPatterns(): boolean {
|
||||
return this._staticValue === null;
|
||||
return (this._state.kind === ReplacePatternKind.DynamicPieces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigned when the replace pattern has replacemend patterns.
|
||||
*/
|
||||
private readonly _pieces: ReplacePiece[];
|
||||
|
||||
constructor(pieces: ReplacePiece[]) {
|
||||
constructor(pieces: ReplacePiece[] | null) {
|
||||
if (!pieces || pieces.length === 0) {
|
||||
this._staticValue = '';
|
||||
this._pieces = null;
|
||||
this._state = new StaticValueReplacePattern('');
|
||||
} else if (pieces.length === 1 && pieces[0].staticValue !== null) {
|
||||
this._staticValue = pieces[0].staticValue;
|
||||
this._pieces = null;
|
||||
this._state = new StaticValueReplacePattern(pieces[0].staticValue);
|
||||
} else {
|
||||
this._staticValue = null;
|
||||
this._pieces = pieces;
|
||||
this._state = new DynamicPiecesReplacePattern(pieces);
|
||||
}
|
||||
}
|
||||
|
||||
public buildReplaceString(matches: string[]): string {
|
||||
if (this._staticValue !== null) {
|
||||
return this._staticValue;
|
||||
public buildReplaceString(matches: string[] | null): string {
|
||||
if (this._state.kind === ReplacePatternKind.StaticValue) {
|
||||
return this._state.staticValue;
|
||||
}
|
||||
|
||||
let result = '';
|
||||
for (let i = 0, len = this._pieces.length; i < len; i++) {
|
||||
let piece = this._pieces[i];
|
||||
for (let i = 0, len = this._state.pieces.length; i < len; i++) {
|
||||
let piece = this._state.pieces[i];
|
||||
if (piece.staticValue !== null) {
|
||||
// static value ReplacePiece
|
||||
result += piece.staticValue;
|
||||
@@ -59,7 +69,10 @@ export class ReplacePattern {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _substitute(matchIndex: number, matches: string[]): string {
|
||||
private static _substitute(matchIndex: number, matches: string[] | null): string {
|
||||
if (matches === null) {
|
||||
return '';
|
||||
}
|
||||
if (matchIndex === 0) {
|
||||
return matches[0];
|
||||
}
|
||||
@@ -91,10 +104,10 @@ export class ReplacePiece {
|
||||
return new ReplacePiece(null, index);
|
||||
}
|
||||
|
||||
public readonly staticValue: string;
|
||||
public readonly staticValue: string | null;
|
||||
public readonly matchIndex: number;
|
||||
|
||||
private constructor(staticValue: string, matchIndex: number) {
|
||||
private constructor(staticValue: string | null, matchIndex: number) {
|
||||
this.staticValue = staticValue;
|
||||
this.matchIndex = matchIndex;
|
||||
}
|
||||
@@ -185,7 +198,7 @@ export function parseReplaceString(replaceString: string): ReplacePattern {
|
||||
}
|
||||
|
||||
let nextChCode = replaceString.charCodeAt(i);
|
||||
// let replaceWithCharacter: string = null;
|
||||
// let replaceWithCharacter: string | null = null;
|
||||
|
||||
switch (nextChCode) {
|
||||
case CharCode.Backslash:
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 28px;
|
||||
right: 18px;
|
||||
width: 220px;
|
||||
max-width: calc(100% - 28px - 28px - 8px);
|
||||
pointer-events: none;
|
||||
padding: 0 10px 10px;
|
||||
}
|
||||
|
||||
.monaco-workbench .simple-find-part {
|
||||
@@ -22,11 +23,6 @@
|
||||
padding: 4px;
|
||||
align-items: center;
|
||||
pointer-events: all;
|
||||
|
||||
-webkit-transition: top 200ms linear;
|
||||
-o-transition: top 200ms linear;
|
||||
-moz-transition: top 200ms linear;
|
||||
-ms-transition: top 200ms linear;
|
||||
transition: top 200ms linear;
|
||||
}
|
||||
|
||||
@@ -38,10 +34,6 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Temporarily we don't show match numbers */
|
||||
.monaco-workbench .simple-find-part .monaco-findInput .controls {
|
||||
display: none;
|
||||
}
|
||||
.monaco-workbench .simple-find-part .monaco-findInput .monaco-inputbox .wrapper .input {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@@ -5,17 +5,18 @@
|
||||
|
||||
import 'vs/css!./simpleFindWidget';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { FindInput } from 'vs/base/browser/ui/findinput/findInput';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { FindInput } from 'vs/base/browser/ui/findinput/findInput';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { registerThemingParticipant, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { inputBackground, inputActiveOptionBorder, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorBorder, editorWidgetBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SimpleButton } from './findWidget';
|
||||
import { ContextScopedFindInput } from 'vs/platform/widget/browser/contextScopedHistoryWidget';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { editorWidgetBackground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ContextScopedFindInput } from 'vs/platform/widget/browser/contextScopedHistoryWidget';
|
||||
|
||||
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
|
||||
const NLS_FIND_INPUT_PLACEHOLDER = nls.localize('placeholder.find', "Find");
|
||||
@@ -27,21 +28,23 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
private _findInput: FindInput;
|
||||
private _domNode: HTMLElement;
|
||||
private _innerDomNode: HTMLElement;
|
||||
private _isVisible: boolean;
|
||||
private _isVisible: boolean = false;
|
||||
private _focusTracker: dom.IFocusTracker;
|
||||
private _findInputFocusTracker: dom.IFocusTracker;
|
||||
private _updateHistoryDelayer: Delayer<void>;
|
||||
|
||||
constructor(
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
private readonly _state: FindReplaceState = new FindReplaceState(),
|
||||
showOptionButtons?: boolean
|
||||
) {
|
||||
super();
|
||||
|
||||
this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewService, {
|
||||
label: NLS_FIND_INPUT_LABEL,
|
||||
placeholder: NLS_FIND_INPUT_PLACEHOLDER,
|
||||
}, contextKeyService));
|
||||
}, contextKeyService, showOptionButtons));
|
||||
|
||||
// Find History with update delayer
|
||||
this._updateHistoryDelayer = new Delayer<void>(500);
|
||||
@@ -51,6 +54,24 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
this._delayedUpdateHistory();
|
||||
});
|
||||
|
||||
this._findInput.setRegex(!!this._state.isRegex);
|
||||
this._findInput.setCaseSensitive(!!this._state.matchCase);
|
||||
this._findInput.setWholeWords(!!this._state.wholeWord);
|
||||
|
||||
this._register(this._findInput.onDidOptionChange(() => {
|
||||
this._state.change({
|
||||
isRegex: this._findInput.getRegex(),
|
||||
wholeWord: this._findInput.getWholeWords(),
|
||||
matchCase: this._findInput.getCaseSensitive()
|
||||
}, true);
|
||||
}));
|
||||
|
||||
this._register(this._state.onFindReplaceStateChange(() => {
|
||||
this._findInput.setRegex(this._state.isRegex);
|
||||
this._findInput.setWholeWords(this._state.wholeWord);
|
||||
this._findInput.setCaseSensitive(this._state.matchCase);
|
||||
}));
|
||||
|
||||
this._register(this._findInput.onKeyDown((e) => {
|
||||
if (e.equals(KeyCode.Enter)) {
|
||||
this.find(false);
|
||||
@@ -134,7 +155,7 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
}
|
||||
|
||||
public get focusTracker(): dom.IFocusTracker {
|
||||
return this._findInputFocusTracker;
|
||||
return this._focusTracker;
|
||||
}
|
||||
|
||||
public updateTheme(theme: ITheme): void {
|
||||
@@ -144,10 +165,13 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
inputForeground: theme.getColor(inputForeground),
|
||||
inputBorder: theme.getColor(inputBorder),
|
||||
inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground),
|
||||
inputValidationInfoForeground: theme.getColor(inputValidationInfoForeground),
|
||||
inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder),
|
||||
inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground),
|
||||
inputValidationWarningForeground: theme.getColor(inputValidationWarningForeground),
|
||||
inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder),
|
||||
inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground),
|
||||
inputValidationErrorForeground: theme.getColor(inputValidationErrorForeground),
|
||||
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder)
|
||||
};
|
||||
this._findInput.style(inputStyles);
|
||||
@@ -187,6 +211,19 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public show(initialInput?: string): void {
|
||||
if (initialInput && !this._isVisible) {
|
||||
this._findInput.setValue(initialInput);
|
||||
}
|
||||
|
||||
this._isVisible = true;
|
||||
|
||||
setTimeout(() => {
|
||||
dom.addClass(this._innerDomNode, 'visible');
|
||||
this._innerDomNode.setAttribute('aria-hidden', 'false');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
if (this._isVisible) {
|
||||
this._isVisible = false;
|
||||
@@ -203,6 +240,18 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
protected _updateHistory() {
|
||||
this._findInput.inputBox.addToHistory();
|
||||
}
|
||||
|
||||
protected _getRegexValue(): boolean {
|
||||
return this._findInput.getRegex();
|
||||
}
|
||||
|
||||
protected _getWholeWordValue(): boolean {
|
||||
return this._findInput.getWholeWords();
|
||||
}
|
||||
|
||||
protected _getCaseSensitiveValue(): boolean {
|
||||
return this._findInput.getCaseSensitive();
|
||||
}
|
||||
}
|
||||
|
||||
// theming
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
@@ -2,29 +2,31 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { CommonFindController, FindStartFocusAction, IFindStartOptions, NextMatchFindAction, StartFindAction, NextSelectionMatchFindAction } from 'vs/editor/contrib/find/findController';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { CommonFindController, FindStartFocusAction, IFindStartOptions, NextMatchFindAction, NextSelectionMatchFindAction, StartFindAction, StartFindReplaceAction } from 'vs/editor/contrib/find/findController';
|
||||
import { CONTEXT_FIND_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
|
||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class TestFindController extends CommonFindController {
|
||||
|
||||
public hasFocus: boolean;
|
||||
public delayUpdateHistory: boolean = false;
|
||||
public delayedUpdateHistoryPromise: TPromise<void>;
|
||||
public delayedUpdateHistoryPromise: Promise<void>;
|
||||
|
||||
private _findInputFocused: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@@ -33,6 +35,7 @@ export class TestFindController extends CommonFindController {
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(editor, contextKeyService, storageService, clipboardService);
|
||||
this._findInputFocused = CONTEXT_FIND_INPUT_FOCUSED.bindTo(contextKeyService);
|
||||
this._updateHistoryDelayer = new Delayer<void>(50);
|
||||
}
|
||||
|
||||
@@ -42,6 +45,9 @@ export class TestFindController extends CommonFindController {
|
||||
if (opts.shouldFocus !== FindStartFocusAction.NoFocusChange) {
|
||||
this.hasFocus = true;
|
||||
}
|
||||
|
||||
let inputFocused = opts.shouldFocus === FindStartFocusAction.FocusFindInput;
|
||||
this._findInputFocused.set(inputFocused);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +60,14 @@ suite('FindController', () => {
|
||||
let clipboardState = '';
|
||||
let serviceCollection = new ServiceCollection();
|
||||
serviceCollection.set(IStorageService, {
|
||||
_serviceBrand: undefined,
|
||||
onDidChangeStorage: Event.None,
|
||||
onWillSaveState: Event.None,
|
||||
get: (key: string) => queryState[key],
|
||||
getBoolean: (key: string) => !!queryState[key],
|
||||
store: (key: string, value: any) => { queryState[key] = value; }
|
||||
getInteger: (key: string) => undefined,
|
||||
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
|
||||
remove: (key) => void 0
|
||||
} as IStorageService);
|
||||
|
||||
if (platform.isMacintosh) {
|
||||
@@ -248,6 +259,34 @@ suite('FindController', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #41027: Don\'t replace find input value on replace action if find input is active', () => {
|
||||
withTestCodeEditor([
|
||||
'test',
|
||||
], { serviceCollection: serviceCollection }, (editor, cursor) => {
|
||||
let testRegexString = 'tes.';
|
||||
let findController = editor.registerAndInstantiateContribution<TestFindController>(TestFindController);
|
||||
let nextMatchFindAction = new NextMatchFindAction();
|
||||
let startFindReplaceAction = new StartFindReplaceAction();
|
||||
|
||||
findController.toggleRegex();
|
||||
findController.setSearchString(testRegexString);
|
||||
findController.start({
|
||||
forceRevealReplace: false,
|
||||
seedSearchStringFromSelection: false,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
});
|
||||
nextMatchFindAction.run(null, editor);
|
||||
startFindReplaceAction.run(null, editor);
|
||||
|
||||
assert.equal(findController.getState().searchString, testRegexString);
|
||||
|
||||
findController.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #9043: Clear search scope when find widget is hidden', () => {
|
||||
withTestCodeEditor([
|
||||
'var x = (3 * 5)',
|
||||
@@ -261,7 +300,8 @@ suite('FindController', () => {
|
||||
seedSearchStringFromSelection: false,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: false
|
||||
});
|
||||
|
||||
assert.equal(findController.getState().searchScope, null);
|
||||
@@ -395,9 +435,14 @@ suite('FindController query options persistence', () => {
|
||||
queryState['editor.wholeWord'] = false;
|
||||
let serviceCollection = new ServiceCollection();
|
||||
serviceCollection.set(IStorageService, {
|
||||
_serviceBrand: undefined,
|
||||
onDidChangeStorage: Event.None,
|
||||
onWillSaveState: Event.None,
|
||||
get: (key: string) => queryState[key],
|
||||
getBoolean: (key: string) => !!queryState[key],
|
||||
store: (key: string, value: any) => { queryState[key] = value; }
|
||||
getInteger: (key: string) => undefined,
|
||||
store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); },
|
||||
remove: (key) => void 0
|
||||
} as IStorageService);
|
||||
|
||||
test('matchCase', () => {
|
||||
@@ -468,4 +513,73 @@ suite('FindController query options persistence', () => {
|
||||
findController.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #27083: Update search scope once find widget becomes visible', () => {
|
||||
withTestCodeEditor([
|
||||
'var x = (3 * 5)',
|
||||
'var y = (3 * 5)',
|
||||
'var z = (3 * 5)',
|
||||
], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => {
|
||||
// clipboardState = '';
|
||||
editor.setSelection(new Range(1, 1, 2, 1));
|
||||
let findController = editor.registerAndInstantiateContribution<TestFindController>(TestFindController);
|
||||
|
||||
findController.start({
|
||||
forceRevealReplace: false,
|
||||
seedSearchStringFromSelection: false,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 1, 2, 1));
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #58604: Do not update searchScope if it is empty', () => {
|
||||
withTestCodeEditor([
|
||||
'var x = (3 * 5)',
|
||||
'var y = (3 * 5)',
|
||||
'var z = (3 * 5)',
|
||||
], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => {
|
||||
// clipboardState = '';
|
||||
editor.setSelection(new Range(1, 2, 1, 2));
|
||||
let findController = editor.registerAndInstantiateContribution<TestFindController>(TestFindController);
|
||||
|
||||
findController.start({
|
||||
forceRevealReplace: false,
|
||||
seedSearchStringFromSelection: false,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, null);
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #58604: Update searchScope if it is not empty', () => {
|
||||
withTestCodeEditor([
|
||||
'var x = (3 * 5)',
|
||||
'var y = (3 * 5)',
|
||||
'var z = (3 * 5)',
|
||||
], { serviceCollection: serviceCollection, find: { autoFindInSelection: true, globalFindClipboard: false } }, (editor, cursor) => {
|
||||
// clipboardState = '';
|
||||
editor.setSelection(new Range(1, 2, 1, 3));
|
||||
let findController = editor.registerAndInstantiateContribution<TestFindController>(TestFindController);
|
||||
|
||||
findController.start({
|
||||
forceRevealReplace: false,
|
||||
seedSearchStringFromSelection: false,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: false,
|
||||
updateSearchScope: true
|
||||
});
|
||||
|
||||
assert.deepEqual(findController.getState().searchScope, new Selection(1, 2, 1, 3));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Cursor } from 'vs/editor/common/controller/cursor';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { FindModelBoundToEditorModel } from 'vs/editor/contrib/find/findModel';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
||||
|
||||
suite('FindModel', () => {
|
||||
|
||||
@@ -2031,4 +2030,22 @@ suite('FindModel', () => {
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
});
|
||||
|
||||
findTest('issue #27083. search scope works even if it is a single line', (editor, cursor) => {
|
||||
let findState = new FindReplaceState();
|
||||
findState.change({ searchString: 'hello', wholeWord: true, searchScope: new Range(7, 1, 8, 1) }, false);
|
||||
let findModel = new FindModelBoundToEditorModel(editor, findState);
|
||||
|
||||
assertFindState(
|
||||
editor,
|
||||
[1, 1, 1, 1],
|
||||
null,
|
||||
[
|
||||
[7, 14, 7, 19]
|
||||
]
|
||||
);
|
||||
|
||||
findModel.dispose();
|
||||
findState.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { parseReplaceString, ReplacePattern, ReplacePiece } from 'vs/editor/contrib/find/replacePattern';
|
||||
import { ReplacePattern, ReplacePiece, parseReplaceString } from 'vs/editor/contrib/find/replacePattern';
|
||||
|
||||
suite('Replace Pattern test', () => {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user