mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-20 20:10:11 -04:00
Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 (#6516)
* Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 * fix tests
This commit is contained in:
@@ -148,12 +148,6 @@ class ExecCommandCopyAction extends ExecCommandAction {
|
||||
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Prevent copying an empty line by accident
|
||||
if (editor.getSelections().length === 1 && editor.getSelection().isEmpty()) {
|
||||
if (editor.getModel().getLineFirstNonWhitespaceColumn(editor.getSelection().positionLineNumber) === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.run(accessor, editor);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import 'vs/css!./media/outlineTree';
|
||||
import 'vs/css!./media/symbol-icons';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes';
|
||||
import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -38,7 +38,7 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP
|
||||
|
||||
|
||||
export class OutlineIdentityProvider implements IIdentityProvider<OutlineItem> {
|
||||
getId(element: TreeElement): { toString(): string; } {
|
||||
getId(element: OutlineItem): { toString(): string; } {
|
||||
return element.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,8 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
searchScope: null,
|
||||
matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false),
|
||||
wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false),
|
||||
isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false)
|
||||
isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false),
|
||||
preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false)
|
||||
}, false);
|
||||
|
||||
if (shouldRestartFind) {
|
||||
@@ -170,13 +171,17 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
if (e.matchCase) {
|
||||
this._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE);
|
||||
}
|
||||
if (e.preserveCase) {
|
||||
this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private loadQueryState() {
|
||||
this._state.change({
|
||||
matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase),
|
||||
wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord),
|
||||
isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex)
|
||||
isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex),
|
||||
preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase)
|
||||
}, false);
|
||||
}
|
||||
|
||||
@@ -217,6 +222,11 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
||||
}
|
||||
}
|
||||
|
||||
public togglePreserveCase(): void {
|
||||
this._state.change({ preserveCase: !this._state.preserveCase }, false);
|
||||
this.highlightFindOptions();
|
||||
}
|
||||
|
||||
public toggleSearchScope(): void {
|
||||
if (this._state.searchScope) {
|
||||
this._state.change({ searchScope: null }, true);
|
||||
|
||||
@@ -59,6 +59,7 @@ export const FIND_IDS = {
|
||||
ToggleWholeWordCommand: 'toggleFindWholeWord',
|
||||
ToggleRegexCommand: 'toggleFindRegex',
|
||||
ToggleSearchScopeCommand: 'toggleFindInSelection',
|
||||
TogglePreserveCaseCommand: 'togglePreserveCase',
|
||||
ReplaceOneAction: 'editor.action.replaceOne',
|
||||
ReplaceAllAction: 'editor.action.replaceAll',
|
||||
SelectAllMatchesAction: 'editor.action.selectAllMatches'
|
||||
@@ -416,11 +417,11 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
let replacePattern = this._getReplacePattern();
|
||||
let selection = this._editor.getSelection();
|
||||
let nextMatch = this._getNextMatch(selection.getStartPosition(), replacePattern.hasReplacementPatterns, false);
|
||||
let nextMatch = this._getNextMatch(selection.getStartPosition(), true, false);
|
||||
if (nextMatch) {
|
||||
if (selection.equalsRange(nextMatch.range)) {
|
||||
// selection sits on a find match => replace it!
|
||||
let replaceString = replacePattern.buildReplaceString(nextMatch.matches);
|
||||
let replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase);
|
||||
|
||||
let command = new ReplaceCommand(selection, replaceString);
|
||||
|
||||
@@ -482,12 +483,14 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
const replacePattern = this._getReplacePattern();
|
||||
let resultText: string;
|
||||
const preserveCase = this._state.preserveCase;
|
||||
|
||||
if (replacePattern.hasReplacementPatterns) {
|
||||
resultText = modelText.replace(searchRegex, function () {
|
||||
return replacePattern.buildReplaceString(<string[]><any>arguments);
|
||||
return replacePattern.buildReplaceString(<string[]><any>arguments, preserveCase);
|
||||
});
|
||||
} else {
|
||||
resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null));
|
||||
resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase));
|
||||
}
|
||||
|
||||
let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection());
|
||||
@@ -501,7 +504,7 @@ export class FindModelBoundToEditorModel {
|
||||
|
||||
let replaceStrings: string[] = [];
|
||||
for (let i = 0, len = matches.length; i < len; i++) {
|
||||
replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches);
|
||||
replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase);
|
||||
}
|
||||
|
||||
let command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings);
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface FindReplaceStateChangedEvent {
|
||||
isRegex: boolean;
|
||||
wholeWord: boolean;
|
||||
matchCase: boolean;
|
||||
preserveCase: boolean;
|
||||
searchScope: boolean;
|
||||
matchesPosition: boolean;
|
||||
matchesCount: boolean;
|
||||
@@ -41,6 +42,8 @@ export interface INewFindReplaceState {
|
||||
wholeWordOverride?: FindOptionOverride;
|
||||
matchCase?: boolean;
|
||||
matchCaseOverride?: FindOptionOverride;
|
||||
preserveCase?: boolean;
|
||||
preserveCaseOverride?: FindOptionOverride;
|
||||
searchScope?: Range | null;
|
||||
}
|
||||
|
||||
@@ -65,6 +68,8 @@ export class FindReplaceState implements IDisposable {
|
||||
private _wholeWordOverride: FindOptionOverride;
|
||||
private _matchCase: boolean;
|
||||
private _matchCaseOverride: FindOptionOverride;
|
||||
private _preserveCase: boolean;
|
||||
private _preserveCaseOverride: FindOptionOverride;
|
||||
private _searchScope: Range | null;
|
||||
private _matchesPosition: number;
|
||||
private _matchesCount: number;
|
||||
@@ -78,10 +83,12 @@ export class FindReplaceState implements IDisposable {
|
||||
public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); }
|
||||
public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); }
|
||||
public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); }
|
||||
public get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); }
|
||||
|
||||
public get actualIsRegex(): boolean { return this._isRegex; }
|
||||
public get actualWholeWord(): boolean { return this._wholeWord; }
|
||||
public get actualMatchCase(): boolean { return this._matchCase; }
|
||||
public get actualPreserveCase(): boolean { return this._preserveCase; }
|
||||
|
||||
public get searchScope(): Range | null { return this._searchScope; }
|
||||
public get matchesPosition(): number { return this._matchesPosition; }
|
||||
@@ -100,6 +107,8 @@ export class FindReplaceState implements IDisposable {
|
||||
this._wholeWordOverride = FindOptionOverride.NotSet;
|
||||
this._matchCase = false;
|
||||
this._matchCaseOverride = FindOptionOverride.NotSet;
|
||||
this._preserveCase = false;
|
||||
this._preserveCaseOverride = FindOptionOverride.NotSet;
|
||||
this._searchScope = null;
|
||||
this._matchesPosition = 0;
|
||||
this._matchesCount = 0;
|
||||
@@ -120,6 +129,7 @@ export class FindReplaceState implements IDisposable {
|
||||
isRegex: false,
|
||||
wholeWord: false,
|
||||
matchCase: false,
|
||||
preserveCase: false,
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
@@ -169,6 +179,7 @@ export class FindReplaceState implements IDisposable {
|
||||
isRegex: false,
|
||||
wholeWord: false,
|
||||
matchCase: false,
|
||||
preserveCase: false,
|
||||
searchScope: false,
|
||||
matchesPosition: false,
|
||||
matchesCount: false,
|
||||
@@ -179,6 +190,7 @@ export class FindReplaceState implements IDisposable {
|
||||
const oldEffectiveIsRegex = this.isRegex;
|
||||
const oldEffectiveWholeWords = this.wholeWord;
|
||||
const oldEffectiveMatchCase = this.matchCase;
|
||||
const oldEffectivePreserveCase = this.preserveCase;
|
||||
|
||||
if (typeof newState.searchString !== 'undefined') {
|
||||
if (this._searchString !== newState.searchString) {
|
||||
@@ -217,6 +229,9 @@ export class FindReplaceState implements IDisposable {
|
||||
if (typeof newState.matchCase !== 'undefined') {
|
||||
this._matchCase = newState.matchCase;
|
||||
}
|
||||
if (typeof newState.preserveCase !== 'undefined') {
|
||||
this._preserveCase = newState.preserveCase;
|
||||
}
|
||||
if (typeof newState.searchScope !== 'undefined') {
|
||||
if (!Range.equalsRange(this._searchScope, newState.searchScope)) {
|
||||
this._searchScope = newState.searchScope;
|
||||
@@ -229,6 +244,7 @@ export class FindReplaceState implements IDisposable {
|
||||
this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet);
|
||||
this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet);
|
||||
this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet);
|
||||
this._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet);
|
||||
|
||||
if (oldEffectiveIsRegex !== this.isRegex) {
|
||||
somethingChanged = true;
|
||||
@@ -243,6 +259,11 @@ export class FindReplaceState implements IDisposable {
|
||||
changeEvent.matchCase = true;
|
||||
}
|
||||
|
||||
if (oldEffectivePreserveCase !== this.preserveCase) {
|
||||
somethingChanged = true;
|
||||
changeEvent.preserveCase = true;
|
||||
}
|
||||
|
||||
if (somethingChanged) {
|
||||
this._onFindReplaceStateChange.fire(changeEvent);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
transition: top 200ms linear;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget.hiddenEditor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Find widget when replace is toggled on */
|
||||
.monaco-editor .find-widget.replaceToggled {
|
||||
top: -74px; /* find input height + replace input height + shadow (10px) */
|
||||
@@ -79,6 +84,15 @@
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input {
|
||||
width: 100% !important;
|
||||
padding-right: 66px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input {
|
||||
padding-right: 22px;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input,
|
||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input {
|
||||
padding-top: 2px;
|
||||
@@ -224,12 +238,19 @@
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part > .replace-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
vertical-align: middle;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.monaco-editor .find-widget > .replace-part > .replace-input > .controls {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
/* REDUCED */
|
||||
.monaco-editor .find-widget.reduced-find-widget .matchesCount,
|
||||
.monaco-editor .find-widget.reduced-find-widget .monaco-checkbox {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findIn
|
||||
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 { 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';
|
||||
@@ -47,6 +48,7 @@ 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");
|
||||
@@ -101,6 +103,7 @@ 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;
|
||||
|
||||
@@ -590,14 +593,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
};
|
||||
this._findInput.style(inputStyles);
|
||||
this._replaceInputBox.style(inputStyles);
|
||||
this._preserveCase.style(inputStyles);
|
||||
}
|
||||
|
||||
private _tryUpdateWidgetWidth() {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width;
|
||||
let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth;
|
||||
|
||||
const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth;
|
||||
|
||||
if (editorContentWidth <= 0) {
|
||||
// for example, diff view original editor
|
||||
dom.addClass(this._domNode, 'hiddenEditor');
|
||||
return;
|
||||
} else if (dom.hasClass(this._domNode, 'hiddenEditor')) {
|
||||
dom.removeClass(this._domNode, 'hiddenEditor');
|
||||
}
|
||||
|
||||
const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width;
|
||||
const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth;
|
||||
let collapsedFindWidget = false;
|
||||
let reducedFindWidget = false;
|
||||
let narrowFindWidget = false;
|
||||
@@ -913,6 +928,19 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
||||
this._state.change({ replaceString: this._replaceInputBox.value }, false);
|
||||
}));
|
||||
|
||||
this._preserveCase = this._register(new Checkbox({
|
||||
actionClassName: 'monaco-case-sensitive',
|
||||
title: NLS_PRESERVE_CASE_LABEL,
|
||||
isChecked: false,
|
||||
}));
|
||||
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();
|
||||
}
|
||||
}));
|
||||
|
||||
// Replace one button
|
||||
this._replaceBtn = this._register(new SimpleButton({
|
||||
label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction),
|
||||
@@ -937,6 +965,12 @@ 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);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { containsUppercaseCharacter } from 'vs/base/common/strings';
|
||||
|
||||
const enum ReplacePatternKind {
|
||||
StaticValue = 0,
|
||||
@@ -48,9 +49,22 @@ export class ReplacePattern {
|
||||
}
|
||||
}
|
||||
|
||||
public buildReplaceString(matches: string[] | null): string {
|
||||
public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string {
|
||||
if (this._state.kind === ReplacePatternKind.StaticValue) {
|
||||
return this._state.staticValue;
|
||||
if (preserveCase && matches && (matches[0] !== '')) {
|
||||
if (matches[0].toUpperCase() === matches[0]) {
|
||||
return this._state.staticValue.toUpperCase();
|
||||
} else if (matches[0].toLowerCase() === matches[0]) {
|
||||
return this._state.staticValue.toLowerCase();
|
||||
} else if (containsUppercaseCharacter(matches[0][0])) {
|
||||
return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1);
|
||||
} else {
|
||||
// we don't understand its pattern yet.
|
||||
return this._state.staticValue;
|
||||
}
|
||||
} else {
|
||||
return this._state.staticValue;
|
||||
}
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
@@ -41,7 +41,8 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
private readonly _state: FindReplaceState = new FindReplaceState(),
|
||||
showOptionButtons?: boolean
|
||||
showOptionButtons?: boolean,
|
||||
private readonly _invertDefaultDirection: boolean = false
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -93,13 +94,13 @@ export abstract class SimpleFindWidget extends Widget {
|
||||
|
||||
this._register(this._findInput.onKeyDown((e) => {
|
||||
if (e.equals(KeyCode.Enter)) {
|
||||
this.find(false);
|
||||
this.find(this._invertDefaultDirection);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
|
||||
this.find(true);
|
||||
this.find(!this._invertDefaultDirection);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
@@ -295,4 +296,4 @@ registerThemingParticipant((theme, collector) => {
|
||||
if (widgetShadowColor) {
|
||||
collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,4 +153,26 @@ suite('Replace Pattern test', () => {
|
||||
let actual = replacePattern.buildReplaceString(matches);
|
||||
assert.equal(actual, 'a{}');
|
||||
});
|
||||
|
||||
test('preserve case', () => {
|
||||
let replacePattern = parseReplaceString('Def');
|
||||
let actual = replacePattern.buildReplaceString(['abc'], true);
|
||||
assert.equal(actual, 'def');
|
||||
actual = replacePattern.buildReplaceString(['Abc'], true);
|
||||
assert.equal(actual, 'Def');
|
||||
actual = replacePattern.buildReplaceString(['ABC'], true);
|
||||
assert.equal(actual, 'DEF');
|
||||
|
||||
actual = replacePattern.buildReplaceString(['abc', 'Abc'], true);
|
||||
assert.equal(actual, 'def');
|
||||
actual = replacePattern.buildReplaceString(['Abc', 'abc'], true);
|
||||
assert.equal(actual, 'Def');
|
||||
actual = replacePattern.buildReplaceString(['ABC', 'abc'], true);
|
||||
assert.equal(actual, 'DEF');
|
||||
|
||||
actual = replacePattern.buildReplaceString(['AbC'], true);
|
||||
assert.equal(actual, 'Def');
|
||||
actual = replacePattern.buildReplaceString(['aBC'], true);
|
||||
assert.equal(actual, 'Def');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -589,13 +589,13 @@ export class AutoIndentOnPaste implements IEditorContribution {
|
||||
|
||||
private shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean {
|
||||
model.forceTokenization(lineNumber);
|
||||
let nonWhiteSpaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);
|
||||
if (nonWhiteSpaceColumn === 0) {
|
||||
let nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);
|
||||
if (nonWhitespaceColumn === 0) {
|
||||
return true;
|
||||
}
|
||||
let tokens = model.getLineTokens(lineNumber);
|
||||
if (tokens.getCount() > 0) {
|
||||
let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhiteSpaceColumn);
|
||||
let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn);
|
||||
if (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,17 @@ export class CommitCharacterController {
|
||||
|
||||
private _onItem(selected: ISelectedSuggestion | undefined): void {
|
||||
if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) {
|
||||
// no item or no commit characters
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._active && this._active.item.item === selected.item) {
|
||||
// still the same item
|
||||
return;
|
||||
}
|
||||
|
||||
// keep item and its commit characters
|
||||
const acceptCharacters = new CharacterSet();
|
||||
for (const ch of selected.item.completion.commitCharacters) {
|
||||
if (ch.length > 0) {
|
||||
|
||||
@@ -50,7 +50,7 @@ interface ISuggestionTemplateData {
|
||||
iconLabel: IconLabel;
|
||||
typeLabel: HTMLElement;
|
||||
readMore: HTMLElement;
|
||||
disposables: IDisposable[];
|
||||
disposables: DisposableStore;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,8 +106,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
|
||||
renderTemplate(container: HTMLElement): ISuggestionTemplateData {
|
||||
const data = <ISuggestionTemplateData>Object.create(null);
|
||||
const disposables = new DisposableStore();
|
||||
data.disposables = [disposables];
|
||||
data.disposables = new DisposableStore();
|
||||
|
||||
data.root = container;
|
||||
addClass(data.root, 'show-file-icons');
|
||||
@@ -119,7 +118,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
const main = append(text, $('.main'));
|
||||
|
||||
data.iconLabel = new IconLabel(main, { supportHighlights: true });
|
||||
disposables.add(data.iconLabel);
|
||||
data.disposables.add(data.iconLabel);
|
||||
|
||||
data.typeLabel = append(main, $('span.type-label'));
|
||||
|
||||
@@ -147,7 +146,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
|
||||
configureFont();
|
||||
|
||||
disposables.add(Event.chain<IConfigurationChangedEvent>(this.editor.onDidChangeConfiguration.bind(this.editor))
|
||||
data.disposables.add(Event.chain<IConfigurationChangedEvent>(this.editor.onDidChangeConfiguration.bind(this.editor))
|
||||
.filter(e => e.fontInfo || e.contribInfo)
|
||||
.on(configureFont, null));
|
||||
|
||||
@@ -218,7 +217,7 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISuggestionTemplateData): void {
|
||||
templateData.disposables = dispose(templateData.disposables);
|
||||
templateData.disposables.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +252,7 @@ class SuggestionDetails {
|
||||
private type: HTMLElement;
|
||||
private docs: HTMLElement;
|
||||
private ariaLabel: string | null;
|
||||
private disposables: IDisposable[];
|
||||
private readonly disposables: DisposableStore;
|
||||
private renderDisposeable: IDisposable;
|
||||
private borderWidth: number = 1;
|
||||
|
||||
@@ -264,16 +263,16 @@ class SuggestionDetails {
|
||||
private readonly markdownRenderer: MarkdownRenderer,
|
||||
private readonly triggerKeybindingLabel: string,
|
||||
) {
|
||||
this.disposables = [];
|
||||
this.disposables = new DisposableStore();
|
||||
|
||||
this.el = append(container, $('.details'));
|
||||
this.disposables.push(toDisposable(() => container.removeChild(this.el)));
|
||||
this.disposables.add(toDisposable(() => container.removeChild(this.el)));
|
||||
|
||||
this.body = $('.body');
|
||||
|
||||
this.scrollbar = new DomScrollableElement(this.body, {});
|
||||
append(this.el, this.scrollbar.getDomNode());
|
||||
this.disposables.push(this.scrollbar);
|
||||
this.disposables.add(this.scrollbar);
|
||||
|
||||
this.header = append(this.body, $('.header'));
|
||||
this.close = append(this.header, $('span.close'));
|
||||
@@ -414,7 +413,7 @@ class SuggestionDetails {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.disposables.dispose();
|
||||
this.renderDisposeable = dispose(this.renderDisposeable);
|
||||
}
|
||||
}
|
||||
@@ -672,7 +671,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
});
|
||||
|
||||
this.currentSuggestionDetails.then(() => {
|
||||
if (this.list.length < index) {
|
||||
if (index >= this.list.length || item !== this.list.element(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -689,11 +688,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
}
|
||||
|
||||
this._ariaAlert(this._getSuggestionAriaAlertLabel(item));
|
||||
}).catch(onUnexpectedError).then(() => {
|
||||
if (this.focusedItem === item) {
|
||||
this.currentSuggestionDetails = null;
|
||||
}
|
||||
});
|
||||
}).catch(onUnexpectedError);
|
||||
}
|
||||
|
||||
// emit an event
|
||||
@@ -810,12 +805,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
"suggestWidget" : {
|
||||
"wasAutomaticallyTriggered" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
|
||||
"${include}": [
|
||||
"${ICompletionStats}",
|
||||
"${EditorTelemetryData}"
|
||||
"${ICompletionStats}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('suggestWidget', { ...stats, ...this.editor.getTelemetryData() });
|
||||
this.telemetryService.publicLog('suggestWidget', { ...stats });
|
||||
}
|
||||
|
||||
this.focusedItem = null;
|
||||
@@ -949,14 +943,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.details.element.style.borderColor = this.detailsFocusBorderColor;
|
||||
}
|
||||
}
|
||||
/* __GDPR__
|
||||
"suggestWidget:toggleDetailsFocus" : {
|
||||
"${include}": [
|
||||
"${EditorTelemetryData}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('suggestWidget:toggleDetailsFocus', this.editor.getTelemetryData());
|
||||
this.telemetryService.publicLog2('suggestWidget:toggleDetailsFocus');
|
||||
}
|
||||
|
||||
toggleDetails(): void {
|
||||
@@ -970,14 +957,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
removeClass(this.element, 'docs-side');
|
||||
removeClass(this.element, 'docs-below');
|
||||
this.editor.layoutContentWidget(this);
|
||||
/* __GDPR__
|
||||
"suggestWidget:collapseDetails" : {
|
||||
"${include}": [
|
||||
"${EditorTelemetryData}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('suggestWidget:collapseDetails', this.editor.getTelemetryData());
|
||||
this.telemetryService.publicLog2('suggestWidget:collapseDetails');
|
||||
} else {
|
||||
if (this.state !== State.Open && this.state !== State.Details && this.state !== State.Frozen) {
|
||||
return;
|
||||
@@ -986,14 +966,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate<Compl
|
||||
this.updateExpandDocsSetting(true);
|
||||
this.showDetails(false);
|
||||
this._ariaAlert(this.details.getAriaLabel());
|
||||
/* __GDPR__
|
||||
"suggestWidget:expandDetails" : {
|
||||
"${include}": [
|
||||
"${EditorTelemetryData}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('suggestWidget:expandDetails', this.editor.getTelemetryData());
|
||||
this.telemetryService.publicLog2('suggestWidget:expandDetails');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,22 @@ suite('WordOperations', () => {
|
||||
assert.deepEqual(actual, EXPECTED);
|
||||
});
|
||||
|
||||
test('cursorWordLeftSelect - issue #74369: cursorWordLeft and cursorWordLeftSelect do not behave consistently', () => {
|
||||
const EXPECTED = [
|
||||
'|this.|is.|a.|test',
|
||||
].join('\n');
|
||||
const [text,] = deserializePipePositions(EXPECTED);
|
||||
const actualStops = testRepeatedActionAndExtractPositions(
|
||||
text,
|
||||
new Position(1, 15),
|
||||
ed => cursorWordLeft(ed, true),
|
||||
ed => ed.getPosition()!,
|
||||
ed => ed.getPosition()!.equals(new Position(1, 1))
|
||||
);
|
||||
const actual = serializePipePositions(text, actualStops);
|
||||
assert.deepEqual(actual, EXPECTED);
|
||||
});
|
||||
|
||||
test('cursorWordStartLeft', () => {
|
||||
// This is the behaviour observed in Visual Studio, please do not touch test
|
||||
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n');
|
||||
|
||||
@@ -163,7 +163,7 @@ export class CursorWordLeftSelect extends WordLeftCommand {
|
||||
constructor() {
|
||||
super({
|
||||
inSelectionMode: true,
|
||||
wordNavigationType: WordNavigationType.WordStart,
|
||||
wordNavigationType: WordNavigationType.WordStartFast,
|
||||
id: 'cursorWordLeftSelect',
|
||||
precondition: undefined
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user