Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .bracket-match {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./bracketMatching';
|
||||
import * as nls from 'vs/nls';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { editorBracketMatchBackground, editorBracketMatchBorder } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant, themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
const overviewRulerBracketMatchForeground = registerColor('editorOverviewRuler.bracketMatchForeground', { dark: '#A0A0A0', light: '#A0A0A0', hc: '#A0A0A0' }, nls.localize('overviewRulerBracketMatchForeground', 'Overview ruler marker color for matching brackets.'));
|
||||
|
||||
class JumpToBracketAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.jumpToBracket',
|
||||
label: nls.localize('smartSelect.jumpBracket', "Go to Bracket"),
|
||||
alias: 'Go to Bracket',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKSLASH,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
let controller = BracketMatchingController.get(editor);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
controller.jumpToBracket();
|
||||
}
|
||||
}
|
||||
|
||||
class SelectToBracketAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.selectToBracket',
|
||||
label: nls.localize('smartSelect.selectToBracket', "Select to Bracket"),
|
||||
alias: 'Select to Bracket',
|
||||
precondition: undefined,
|
||||
description: {
|
||||
description: `Select to Bracket`,
|
||||
args: [{
|
||||
name: 'args',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'selectBrackets': {
|
||||
type: 'boolean',
|
||||
default: true
|
||||
}
|
||||
},
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
const controller = BracketMatchingController.get(editor);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selectBrackets = true;
|
||||
if (args && args.selectBrackets === false) {
|
||||
selectBrackets = false;
|
||||
}
|
||||
controller.selectToBracket(selectBrackets);
|
||||
}
|
||||
}
|
||||
|
||||
type Brackets = [Range, Range];
|
||||
|
||||
class BracketsData {
|
||||
public readonly position: Position;
|
||||
public readonly brackets: Brackets | null;
|
||||
public readonly options: ModelDecorationOptions;
|
||||
|
||||
constructor(position: Position, brackets: Brackets | null, options: ModelDecorationOptions) {
|
||||
this.position = position;
|
||||
this.brackets = brackets;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
export class BracketMatchingController extends Disposable implements IEditorContribution {
|
||||
public static readonly ID = 'editor.contrib.bracketMatchingController';
|
||||
|
||||
public static get(editor: ICodeEditor): BracketMatchingController {
|
||||
return editor.getContribution<BracketMatchingController>(BracketMatchingController.ID);
|
||||
}
|
||||
|
||||
private readonly _editor: ICodeEditor;
|
||||
|
||||
private _lastBracketsData: BracketsData[];
|
||||
private _lastVersionId: number;
|
||||
private _decorations: string[];
|
||||
private readonly _updateBracketsSoon: RunOnceScheduler;
|
||||
private _matchBrackets: 'never' | 'near' | 'always';
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor
|
||||
) {
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._lastBracketsData = [];
|
||||
this._lastVersionId = 0;
|
||||
this._decorations = [];
|
||||
this._updateBracketsSoon = this._register(new RunOnceScheduler(() => this._updateBrackets(), 50));
|
||||
this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);
|
||||
|
||||
this._updateBracketsSoon.schedule();
|
||||
this._register(editor.onDidChangeCursorPosition((e) => {
|
||||
|
||||
if (this._matchBrackets === 'never') {
|
||||
// Early exit if nothing needs to be done!
|
||||
// Leave some form of early exit check here if you wish to continue being a cursor position change listener ;)
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateBracketsSoon.schedule();
|
||||
}));
|
||||
this._register(editor.onDidChangeModelContent((e) => {
|
||||
this._updateBracketsSoon.schedule();
|
||||
}));
|
||||
this._register(editor.onDidChangeModel((e) => {
|
||||
this._lastBracketsData = [];
|
||||
this._decorations = [];
|
||||
this._updateBracketsSoon.schedule();
|
||||
}));
|
||||
this._register(editor.onDidChangeModelLanguageConfiguration((e) => {
|
||||
this._lastBracketsData = [];
|
||||
this._updateBracketsSoon.schedule();
|
||||
}));
|
||||
this._register(editor.onDidChangeConfiguration((e) => {
|
||||
if (e.hasChanged(EditorOption.matchBrackets)) {
|
||||
this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);
|
||||
this._decorations = this._editor.deltaDecorations(this._decorations, []);
|
||||
this._lastBracketsData = [];
|
||||
this._lastVersionId = 0;
|
||||
this._updateBracketsSoon.schedule();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public jumpToBracket(): void {
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const newSelections = this._editor.getSelections().map(selection => {
|
||||
const position = selection.getStartPosition();
|
||||
|
||||
// find matching brackets if position is on a bracket
|
||||
const brackets = model.matchBracket(position);
|
||||
let newCursorPosition: Position | null = null;
|
||||
if (brackets) {
|
||||
if (brackets[0].containsPosition(position)) {
|
||||
newCursorPosition = brackets[1].getStartPosition();
|
||||
} else if (brackets[1].containsPosition(position)) {
|
||||
newCursorPosition = brackets[0].getStartPosition();
|
||||
}
|
||||
} else {
|
||||
// find the enclosing brackets if the position isn't on a matching bracket
|
||||
const enclosingBrackets = model.findEnclosingBrackets(position);
|
||||
if (enclosingBrackets) {
|
||||
newCursorPosition = enclosingBrackets[0].getStartPosition();
|
||||
} else {
|
||||
// no enclosing brackets, try the very first next bracket
|
||||
const nextBracket = model.findNextBracket(position);
|
||||
if (nextBracket && nextBracket.range) {
|
||||
newCursorPosition = nextBracket.range.getStartPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newCursorPosition) {
|
||||
return new Selection(newCursorPosition.lineNumber, newCursorPosition.column, newCursorPosition.lineNumber, newCursorPosition.column);
|
||||
}
|
||||
return new Selection(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
});
|
||||
|
||||
this._editor.setSelections(newSelections);
|
||||
this._editor.revealRange(newSelections[0]);
|
||||
}
|
||||
|
||||
public selectToBracket(selectBrackets: boolean): void {
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const newSelections: Selection[] = [];
|
||||
|
||||
this._editor.getSelections().forEach(selection => {
|
||||
const position = selection.getStartPosition();
|
||||
let brackets = model.matchBracket(position);
|
||||
|
||||
if (!brackets) {
|
||||
brackets = model.findEnclosingBrackets(position);
|
||||
if (!brackets) {
|
||||
const nextBracket = model.findNextBracket(position);
|
||||
if (nextBracket && nextBracket.range) {
|
||||
brackets = model.matchBracket(nextBracket.range.getStartPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let selectFrom: Position | null = null;
|
||||
let selectTo: Position | null = null;
|
||||
|
||||
if (brackets) {
|
||||
brackets.sort(Range.compareRangesUsingStarts);
|
||||
const [open, close] = brackets;
|
||||
selectFrom = selectBrackets ? open.getStartPosition() : open.getEndPosition();
|
||||
selectTo = selectBrackets ? close.getEndPosition() : close.getStartPosition();
|
||||
}
|
||||
|
||||
if (selectFrom && selectTo) {
|
||||
newSelections.push(new Selection(selectFrom.lineNumber, selectFrom.column, selectTo.lineNumber, selectTo.column));
|
||||
}
|
||||
});
|
||||
|
||||
if (newSelections.length > 0) {
|
||||
this._editor.setSelections(newSelections);
|
||||
this._editor.revealRange(newSelections[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'bracket-match',
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(overviewRulerBracketMatchForeground),
|
||||
position: OverviewRulerLane.Center
|
||||
}
|
||||
});
|
||||
|
||||
private static readonly _DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = ModelDecorationOptions.register({
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'bracket-match'
|
||||
});
|
||||
|
||||
private _updateBrackets(): void {
|
||||
if (this._matchBrackets === 'never') {
|
||||
return;
|
||||
}
|
||||
this._recomputeBrackets();
|
||||
|
||||
let newDecorations: IModelDeltaDecoration[] = [], newDecorationsLen = 0;
|
||||
for (const bracketData of this._lastBracketsData) {
|
||||
let brackets = bracketData.brackets;
|
||||
if (brackets) {
|
||||
newDecorations[newDecorationsLen++] = { range: brackets[0], options: bracketData.options };
|
||||
newDecorations[newDecorationsLen++] = { range: brackets[1], options: bracketData.options };
|
||||
}
|
||||
}
|
||||
|
||||
this._decorations = this._editor.deltaDecorations(this._decorations, newDecorations);
|
||||
}
|
||||
|
||||
private _recomputeBrackets(): void {
|
||||
if (!this._editor.hasModel()) {
|
||||
// no model => no brackets!
|
||||
this._lastBracketsData = [];
|
||||
this._lastVersionId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const selections = this._editor.getSelections();
|
||||
if (selections.length > 100) {
|
||||
// no bracket matching for high numbers of selections
|
||||
this._lastBracketsData = [];
|
||||
this._lastVersionId = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const versionId = model.getVersionId();
|
||||
let previousData: BracketsData[] = [];
|
||||
if (this._lastVersionId === versionId) {
|
||||
// use the previous data only if the model is at the same version id
|
||||
previousData = this._lastBracketsData;
|
||||
}
|
||||
|
||||
let positions: Position[] = [], positionsLen = 0;
|
||||
for (let i = 0, len = selections.length; i < len; i++) {
|
||||
let selection = selections[i];
|
||||
|
||||
if (selection.isEmpty()) {
|
||||
// will bracket match a cursor only if the selection is collapsed
|
||||
positions[positionsLen++] = selection.getStartPosition();
|
||||
}
|
||||
}
|
||||
|
||||
// sort positions for `previousData` cache hits
|
||||
if (positions.length > 1) {
|
||||
positions.sort(Position.compare);
|
||||
}
|
||||
|
||||
let newData: BracketsData[] = [], newDataLen = 0;
|
||||
let previousIndex = 0, previousLen = previousData.length;
|
||||
for (let i = 0, len = positions.length; i < len; i++) {
|
||||
let position = positions[i];
|
||||
|
||||
while (previousIndex < previousLen && previousData[previousIndex].position.isBefore(position)) {
|
||||
previousIndex++;
|
||||
}
|
||||
|
||||
if (previousIndex < previousLen && previousData[previousIndex].position.equals(position)) {
|
||||
newData[newDataLen++] = previousData[previousIndex];
|
||||
} else {
|
||||
let brackets = model.matchBracket(position);
|
||||
let options = BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER;
|
||||
if (!brackets && this._matchBrackets === 'always') {
|
||||
brackets = model.findEnclosingBrackets(position, 20 /* give at most 20ms to compute */);
|
||||
options = BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER;
|
||||
}
|
||||
newData[newDataLen++] = new BracketsData(position, brackets, options);
|
||||
}
|
||||
}
|
||||
|
||||
this._lastBracketsData = newData;
|
||||
this._lastVersionId = versionId;
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
registerEditorAction(SelectToBracketAction);
|
||||
registerEditorAction(JumpToBracketAction);
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const bracketMatchBackground = theme.getColor(editorBracketMatchBackground);
|
||||
if (bracketMatchBackground) {
|
||||
collector.addRule(`.monaco-editor .bracket-match { background-color: ${bracketMatchBackground}; }`);
|
||||
}
|
||||
const bracketMatchBorder = theme.getColor(editorBracketMatchBorder);
|
||||
if (bracketMatchBorder) {
|
||||
collector.addRule(`.monaco-editor .bracket-match { border: 1px solid ${bracketMatchBorder}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
// Go to menu
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '5_infile_nav',
|
||||
command: {
|
||||
id: 'editor.action.jumpToBracket',
|
||||
title: nls.localize({ key: 'miGoToBracket', comment: ['&& denotes a mnemonic'] }, "Go to &&Bracket")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
@@ -0,0 +1,248 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { BracketMatchingController } from 'vs/editor/contrib/bracketMatching/bracketMatching';
|
||||
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
|
||||
|
||||
suite('bracket matching', () => {
|
||||
class BracketMode extends MockMode {
|
||||
|
||||
private static readonly _id = new LanguageIdentifier('bracketMode', 3);
|
||||
|
||||
constructor() {
|
||||
super(BracketMode._id);
|
||||
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')'],
|
||||
]
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
test('issue #183: jump to matching bracket position', () => {
|
||||
let mode = new BracketMode();
|
||||
let model = createTextModel('var x = (3 + (5-7)) + ((5+3)+5);', undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
// start on closing bracket
|
||||
editor.setPosition(new Position(1, 20));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 9));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 19));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 9));
|
||||
|
||||
// start on opening bracket
|
||||
editor.setPosition(new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 31));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 31));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('Jump to next bracket', () => {
|
||||
let mode = new BracketMode();
|
||||
let model = createTextModel('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
// start position between brackets
|
||||
editor.setPosition(new Position(1, 16));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 18));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 14));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 18));
|
||||
|
||||
// skip brackets in comments
|
||||
editor.setPosition(new Position(1, 21));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 24));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 23));
|
||||
|
||||
// do not break if no brackets are available
|
||||
editor.setPosition(new Position(1, 26));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 26));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('Select to next bracket', () => {
|
||||
let mode = new BracketMode();
|
||||
let model = createTextModel('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
|
||||
// start position in open brackets
|
||||
editor.setPosition(new Position(1, 9));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
|
||||
// start position in close brackets
|
||||
editor.setPosition(new Position(1, 20));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 20));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 9, 1, 20));
|
||||
|
||||
// start position between brackets
|
||||
editor.setPosition(new Position(1, 16));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 19));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 14, 1, 19));
|
||||
|
||||
// start position outside brackets
|
||||
editor.setPosition(new Position(1, 21));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 25));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 23, 1, 25));
|
||||
|
||||
// do not break if no brackets are available
|
||||
editor.setPosition(new Position(1, 26));
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getPosition(), new Position(1, 26));
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 26, 1, 26));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('issue #1772: jump to enclosing brackets', () => {
|
||||
const text = [
|
||||
'const x = {',
|
||||
' something: [0, 1, 2],',
|
||||
' another: true,',
|
||||
' somethingmore: [0, 2, 4]',
|
||||
'};',
|
||||
].join('\n');
|
||||
const mode = new BracketMode();
|
||||
const model = createTextModel(text, undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
const bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
editor.setPosition(new Position(3, 5));
|
||||
bracketMatchingController.jumpToBracket();
|
||||
assert.deepEqual(editor.getSelection(), new Selection(5, 1, 5, 1));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('issue #43371: argument to not select brackets', () => {
|
||||
const text = [
|
||||
'const x = {',
|
||||
' something: [0, 1, 2],',
|
||||
' another: true,',
|
||||
' somethingmore: [0, 2, 4]',
|
||||
'};',
|
||||
].join('\n');
|
||||
const mode = new BracketMode();
|
||||
const model = createTextModel(text, undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
const bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
editor.setPosition(new Position(3, 5));
|
||||
bracketMatchingController.selectToBracket(false);
|
||||
assert.deepEqual(editor.getSelection(), new Selection(1, 12, 5, 1));
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
|
||||
test('issue #45369: Select to Bracket with multicursor', () => {
|
||||
let mode = new BracketMode();
|
||||
let model = createTextModel('{ } { } { }', undefined, mode.getLanguageIdentifier());
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor) => {
|
||||
let bracketMatchingController = editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController);
|
||||
|
||||
// cursors inside brackets become selections of the entire bracket contents
|
||||
editor.setSelections([
|
||||
new Selection(1, 3, 1, 3),
|
||||
new Selection(1, 10, 1, 10),
|
||||
new Selection(1, 17, 1, 17)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
]);
|
||||
|
||||
// cursors to the left of bracket pairs become selections of the entire pair
|
||||
editor.setSelections([
|
||||
new Selection(1, 1, 1, 1),
|
||||
new Selection(1, 6, 1, 6),
|
||||
new Selection(1, 14, 1, 14)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
]);
|
||||
|
||||
// cursors just right of a bracket pair become selections of the entire pair
|
||||
editor.setSelections([
|
||||
new Selection(1, 5, 1, 5),
|
||||
new Selection(1, 13, 1, 13),
|
||||
new Selection(1, 19, 1, 19)
|
||||
]);
|
||||
bracketMatchingController.selectToBracket(true);
|
||||
assert.deepEqual(editor.getSelections(), [
|
||||
new Selection(1, 1, 1, 5),
|
||||
new Selection(1, 8, 1, 13),
|
||||
new Selection(1, 16, 1, 19)
|
||||
]);
|
||||
|
||||
bracketMatchingController.dispose();
|
||||
});
|
||||
|
||||
model.dispose();
|
||||
mode.dispose();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user