提交 b45424ab 编写于 作者: D Daniel Jost 提交者: Peng Lyu

Improved "Go To Bracket" to jump to next bracket. (#32110)

* Improved "Go To Bracket" to jump to next bracket.

* Removed extra bracket.

* Moved BracketMode class outside of test and removed comment from test string.

* Added multi-cursor support to "Go to Bracket"

* Fixed formatting.

* Changed line endings to LF.

* Fixed more line endings.

* Fixed "Go to Bracket" failing with a selection.
上级 ec58dc22
......@@ -875,19 +875,21 @@ export interface ITokenizedModel extends ITextModel {
*/
findMatchingBracketUp(bracket: string, position: IPosition): Range;
// /**
// * Find the first bracket in the model before `position`.
// * @param position The position at which to start the search.
// * @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.
// */
// findPrevBracket(position:IPosition): IFoundBracket;
// /**
// * Find the first bracket in the model after `position`.
// * @param position The position at which to start the search.
// * @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.
// */
// findNextBracket(position:IPosition): IFoundBracket;
/**
* Find the first bracket in the model before `position`.
* @param position The position at which to start the search.
* @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.
* @internal
*/
findPrevBracket(position:IPosition): IFoundBracket;
/**
* Find the first bracket in the model after `position`.
* @param position The position at which to start the search.
* @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.
* @internal
*/
findNextBracket(position:IPosition): IFoundBracket;
/**
* Given a `position`, if the position is on top or near a bracket,
......
......@@ -10,6 +10,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle';
import { Range } from 'vs/editor/common/core/range';
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 { editorAction, commonEditorContribution, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
......@@ -113,28 +114,33 @@ export class BracketMatchingController extends Disposable implements editorCommo
return;
}
const selection = this._editor.getSelection();
if (!selection.isEmpty()) {
return;
}
let newSelections = this._editor.getSelections().map(selection => {
const position = selection.getStartPosition();
const position = selection.getStartPosition();
const brackets = model.matchBracket(position);
if (!brackets) {
return;
}
// find matching brackets if position is on a bracket
const brackets = model.matchBracket(position);
let newCursorPosition: Position = 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 next bracket if the position isn't on a matching bracket
const nextBracket = model.findNextBracket(position);
if (nextBracket && nextBracket.range) {
newCursorPosition = nextBracket.range.getStartPosition();
}
}
let resultingPosition: Position = null;
if (brackets[0].containsPosition(position)) {
resultingPosition = brackets[1].getStartPosition();
} else if (brackets[1].containsPosition(position)) {
resultingPosition = brackets[0].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);
});
if (resultingPosition) {
this._editor.setPosition(resultingPosition);
this._editor.revealPosition(resultingPosition);
}
this._editor.setSelections(newSelections);
}
private static _DECORATION_OPTIONS = ModelDecorationOptions.register({
......@@ -224,4 +230,4 @@ registerThemingParticipant((theme, collector) => {
if (bracketMatchBorder) {
collector.addRule(`.monaco-editor .bracket-match { border: 1px solid ${bracketMatchBorder}; }`);
}
});
\ No newline at end of file
});
......@@ -14,29 +14,30 @@ import { LanguageIdentifier } from 'vs/editor/common/modes';
import { BracketMatchingController } from 'vs/editor/contrib/bracketMatching/common/bracketMatching';
suite('bracket matching', () => {
test('issue #183: jump to matching bracket position', () => {
class BracketMode extends MockMode {
private static _id = new LanguageIdentifier('bracketMode', 3);
constructor() {
super(BracketMode._id);
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
brackets: [
['{', '}'],
['[', ']'],
['(', ')'],
]
}));
}
class BracketMode extends MockMode {
private static _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 = Model.createFromString('var x = (3 + (5-7)) + ((5+3)+5);', undefined, mode.getLanguageIdentifier());
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
let bracketMatchingController = editor.registerAndInstantiateContribution<BracketMatchingController>(BracketMatchingController);
// start on closing bracket
editor.setPosition(new Position(1, 20));
bracketMatchingController.jumpToBracket();
assert.deepEqual(editor.getPosition(), new Position(1, 9));
......@@ -45,6 +46,7 @@ suite('bracket matching', () => {
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));
......@@ -59,4 +61,41 @@ suite('bracket matching', () => {
model.dispose();
mode.dispose();
});
test('Jump to next bracket', () => {
let mode = new BracketMode();
let model = Model.createFromString('var x = (3 + (5-7)); y();', undefined, mode.getLanguageIdentifier());
withMockCodeEditor(null, { model: model }, (editor, cursor) => {
let bracketMatchingController = editor.registerAndInstantiateContribution<BracketMatchingController>(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();
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册