提交 568c9e51 编写于 作者: A Alex Dima

Begin using mode's brackets when searching for brackets

上级 8c60e594
......@@ -1161,7 +1161,7 @@ export class OneCursorOp {
if (matchOpenBracket) {
var match = cursor.model.findMatchingBracketUp(matchOpenBracket, {
lineNumber: position.lineNumber,
column: position.column - matchOpenBracket.close.length
column: position.column - matchOpenBracket.length
});
if (match) {
var matchLineNumber = match.startLineNumber;
......
......@@ -1376,10 +1376,11 @@ export interface ITextModel {
isDisposed(): boolean;
}
export interface IFindBracketRequest {
modeId: string;
export interface IRichEditBracket {
open: string;
close: string;
forwardRegex: RegExp;
reversedRegex: RegExp;
}
export interface IFoundBracket {
......@@ -1486,7 +1487,7 @@ export interface ITokenizedModel extends ITextModel {
* @param position The position at which to start the search.
* @return The range of the matching bracket, or null if the bracket match was not found.
*/
findMatchingBracketUp(request:IFindBracketRequest, position:IPosition): IEditorRange;
findMatchingBracketUp(bracket:string, position:IPosition): IEditorRange;
/**
* Find the first bracket in the model before `position`.
......
......@@ -24,6 +24,7 @@ import {TPromise} from 'vs/base/common/winjs.base';
import {Range} from 'vs/editor/common/core/range';
import * as Strings from 'vs/base/common/strings';
import {ignoreBracketsInToken} from 'vs/editor/common/modes/supports';
import {BracketsUtils} from 'vs/editor/common/modes/supports/electricCharacter';
export class TokensInflatorMap implements EditorCommon.ITokensInflatorMap {
......@@ -847,12 +848,28 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return result;
}
public findMatchingBracketUp(request:EditorCommon.IFindBracketRequest, _position:EditorCommon.IPosition): EditorCommon.IEditorRange {
public findMatchingBracketUp(bracket:string, _position:EditorCommon.IPosition): EditorCommon.IEditorRange {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findMatchingBracketUp: Model is disposed');
}
return this._findMatchingBracketUp(request.open, request.close, this.validatePosition(_position));
let position = this.validatePosition(_position);
let modeTransitions = this._lines[position.lineNumber - 1].getModeTransitions().toArray(this._mode);
let currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
let currentMode = modeTransitions[currentModeIndex];
let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null;
if (!currentModeBrackets) {
return null;
}
let data = currentModeBrackets.textIsBracket[bracket];
if (!data) {
return null;
}
return this._findMatchingBracketUp(data, position);
}
public matchBracket(position:EditorCommon.IPosition, inaccurateResultAcceptable:boolean = false): EditorCommon.IMatchBracketResult {
......@@ -864,19 +881,20 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
}
private _matchBracket(position:EditorCommon.IEditorPosition): EditorCommon.IMatchBracketResult {
let reversedBracketRegex = /[\(\)\[\]\{\}]/; // TODO@Alex: use mode's brackets
let bracketRegex = /[\(\)\[\]\{\}]/; // TODO@Alex: use mode's brackets
let maxBracketLength = 1; // TODO@Alex: use mode's brackets
let tokensMap = this._tokensInflatorMap;
let lineNumber = position.lineNumber;
let lineTokens = this._lines[lineNumber - 1].getTokens();
let lineText = this._lines[lineNumber - 1].text;
let lineTokens = this._lines[lineNumber - 1].getTokens();
let tokens = lineTokens.getBinaryEncodedTokens();
let currentTokenIndex = lineTokens.findIndexOfOffset(position.column - 1);
let currentTokenStart = getStartIndex(tokens[currentTokenIndex]);
let modeTransitions = this._lines[lineNumber - 1].getModeTransitions().toArray(this._mode);
let currentModeIndex = Arrays.findIndexInSegmentsArray(modeTransitions, position.column - 1);
let currentMode = modeTransitions[currentModeIndex];
let currentModeBrackets = currentMode.mode.richEditSupport ? currentMode.mode.richEditSupport.brackets : null;
// If position is in between two tokens, try first looking in the previous token
if (currentTokenIndex > 0 && currentTokenStart === position.column - 1) {
let prevTokenIndex = currentTokenIndex - 1;
......@@ -886,18 +904,29 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
if (!ignoreBracketsInToken(prevTokenType)) {
let prevTokenStart = getStartIndex(tokens[prevTokenIndex]);
// limit search in case previous token is very large, there's no need to go beyond `maxBracketLength`
prevTokenStart = Math.max(prevTokenStart, position.column - 1 - maxBracketLength);
let prevMode = currentMode;
let prevModeBrackets = currentModeBrackets;
// check if previous token is in a different mode
if (currentModeIndex > 0 && currentMode.startIndex === position.column - 1) {
prevMode = modeTransitions[currentModeIndex - 1];
prevModeBrackets = prevMode.mode.richEditSupport ? prevMode.mode.richEditSupport.brackets : null;
}
let foundBracket = TextModelWithTokens._findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, prevTokenStart, currentTokenStart);
if (prevModeBrackets) {
// limit search in case previous token is very large, there's no need to go beyond `maxBracketLength`
prevTokenStart = Math.max(prevTokenStart, position.column - 1 - prevModeBrackets.maxBracketLength);
// check that we didn't hit a bracket too far away from position
if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let r = this._matchFoundBracket(foundBracket);
let foundBracket = BracketsUtils.findPrevBracketInToken(prevModeBrackets.reversedRegex, lineNumber, lineText, prevTokenStart, currentTokenStart);
// check that we can actually match this bracket
if (r) {
return r;
// check that we didn't hit a bracket too far away from position
if (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1);
let r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText]);
// check that we can actually match this bracket
if (r) {
return r;
}
}
}
}
......@@ -906,32 +935,35 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
// check that the token is not to be ignored
if (!ignoreBracketsInToken(getType(tokensMap, tokens[currentTokenIndex]))) {
// limit search to not go before `maxBracketLength`
currentTokenStart = Math.max(currentTokenStart, position.column - 1 - maxBracketLength);
if (currentModeBrackets) {
// limit search to not go before `maxBracketLength`
currentTokenStart = Math.max(currentTokenStart, position.column - 1 - currentModeBrackets.maxBracketLength);
// limit search to not go after `maxBracketLength`
let currentTokenEnd = (currentTokenIndex + 1 < tokens.length ? getStartIndex(tokens[currentTokenIndex + 1]) : lineText.length);
currentTokenEnd = Math.min(currentTokenEnd, position.column - 1 + maxBracketLength);
// limit search to not go after `maxBracketLength`
let currentTokenEnd = (currentTokenIndex + 1 < tokens.length ? getStartIndex(tokens[currentTokenIndex + 1]) : lineText.length);
currentTokenEnd = Math.min(currentTokenEnd, position.column - 1 + currentModeBrackets.maxBracketLength);
// it might still be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets
while(true) {
let foundBracket = TextModelWithTokens._findNextBracketInText(bracketRegex, lineNumber, lineText.substring(currentTokenStart, currentTokenEnd), currentTokenStart);
if (!foundBracket) {
// there are no brackets in this text
break;
}
// it might still be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets
while(true) {
let foundBracket = BracketsUtils.findNextBracketInText(currentModeBrackets.forwardRegex, lineNumber, lineText.substring(currentTokenStart, currentTokenEnd), currentTokenStart);
if (!foundBracket) {
// there are no brackets in this text
break;
}
// check that we didn't hit a bracket too far away from position
if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let r = this._matchFoundBracket(foundBracket);
// check that we didn't hit a bracket too far away from position
if (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {
let foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1);
let r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText]);
// check that we can actually match this bracket
if (r) {
return r;
// check that we can actually match this bracket
if (r) {
return r;
}
}
}
currentTokenStart = foundBracket.endColumn - 1;
currentTokenStart = foundBracket.endColumn - 1;
}
}
}
......@@ -941,19 +973,17 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
};
}
private _matchFoundBracket(foundBracket:Range): EditorCommon.IMatchBracketResult {
let data = this._toFoundBracket(foundBracket);
if (data.isOpen) {
let matched = this._findMatchingBracketDown(data.open, data.close, data.range.getEndPosition());
private _matchFoundBracket(foundBracket:Range, data:EditorCommon.IRichEditBracket, isOpen:boolean): EditorCommon.IMatchBracketResult {
if (isOpen) {
let matched = this._findMatchingBracketDown(data, foundBracket.getEndPosition());
if (matched) {
return {
brackets: [foundBracket, matched],
isAccurate: true
};
}
} else if (!data.isOpen) {
let matched = this._findMatchingBracketUp(data.open, data.close, data.range.getStartPosition());
} else {
let matched = this._findMatchingBracketUp(data, foundBracket.getStartPosition());
if (matched) {
return {
brackets: [foundBracket, matched],
......@@ -965,50 +995,13 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return null;
}
private static _getReversedString(str:string): string {
let reversedStr = '';
for (let i = str.length - 1; i >= 0; i--) {
reversedStr += str.charAt(i);
}
return reversedStr;
}
private static _REVERSED_REGEX_BRACKET_PAIR_CACHE: {[key:string]: RegExp;} = {};
private static _getReversedRegexForBracketPair(open:string, close:string): RegExp {
let key = open + ';' + close;
if (!this._REVERSED_REGEX_BRACKET_PAIR_CACHE.hasOwnProperty(key)) {
let reversedOpen = this._getReversedString(open);
let reversedClose = this._getReversedString(close);
let reversedOpenEscaped = Strings.escapeRegExpCharacters(reversedOpen);
let reversedCloseEscaped = Strings.escapeRegExpCharacters(reversedClose);
private _findMatchingBracketUp(bracket:EditorCommon.IRichEditBracket, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
let regexStr = `(${reversedOpenEscaped})|(${reversedCloseEscaped})`;
this._REVERSED_REGEX_BRACKET_PAIR_CACHE[key] = Strings.createRegExp(regexStr, true, false, false, false);
}
return this._REVERSED_REGEX_BRACKET_PAIR_CACHE[key];
}
private static _REGEX_BRACKET_PAIR_CACHE: {[key:string]: RegExp;} = {};
private static _getRegexForBracketPair(open:string, close:string): RegExp {
let key = open + ';' + close;
if (!this._REGEX_BRACKET_PAIR_CACHE.hasOwnProperty(key)) {
let openEscaped = Strings.escapeRegExpCharacters(open);
let closeEscaped = Strings.escapeRegExpCharacters(close);
let regexStr = `(${openEscaped})|(${closeEscaped})`;
this._REGEX_BRACKET_PAIR_CACHE[key] = Strings.createRegExp(regexStr, true, false, false, false);
}
return this._REGEX_BRACKET_PAIR_CACHE[key];
}
private _findMatchingBracketUp(openBracket:string, closeBracket:string, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketUp: ', 'openBracket: ', openBracket, 'closeBracket: ', closeBracket, 'startPosition: ', String(position));
let tokensMap = this._tokensInflatorMap;
let reversedBracketRegex = TextModelWithTokens._getReversedRegexForBracketPair(openBracket, closeBracket);
// TODO@Alex: account for mode transitions
let reversedBracketRegex = bracket.reversedRegex;
let count = -1;
for (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {
......@@ -1031,16 +1024,16 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
if (!ignoreBracketsInToken(currentTokenType)) {
while (true) {
let r = TextModelWithTokens._findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (!r) {
break;
}
let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1);
if (hitText === openBracket) {
if (hitText === bracket.open) {
count++;
} else if (hitText === closeBracket) {
} else if (hitText === bracket.close) {
count--;
}
......@@ -1059,11 +1052,12 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return null;
}
private _findMatchingBracketDown(openBracket:string, closeBracket:string, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketDown: ', 'openBracket: ', openBracket, 'closeBracket: ', closeBracket, 'startPosition: ', String(position));
private _findMatchingBracketDown(bracket:EditorCommon.IRichEditBracket, position:EditorCommon.IEditorPosition): Range {
// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));
let tokensMap = this._tokensInflatorMap;
let bracketRegex = TextModelWithTokens._getRegexForBracketPair(openBracket, closeBracket);
// TODO@Alex: account for mode transitions
let bracketRegex = bracket.forwardRegex;
let count = 1;
for (let lineNumber = position.lineNumber, lineCount = this.getLineCount(); lineNumber <= lineCount; lineNumber++) {
......@@ -1086,16 +1080,16 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
if (!ignoreBracketsInToken(currentTokenType)) {
while (true) {
let r = TextModelWithTokens._findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
let r = BracketsUtils.findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (!r) {
break;
}
let hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1);
if (hitText === openBracket) {
if (hitText === bracket.open) {
count++;
} else if (hitText === closeBracket) {
} else if (hitText === bracket.close) {
count--;
}
......@@ -1114,30 +1108,6 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return null;
}
private static _findPrevBracketInText(reversedBracketRegex:RegExp, lineNumber:number, reversedText:string, offset:number): Range {
let m = reversedText.match(reversedBracketRegex);
if (!m) {
return null;
}
let matchOffset = reversedText.length - 1 - m.index;
let matchLength = m[0].length;
let absoluteMatchOffset = offset + matchOffset;
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
private static _findPrevBracketInToken(reversedBracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
// Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)
let currentTokenReversedText = '';
for (let index = currentTokenEnd - 1; index >= currentTokenStart; index--) {
currentTokenReversedText += lineText.charAt(index);
}
return this._findPrevBracketInText(reversedBracketRegex, lineNumber, currentTokenReversedText, currentTokenStart);
}
public findPrevBracket(_position:EditorCommon.IPosition): EditorCommon.IFoundBracket {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findPrevBracket: Model is disposed');
......@@ -1165,7 +1135,7 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
let currentTokenStart = getStartIndex(currentToken);
if (!ignoreBracketsInToken(currentTokenType)) {
let r = TextModelWithTokens._findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (r) {
return this._toFoundBracket(r);
}
......@@ -1178,26 +1148,6 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
return null;
}
private static _findNextBracketInText(bracketRegex:RegExp, lineNumber:number, text:string, offset:number): Range {
let m = text.match(bracketRegex);
if (!m) {
return null;
}
let matchOffset = m.index;
let matchLength = m[0].length;
let absoluteMatchOffset = offset + matchOffset;
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
private static _findNextBracketInToken(bracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
let currentTokenText = lineText.substring(currentTokenStart, currentTokenEnd);
return this._findNextBracketInText(bracketRegex, lineNumber, currentTokenText, currentTokenStart);
}
public findNextBracket(_position:EditorCommon.IPosition): EditorCommon.IFoundBracket {
if (this._isDisposed) {
throw new Error('TextModelWithTokens.findNextBracket: Model is disposed');
......@@ -1225,7 +1175,7 @@ export class TextModelWithTokens extends TextModel implements EditorCommon.IToke
let currentTokenEnd = tokenIndex + 1 < tokensLength ? getStartIndex(tokens[tokenIndex + 1]) : lineText.length;
if (!ignoreBracketsInToken(currentTokenType)) {
let r = TextModelWithTokens._findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
let r = BracketsUtils.findNextBracketInToken(bracketRegex, lineNumber, lineText, currentTokenStart, currentTokenEnd);
if (r) {
return this._toFoundBracket(r);
}
......
......@@ -697,7 +697,7 @@ export interface IElectricAction {
// The line will be indented at the same level of the line
// which contains the matching given bracket type.
matchOpenBracket?:EditorCommon.IFindBracketRequest;
matchOpenBracket?:string;
// The text will be appended after the electric character.
appendText?:string;
......@@ -754,6 +754,15 @@ export interface IRichEditCharacterPair {
getSurroundingPairs():IAutoClosingPair[];
}
export interface IRichEditBrackets {
maxBracketLength: number;
forwardRegex: RegExp;
reversedRegex: RegExp;
brackets: EditorCommon.IRichEditBracket[];
textIsBracket: {[text:string]:EditorCommon.IRichEditBracket;};
textIsOpenBracket: {[text:string]:boolean;};
}
export interface IRichEditSupport {
/**
* Optional adapter for electric characters.
......@@ -779,4 +788,9 @@ export interface IRichEditSupport {
* Optional adapter for custom Enter handling.
*/
onEnter?: IRichEditOnEnter;
/**
* Optional adapter for brackets.
*/
brackets?: IRichEditBrackets;
}
......@@ -8,7 +8,7 @@ import * as Modes from 'vs/editor/common/modes';
import {handleEvent, ignoreBracketsInToken} from 'vs/editor/common/modes/supports';
import Strings = require('vs/base/common/strings');
import {Range} from 'vs/editor/common/core/range';
import {IFoundBracket} from 'vs/editor/common/editorCommon';
import {IRichEditBracket} from 'vs/editor/common/editorCommon';
import {Arrays} from 'vs/editor/common/core/arrays';
/**
......@@ -58,31 +58,26 @@ export class BracketElectricCharacterSupport implements Modes.IRichEditElectricC
}
});
}
}
interface ISimpleInternalBracket {
open: string;
close: string;
}
interface IInternalBrackets extends ISimpleInternalBracket {
forwardRegex: RegExp;
reversedRegex: RegExp;
public getRichEditBrackets(): Modes.IRichEditBrackets {
return this.brackets.getRichEditBrackets();
}
}
interface ITextBracket {
interface ISimpleInternalBracket {
open: string;
close: string;
isOpen: boolean;
}
export class Brackets {
private _modeId: string;
private _brackets: IInternalBrackets[];
private _brackets: IRichEditBracket[];
private _bracketsForwardRegex: RegExp;
private _bracketsReversedRegex: RegExp;
private _text2Bracket: {[text:string]:ITextBracket;};
private _maxBracketLength: number;
private _textIsBracket: {[text:string]:IRichEditBracket;};
private _textIsOpenBracket: {[text:string]:boolean;};
private _docComment: IDocComment;
constructor(modeId: string, brackets: Modes.IBracketPair[], docComment: IDocComment = null, caseInsensitive: boolean = false) {
......@@ -97,14 +92,35 @@ export class Brackets {
});
this._bracketsForwardRegex = getRegexForBrackets(this._brackets);
this._bracketsReversedRegex = getReversedRegexForBrackets(this._brackets);
this._text2Bracket = {};
this._textIsBracket = {};
this._textIsOpenBracket = {};
this._maxBracketLength = 0;
this._brackets.forEach((b) => {
this._text2Bracket[b.open] = { open: b.open, close: b.close, isOpen: true };
this._text2Bracket[b.close] = { open: b.open, close: b.close, isOpen: false };
this._textIsBracket[b.open] = b;
this._textIsBracket[b.close] = b;
this._textIsOpenBracket[b.open] = true;
this._textIsOpenBracket[b.close] = false;
this._maxBracketLength = Math.max(this._maxBracketLength, b.open.length);
this._maxBracketLength = Math.max(this._maxBracketLength, b.close.length);
});
this._docComment = docComment ? docComment : null;
}
public getRichEditBrackets(): Modes.IRichEditBrackets {
if (this._brackets.length === 0) {
return null;
}
return {
maxBracketLength: this._maxBracketLength,
forwardRegex: this._bracketsForwardRegex,
reversedRegex: this._bracketsReversedRegex,
brackets: this._brackets,
textIsBracket: this._textIsBracket,
textIsOpenBracket: this._textIsOpenBracket
};
}
public getElectricCharacters():string[] {
var result: string[] = [];
......@@ -168,15 +184,11 @@ export class Brackets {
let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, lineText, tokenStart, tokenEnd);
if (r) {
let text = lineText.substring(r.startColumn - 1, r.endColumn - 1);
let data = this._text2Bracket[text];
if (!data.isOpen) {
let isOpen = this._textIsOpenBracket[text];
if (!isOpen) {
return {
matchOpenBracket: {
modeId: this._modeId,
open: data.open,
close: data.close
}
}
matchOpenBracket: text
};
}
}
}
......@@ -228,7 +240,6 @@ function once<T, R>(keyFn:(input:T)=>string, computeFn:(input:T)=>R):(input:T)=>
}
}
// TODO: dup in textModelWithTokens
var getRegexForBracketPair = once<ISimpleInternalBracket,RegExp>(
(input) => `${input.open};${input.close}`,
(input) => {
......@@ -236,7 +247,6 @@ var getRegexForBracketPair = once<ISimpleInternalBracket,RegExp>(
}
);
// TODO: dup in textModelWithTokens
var getReversedRegexForBracketPair = once<ISimpleInternalBracket,RegExp>(
(input) => `${input.open};${input.close}`,
(input) => {
......@@ -273,7 +283,6 @@ function createOrRegex(pieces:string[]): RegExp {
return Strings.createRegExp(regexStr, true, false, false, false);
}
// TODO: dup in textModelWithTokens
function toReversedString(str:string): string {
let reversedStr = '';
for (let i = str.length - 1; i >= 0; i--) {
......@@ -284,7 +293,6 @@ function toReversedString(str:string): string {
export class BracketsUtils {
// TODO: dup in textModelWithTokens
private static _findPrevBracketInText(reversedBracketRegex:RegExp, lineNumber:number, reversedText:string, offset:number): Range {
let m = reversedText.match(reversedBracketRegex);
......@@ -299,7 +307,6 @@ export class BracketsUtils {
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
// TODO: dup in textModelWithTokens
public static findPrevBracketInToken(reversedBracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
// Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)
let currentTokenReversedText = '';
......@@ -310,4 +317,24 @@ export class BracketsUtils {
return this._findPrevBracketInText(reversedBracketRegex, lineNumber, currentTokenReversedText, currentTokenStart);
}
public static findNextBracketInText(bracketRegex:RegExp, lineNumber:number, text:string, offset:number): Range {
let m = text.match(bracketRegex);
if (!m) {
return null;
}
let matchOffset = m.index;
let matchLength = m[0].length;
let absoluteMatchOffset = offset + matchOffset;
return new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);
}
public static findNextBracketInToken(bracketRegex:RegExp, lineNumber:number, lineText:string, currentTokenStart:number, currentTokenEnd:number): Range {
let currentTokenText = lineText.substring(currentTokenStart, currentTokenEnd);
return this.findNextBracketInText(bracketRegex, lineNumber, currentTokenText, currentTokenStart);
}
}
......@@ -30,11 +30,12 @@ export interface IRichEditConfiguration {
export class RichEditSupport implements Modes.IRichEditSupport {
public electricCharacter: Modes.IRichEditElectricCharacter;
public electricCharacter: BracketElectricCharacterSupport;
public comments: Modes.ICommentsConfiguration;
public characterPair: Modes.IRichEditCharacterPair;
public wordDefinition: RegExp;
public onEnter: Modes.IRichEditOnEnter;
public brackets: Modes.IRichEditBrackets;
constructor(modeId:string, conf:IRichEditConfiguration) {
......@@ -48,6 +49,7 @@ export class RichEditSupport implements Modes.IRichEditSupport {
if (conf.__electricCharacterSupport) {
this.electricCharacter = new BracketElectricCharacterSupport(modeId, conf.__electricCharacterSupport);
this.brackets = this.electricCharacter.getRichEditBrackets();
}
this.wordDefinition = conf.wordPattern || NullMode.DEFAULT_WORD_REGEXP;
......
......@@ -220,12 +220,22 @@ export class BracketState extends AbstractState {
export class BracketMode extends TestingMode {
public tokenizationSupport: modes.ITokenizationSupport;
public richEditSupport: modes.IRichEditSupport;
constructor() {
super();
this.tokenizationSupport = new TokenizationSupport(this, {
getInitialState: () => new BracketState(this)
}, false, false);
this.richEditSupport = new RichEditSupport(this.getId(), {
__electricCharacterSupport: {
brackets: [
{ tokenType: 'asd', open: '{', close: '}', isElectric: true },
{ tokenType: 'qwe', open: '[', close: ']', isElectric: true },
{ tokenType: 'zxc', open: '(', close: ')', isElectric: true }
]
}
});
}
}
......
......@@ -68,9 +68,9 @@ suite('JS - Auto Indent', () => {
assert.deepEqual(actual, expected, 'LINE <<<' + line + '>>>, OFFSET: <<<' + offset + '>>>');
}
const CURLY = { matchOpenBracket: { modeId:'javascript', open:'{', close:'}' } };
const ROUND = { matchOpenBracket: { modeId:'javascript', open:'(', close:')' } };
const SQUARE = { matchOpenBracket: { modeId:'javascript', open:'[', close:']' } };
const CURLY = { matchOpenBracket: '}' };
const ROUND = { matchOpenBracket: ')' };
const SQUARE = { matchOpenBracket: ']' };
testElectricCharacter('var f = function() {}', 20, null);
testElectricCharacter('}', 0, CURLY);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册