mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 (#6516)
* Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 * fix tests
This commit is contained in:
@@ -696,7 +696,7 @@ const editorConfiguration: IConfigurationNode = {
|
||||
},
|
||||
'editor.suggest.filteredTypes': {
|
||||
type: 'object',
|
||||
default: { keyword: true },
|
||||
default: { keyword: true, snippet: true },
|
||||
markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."),
|
||||
properties: {
|
||||
method: {
|
||||
@@ -904,7 +904,7 @@ const editorConfiguration: IConfigurationNode = {
|
||||
'enum': ['none', 'boundary', 'selection', 'all'],
|
||||
'enumDescriptions': [
|
||||
'',
|
||||
nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."),
|
||||
nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."),
|
||||
nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."),
|
||||
''
|
||||
],
|
||||
|
||||
@@ -10,15 +10,16 @@ import { CursorCollection } from 'vs/editor/common/controller/cursorCollection';
|
||||
import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon';
|
||||
import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';
|
||||
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';
|
||||
import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean {
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
@@ -83,6 +84,64 @@ export class CursorModelState {
|
||||
}
|
||||
}
|
||||
|
||||
class AutoClosedAction {
|
||||
|
||||
private readonly _model: ITextModel;
|
||||
|
||||
private _autoClosedCharactersDecorations: string[];
|
||||
private _autoClosedEnclosingDecorations: string[];
|
||||
|
||||
constructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) {
|
||||
this._model = model;
|
||||
this._autoClosedCharactersDecorations = autoClosedCharactersDecorations;
|
||||
this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []);
|
||||
this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []);
|
||||
}
|
||||
|
||||
public getAutoClosedCharactersRanges(): Range[] {
|
||||
let result: Range[] = [];
|
||||
for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) {
|
||||
const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]);
|
||||
if (decorationRange) {
|
||||
result.push(decorationRange);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public isValid(selections: Range[]): boolean {
|
||||
let enclosingRanges: Range[] = [];
|
||||
for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) {
|
||||
const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]);
|
||||
if (decorationRange) {
|
||||
enclosingRanges.push(decorationRange);
|
||||
if (decorationRange.startLineNumber !== decorationRange.endLineNumber) {
|
||||
// Stop tracking if the range becomes multiline...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
enclosingRanges.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
selections.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
for (let i = 0; i < selections.length; i++) {
|
||||
if (i >= enclosingRanges.length) {
|
||||
return false;
|
||||
}
|
||||
if (!enclosingRanges[i].strictContainsRange(selections[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
|
||||
public static MAX_CURSOR_COUNT = 10000;
|
||||
@@ -106,6 +165,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
private _isHandling: boolean;
|
||||
private _isDoingComposition: boolean;
|
||||
private _columnSelectData: IColumnSelectData | null;
|
||||
private _autoClosedActions: AutoClosedAction[];
|
||||
private _prevEditOperationType: EditOperationType;
|
||||
|
||||
constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) {
|
||||
@@ -120,6 +180,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
this._isHandling = false;
|
||||
this._isDoingComposition = false;
|
||||
this._columnSelectData = null;
|
||||
this._autoClosedActions = [];
|
||||
this._prevEditOperationType = EditOperationType.Other;
|
||||
|
||||
this._register(this._model.onDidChangeRawContent((e) => {
|
||||
@@ -173,9 +234,24 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
|
||||
public dispose(): void {
|
||||
this._cursors.dispose();
|
||||
this._autoClosedActions = dispose(this._autoClosedActions);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _validateAutoClosedActions(): void {
|
||||
if (this._autoClosedActions.length > 0) {
|
||||
let selections: Range[] = this._cursors.getSelections();
|
||||
for (let i = 0; i < this._autoClosedActions.length; i++) {
|
||||
const autoClosedAction = this._autoClosedActions[i];
|
||||
if (!autoClosedAction.isValid(selections)) {
|
||||
autoClosedAction.dispose();
|
||||
this._autoClosedActions.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------ some getters/setters
|
||||
|
||||
public getPrimaryCursor(): CursorState {
|
||||
@@ -202,6 +278,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
this._cursors.normalize();
|
||||
this._columnSelectData = null;
|
||||
|
||||
this._validateAutoClosedActions();
|
||||
|
||||
this._emitStateChangedIfNecessary(source, reason, oldState);
|
||||
}
|
||||
|
||||
@@ -296,7 +374,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
// a model.setValue() was called
|
||||
this._cursors.dispose();
|
||||
this._cursors = new CursorCollection(this.context);
|
||||
|
||||
this._validateAutoClosedActions();
|
||||
this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null);
|
||||
} else {
|
||||
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
|
||||
@@ -367,6 +445,35 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
// The commands were applied correctly
|
||||
this._interpretCommandResult(result);
|
||||
|
||||
// Check for auto-closing closed characters
|
||||
let autoClosedCharactersRanges: IModelDeltaDecoration[] = [];
|
||||
let autoClosedEnclosingRanges: IModelDeltaDecoration[] = [];
|
||||
|
||||
for (let i = 0; i < opResult.commands.length; i++) {
|
||||
const command = opResult.commands[i];
|
||||
if (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) {
|
||||
autoClosedCharactersRanges.push({
|
||||
range: command.closeCharacterRange,
|
||||
options: {
|
||||
inlineClassName: 'auto-closed-character',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
}
|
||||
});
|
||||
autoClosedEnclosingRanges.push({
|
||||
range: command.enclosingRange,
|
||||
options: {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (autoClosedCharactersRanges.length > 0) {
|
||||
const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersRanges);
|
||||
const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingRanges);
|
||||
this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations));
|
||||
}
|
||||
|
||||
this._prevEditOperationType = opResult.type;
|
||||
}
|
||||
|
||||
@@ -540,6 +647,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
this._cursors.startTrackingSelections();
|
||||
}
|
||||
|
||||
this._validateAutoClosedActions();
|
||||
|
||||
if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) {
|
||||
this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);
|
||||
}
|
||||
@@ -566,8 +675,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
|
||||
chr = text.charAt(i);
|
||||
}
|
||||
|
||||
let autoClosedCharacters: Range[] = [];
|
||||
if (this._autoClosedActions.length > 0) {
|
||||
for (let i = 0, len = this._autoClosedActions.length; i < len; i++) {
|
||||
autoClosedCharacters = autoClosedCharacters.concat(this._autoClosedActions[i].getAutoClosedCharactersRanges());
|
||||
}
|
||||
}
|
||||
|
||||
// Here we must interpret each typed character individually, that's why we create a new context
|
||||
this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr));
|
||||
this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationT
|
||||
import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ICommand } from 'vs/editor/common/editorCommon';
|
||||
import { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { EnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
@@ -430,7 +430,7 @@ export class TypeOperations {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean {
|
||||
private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean {
|
||||
const autoCloseConfig = isQuote(ch) ? config.autoClosingQuotes : config.autoClosingBrackets;
|
||||
|
||||
if (autoCloseConfig === 'never' || !config.autoClosingPairsClose.hasOwnProperty(ch)) {
|
||||
@@ -461,6 +461,19 @@ export class TypeOperations {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Must over-type a closing character typed by the editor
|
||||
let found = false;
|
||||
for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) {
|
||||
const autoClosedCharacter = autoClosedCharacters[j];
|
||||
if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -573,7 +586,7 @@ export class TypeOperations {
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
const selection = selections[i];
|
||||
const closeCharacter = config.autoClosingPairsOpen[ch];
|
||||
commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length);
|
||||
commands[i] = new TypeWithAutoClosingCommand(selection, ch, closeCharacter);
|
||||
}
|
||||
return new EditOperationResult(EditOperationType.Typing, commands, {
|
||||
shouldPushStackElementBefore: true,
|
||||
@@ -802,7 +815,7 @@ export class TypeOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult {
|
||||
public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult {
|
||||
|
||||
if (ch === '\n') {
|
||||
let commands: ICommand[] = [];
|
||||
@@ -833,7 +846,7 @@ export class TypeOperations {
|
||||
}
|
||||
}
|
||||
|
||||
if (this._isAutoClosingCloseCharType(config, model, selections, ch)) {
|
||||
if (this._isAutoClosingCloseCharType(config, model, selections, autoClosedCharacters, ch)) {
|
||||
return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch);
|
||||
}
|
||||
|
||||
@@ -923,3 +936,24 @@ export class TypeOperations {
|
||||
return commands;
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState {
|
||||
|
||||
private _closeCharacter: string;
|
||||
public closeCharacterRange: Range | null;
|
||||
public enclosingRange: Range | null;
|
||||
|
||||
constructor(selection: Selection, openCharacter: string, closeCharacter: string) {
|
||||
super(selection, openCharacter + closeCharacter, 0, -closeCharacter.length);
|
||||
this._closeCharacter = closeCharacter;
|
||||
this.closeCharacterRange = null;
|
||||
}
|
||||
|
||||
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
|
||||
let inverseEditOperations = helper.getInverseEditOperations();
|
||||
let range = inverseEditOperations[0].range;
|
||||
this.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn);
|
||||
this.enclosingRange = range;
|
||||
return super.computeCursorState(model, helper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,32 @@ export class Range {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true.
|
||||
*/
|
||||
public strictContainsRange(range: IRange): boolean {
|
||||
return Range.strictContainsRange(this, range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false.
|
||||
*/
|
||||
public static strictContainsRange(range: IRange, otherRange: IRange): boolean {
|
||||
if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) {
|
||||
return false;
|
||||
}
|
||||
if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reunion of the two ranges.
|
||||
* The smallest position will be used as the start point, and the largest one as the end point.
|
||||
|
||||
@@ -17,7 +17,8 @@ export const enum ClassName {
|
||||
EditorWarningDecoration = 'squiggly-warning',
|
||||
EditorErrorDecoration = 'squiggly-error',
|
||||
EditorUnnecessaryDecoration = 'squiggly-unnecessary',
|
||||
EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary'
|
||||
EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary',
|
||||
EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated'
|
||||
}
|
||||
|
||||
export const enum NodeColor {
|
||||
|
||||
@@ -545,6 +545,12 @@ export class Searcher {
|
||||
const matchStartIndex = m.index;
|
||||
const matchLength = m[0].length;
|
||||
if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) {
|
||||
if (matchLength === 0) {
|
||||
// the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here
|
||||
// we attempt to recover from that by advancing by one
|
||||
this._searchRegex.lastIndex += 1;
|
||||
continue;
|
||||
}
|
||||
// Exit early if the regex matches the same range twice
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -221,6 +221,9 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
|
||||
if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) {
|
||||
inlineClassName = ClassName.EditorUnnecessaryInlineDecoration;
|
||||
}
|
||||
if (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) {
|
||||
inlineClassName = ClassName.EditorDeprecatedInlineDecoration;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
|
||||
export enum MarkerTag {
|
||||
Unnecessary = 1
|
||||
Unnecessary = 1,
|
||||
Deprecated = 2
|
||||
}
|
||||
|
||||
export enum MarkerSeverity {
|
||||
|
||||
Reference in New Issue
Block a user