Skip to content

Commit

Permalink
Merge pull request microsoft#39066 from afonsobspinto/selectToBracket
Browse files Browse the repository at this point in the history
Select to bracket
  • Loading branch information
alexdima authored Jan 23, 2018
2 parents 84991c4 + c903bd7 commit 09b5860
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
70 changes: 67 additions & 3 deletions src/vs/editor/contrib/bracketMatching/bracketMatching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { RunOnceScheduler } from 'vs/base/common/async';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/browser/editorExtensions';
import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorBracketMatchBackground, editorBracketMatchBorder } from 'vs/editor/common/view/editorColorRegistry';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model';

class SelectBracketAction extends EditorAction {
class JumpToBracketAction extends EditorAction {
constructor() {
super({
id: 'editor.action.jumpToBracket',
Expand All @@ -45,6 +45,25 @@ class SelectBracketAction extends EditorAction {
}
}

class SelectToBracketAction extends EditorAction {
constructor() {
super({
id: 'editor.action.selectToBracket',
label: nls.localize('smartSelect.selectToBracket', "Select to Bracket"),
alias: 'Select to Bracket',
precondition: null
});
}

public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
let controller = BracketMatchingController.get(editor);
if (!controller) {
return;
}
controller.selectToBracket();
}
}

type Brackets = [Range, Range];

class BracketsData {
Expand Down Expand Up @@ -149,6 +168,50 @@ export class BracketMatchingController extends Disposable implements editorCommo
this._editor.revealRange(newSelections[0]);
}

public selectToBracket(): void {
const model = this._editor.getModel();
if (!model) {
return;
}
const selection = this._editor.getSelection();
if (!selection.isEmpty()) {
return;
}

const position = selection.getStartPosition();

let brackets = model.matchBracket(position);

let openBracket: Position = null;
let closeBracket: Position = null;

if (!brackets) {
const nextBracket = model.findNextBracket(position);
if (nextBracket && nextBracket.range) {
brackets = model.matchBracket(nextBracket.range.getStartPosition());
}
}

if (brackets) {
if (brackets[0].startLineNumber === brackets[1].startLineNumber) {
openBracket = brackets[1].startColumn < brackets[0].startColumn ?
brackets[1].getStartPosition() : brackets[0].getStartPosition();
closeBracket = brackets[1].startColumn < brackets[0].startColumn ?
brackets[0].getEndPosition() : brackets[1].getEndPosition();
} else {
openBracket = brackets[1].startLineNumber < brackets[0].startLineNumber ?
brackets[1].getStartPosition() : brackets[0].getStartPosition();
closeBracket = brackets[1].startLineNumber < brackets[0].startLineNumber ?
brackets[0].getEndPosition() : brackets[1].getEndPosition();
}
}

if (openBracket && closeBracket) {
this._editor.setSelection(new Range(openBracket.lineNumber, openBracket.column, closeBracket.lineNumber, closeBracket.column));
}
}


private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
className: 'bracket-match'
Expand Down Expand Up @@ -228,7 +291,8 @@ export class BracketMatchingController extends Disposable implements editorCommo
}

registerEditorContribution(BracketMatchingController);
registerEditorAction(SelectBracketAction);
registerEditorAction(SelectToBracketAction);
registerEditorAction(JumpToBracketAction);
registerThemingParticipant((theme, collector) => {
let bracketMatchBackground = theme.getColor(editorBracketMatchBackground);
if (bracketMatchBackground) {
Expand Down
46 changes: 46 additions & 0 deletions src/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import * as assert from 'assert';
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { TextModel } from 'vs/editor/common/model/textModel';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
Expand Down Expand Up @@ -98,4 +99,49 @@ suite('bracket matching', () => {
model.dispose();
mode.dispose();
});

test('Select to next bracket', () => {
let mode = new BracketMode();
let model = TextModel.createFromString('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier());

withTestCodeEditor(null, { model: model }, (editor, cursor) => {
let bracketMatchingController = editor.registerAndInstantiateContribution<BracketMatchingController>(BracketMatchingController);


// start position in open brackets
editor.setPosition(new Position(1, 9));
bracketMatchingController.selectToBracket();
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();
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();
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();
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();
assert.deepEqual(editor.getPosition(), new Position(1, 26));
assert.deepEqual(editor.getSelection(), new Selection(1, 26, 1, 26));

bracketMatchingController.dispose();
});

model.dispose();
mode.dispose();
});
});

0 comments on commit 09b5860

Please sign in to comment.