提交 ca6a1f10 编写于 作者: A Alex Dima

characterPair uses StandardTokenType

上级 b9968a17
......@@ -9,13 +9,13 @@ import { ModeTransition } from 'vs/editor/common/core/modeTransition';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
/**
* A standard token type.
* A standard token type. Values are 2^x such that a bit mask can be used.
*/
export const enum StandardTokenType {
Other = 0,
Comment = 1,
String = 2,
RegEx = 3
RegEx = 4
}
const STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex)\b/;
......
......@@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { StandardTokenType } from 'vs/editor/common/core/lineTokens';
/**
* Describes how comments for a language work.
*/
......@@ -181,3 +183,43 @@ export interface EnterAction {
*/
removeText?: number;
}
/**
* @internal
*/
export class StandardAutoClosingPairConditional {
_standardAutoClosingPairConditionalBrand: void;
readonly open: string;
readonly close: string;
private readonly _standardTokenMask: number;
constructor(source: IAutoClosingPairConditional) {
this.open = source.open;
this.close = source.close;
// initially allowed in all tokens
this._standardTokenMask = 0;
if (Array.isArray(source.notIn)) {
for (let i = 0, len = source.notIn.length; i < len; i++) {
let notIn = source.notIn[i];
switch (notIn) {
case 'string':
this._standardTokenMask |= StandardTokenType.String;
break;
case 'comment':
this._standardTokenMask |= StandardTokenType.Comment;
break;
case 'regex':
this._standardTokenMask |= StandardTokenType.RegEx;
break;
}
}
}
}
public isOK(standardToken: StandardTokenType): boolean {
return (this._standardTokenMask & <number>standardToken) === 0;
}
}
......@@ -16,7 +16,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
import { createScopedLineTokens } from 'vs/editor/common/modes/supports';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { IndentAction, EnterAction, IAutoClosingPair, IAutoClosingPairConditional, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
/**
* Interface used to support insertion of mode specific comments.
......@@ -191,7 +191,7 @@ export class LanguageConfigurationRegistryImpl {
return value.characterPair || null;
}
public getAutoClosingPairs(modeId: string): IAutoClosingPairConditional[] {
public getAutoClosingPairs(modeId: string): IAutoClosingPair[] {
let characterPairSupport = this._getCharacterPairSupport(modeId);
if (!characterPairSupport) {
return [];
......
......@@ -5,18 +5,22 @@
'use strict';
import { ScopedLineTokens } from 'vs/editor/common/modes/supports';
import { CharacterPair, IAutoClosingPair, IAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
import { CharacterPair, IAutoClosingPair, IAutoClosingPairConditional, StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
export class CharacterPairSupport {
private readonly _autoClosingPairs: IAutoClosingPairConditional[];
private readonly _autoClosingPairs: StandardAutoClosingPairConditional[];
private readonly _surroundingPairs: IAutoClosingPair[];
constructor(config: { brackets?: CharacterPair[]; autoClosingPairs?: IAutoClosingPairConditional[], surroundingPairs?: IAutoClosingPair[] }) {
this._autoClosingPairs = config.autoClosingPairs;
if (!this._autoClosingPairs) {
this._autoClosingPairs = config.brackets ? config.brackets.map(b => ({ open: b[0], close: b[1] })) : [];
if (config.autoClosingPairs) {
this._autoClosingPairs = config.autoClosingPairs.map(el => new StandardAutoClosingPairConditional(el));
} else if (config.brackets) {
this._autoClosingPairs = config.brackets.map(b => new StandardAutoClosingPairConditional({ open: b[0], close: b[1] }));
} else {
this._autoClosingPairs = [];
}
this._surroundingPairs = config.surroundingPairs || this._autoClosingPairs;
}
......@@ -30,19 +34,14 @@ export class CharacterPairSupport {
return true;
}
var tokenIndex = context.findTokenIndexAtOffset(offset - 1);
var tokenType = context.getTokenType(tokenIndex);
for (var i = 0; i < this._autoClosingPairs.length; ++i) {
if (this._autoClosingPairs[i].open === character) {
if (this._autoClosingPairs[i].notIn) {
for (var notInIndex = 0; notInIndex < this._autoClosingPairs[i].notIn.length; ++notInIndex) {
if (tokenType.indexOf(this._autoClosingPairs[i].notIn[notInIndex]) > -1) {
return false;
}
}
}
break;
let tokenIndex = context.findTokenIndexAtOffset(offset - 1);
let standardTokenType = context.getStandardTokenType(tokenIndex);
for (let i = 0; i < this._autoClosingPairs.length; ++i) {
let autoClosingPair = this._autoClosingPairs[i];
if (autoClosingPair.open === character) {
return autoClosingPair.isOK(standardTokenType);
}
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
import { StandardTokenType } from 'vs/editor/common/core/lineTokens';
suite('StandardAutoClosingPairConditional', () => {
test('Missing notIn', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}' });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('Empty notIn', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('Invalid notIn', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'bla' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('notIn in strings', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'string' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), false);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('notIn in comments', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'comment' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), false);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('notIn in regex', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'regex' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), false);
});
test('notIn in strings nor comments', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'string', 'comment' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), false);
assert.equal(v.isOK(StandardTokenType.String), false);
assert.equal(v.isOK(StandardTokenType.RegEx), true);
});
test('notIn in strings nor regex', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'string', 'regex' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), true);
assert.equal(v.isOK(StandardTokenType.String), false);
assert.equal(v.isOK(StandardTokenType.RegEx), false);
});
test('notIn in comments nor regex', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'comment', 'regex' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), false);
assert.equal(v.isOK(StandardTokenType.String), true);
assert.equal(v.isOK(StandardTokenType.RegEx), false);
});
test('notIn in strings, comments nor regex', () => {
let v = new StandardAutoClosingPairConditional({ open: '{', close: '}', notIn: [ 'string', 'comment', 'regex' ] });
assert.equal(v.isOK(StandardTokenType.Other), true);
assert.equal(v.isOK(StandardTokenType.Comment), false);
assert.equal(v.isOK(StandardTokenType.String), false);
assert.equal(v.isOK(StandardTokenType.RegEx), false);
});
});
......@@ -5,8 +5,6 @@
'use strict';
import * as assert from 'assert';
import { CharacterPair, IndentAction } from 'vs/editor/common/modes/languageConfiguration';
import { OnEnterSupport } from 'vs/editor/common/modes/supports/onEnter';
import { CharacterPairSupport } from 'vs/editor/common/modes/supports/characterPair';
import { TokenText, createFakeScopedLineTokens } from 'vs/editor/test/common/modesTestUtils';
......@@ -14,8 +12,8 @@ suite('CharacterPairSupport', () => {
test('only autoClosingPairs', () => {
let characaterPairSupport = new CharacterPairSupport({ autoClosingPairs: [{ open: 'a', close: 'b' }] });
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b' }]);
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b' }]);
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
});
test('only empty autoClosingPairs', () => {
......@@ -26,8 +24,8 @@ suite('CharacterPairSupport', () => {
test('only brackets', () => {
let characaterPairSupport = new CharacterPairSupport({ brackets: [['a', 'b']] });
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b' }]);
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b' }]);
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), [{ open: 'a', close: 'b', _standardTokenMask: 0 }]);
});
test('only empty brackets', () => {
......@@ -43,7 +41,7 @@ suite('CharacterPairSupport', () => {
});
test('only empty surroundingPairs', () => {
let characaterPairSupport = new CharacterPairSupport({ brackets: [] });
let characaterPairSupport = new CharacterPairSupport({ surroundingPairs: [] });
assert.deepEqual(characaterPairSupport.getAutoClosingPairs(), []);
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
});
......@@ -71,7 +69,7 @@ suite('CharacterPairSupport', () => {
});
test('shouldAutoClosePair in not interesting line 2', () => {
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}'}] });
let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}' }] });
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], '{', 2), true);
assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], 'a', 2), true);
});
......@@ -121,149 +119,3 @@ suite('CharacterPairSupport', () => {
});
});
// suite('OnEnter', () => {
// test('uses indentationRules', () => {
// var support = new OnEnterSupport({
// indentationRules: {
// decreaseIndentPattern: /^\s*((?!\S.*\/[*]).*[*]\/\s*)?[})\]]|^\s*(case\b.*|default):\s*(\/\/.*|\/[*].*[*]\/\s*)?$/,
// increaseIndentPattern: /(\{[^}"']*|\([^)"']*|\[[^\]"']*|^\s*(\{\}|\(\)|\[\]|(case\b.*|default):))\s*(\/\/.*|\/[*].*[*]\/\s*)?$/,
// indentNextLinePattern: /^\s*(for|while|if|else)\b(?!.*[;{}]\s*(\/\/.*|\/[*].*[*]\/\s*)?$)/,
// unIndentedLinePattern: /^(?!.*([;{}]|\S:)\s*(\/\/.*|\/[*].*[*]\/\s*)?$)(?!.*(\{[^}"']*|\([^)"']*|\[[^\]"']*|^\s*(\{\}|\(\)|\[\]|(case\b.*|default):))\s*(\/\/.*|\/[*].*[*]\/\s*)?$)(?!^\s*((?!\S.*\/[*]).*[*]\/\s*)?[})\]]|^\s*(case\b.*|default):\s*(\/\/.*|\/[*].*[*]\/\s*)?$)(?!^\s*(for|while|if|else)\b(?!.*[;{}]\s*(\/\/.*|\/[*].*[*]\/\s*)?$))/
// }
// });
// var testIndentAction = (oneLineAboveText: string, beforeText: string, afterText: string, expected: IndentAction) => {
// var actual = support.onEnter(oneLineAboveText, beforeText, afterText);
// if (expected === IndentAction.None) {
// assert.equal(actual, null);
// } else {
// assert.equal(actual.indentAction, expected);
// }
// };
// testIndentAction('', 'case', '', IndentAction.None);
// testIndentAction('', 'case:', '', IndentAction.Indent);
// testIndentAction('', 'if (true) {', '', IndentAction.Indent);
// testIndentAction('', 'if (true)', '', IndentAction.Indent);
// testIndentAction('', ' ', '}', IndentAction.Outdent);
// testIndentAction('if(true)', '\treturn false', '', IndentAction.Outdent);
// });
// test('uses brackets', () => {
// var brackets: CharacterPair[] = [
// ['(', ')'],
// ['begin', 'end']
// ];
// var support = new OnEnterSupport({
// brackets: brackets
// });
// var testIndentAction = (beforeText: string, afterText: string, expected: IndentAction) => {
// var actual = support.onEnter('', beforeText, afterText);
// if (expected === IndentAction.None) {
// assert.equal(actual, null);
// } else {
// assert.equal(actual.indentAction, expected);
// }
// };
// testIndentAction('a', '', IndentAction.None);
// testIndentAction('', 'b', IndentAction.None);
// testIndentAction('(', 'b', IndentAction.Indent);
// testIndentAction('a', ')', IndentAction.None);
// testIndentAction('begin', 'ending', IndentAction.Indent);
// testIndentAction('abegin', 'end', IndentAction.None);
// testIndentAction('begin', ')', IndentAction.Indent);
// testIndentAction('begin', 'end', IndentAction.IndentOutdent);
// testIndentAction('begin ', ' end', IndentAction.IndentOutdent);
// testIndentAction(' begin', 'end//as', IndentAction.IndentOutdent);
// testIndentAction('(', ')', IndentAction.IndentOutdent);
// testIndentAction('( ', ')', IndentAction.IndentOutdent);
// testIndentAction('a(', ')b', IndentAction.IndentOutdent);
// testIndentAction('(', '', IndentAction.Indent);
// testIndentAction('(', 'foo', IndentAction.Indent);
// testIndentAction('begin', 'foo', IndentAction.Indent);
// testIndentAction('begin', '', IndentAction.Indent);
// });
// test('uses regExpRules', () => {
// var support = new OnEnterSupport({
// regExpRules: [
// {
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
// afterText: /^\s*\*\/$/,
// action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
// },
// {
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
// action: { indentAction: IndentAction.None, appendText: ' * ' }
// },
// {
// beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
// action: { indentAction: IndentAction.None, appendText: '* ' }
// },
// {
// beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
// action: { indentAction: IndentAction.None, removeText: 1 }
// },
// {
// beforeText: /^(\t|(\ \ ))*\ \*[^/]*\*\/\s*$/,
// action: { indentAction: IndentAction.None, removeText: 1 }
// }
// ]
// });
// var testIndentAction = (beforeText: string, afterText: string, expectedIndentAction: IndentAction, expectedAppendText: string, removeText: number = 0) => {
// var actual = support.onEnter('', beforeText, afterText);
// if (expectedIndentAction === null) {
// assert.equal(actual, null, 'isNull:' + beforeText);
// } else {
// assert.equal(actual !== null, true, 'isNotNull:' + beforeText);
// assert.equal(actual.indentAction, expectedIndentAction, 'indentAction:' + beforeText);
// if (expectedAppendText !== null) {
// assert.equal(actual.appendText, expectedAppendText, 'appendText:' + beforeText);
// }
// if (removeText !== 0) {
// assert.equal(actual.removeText, removeText, 'removeText:' + beforeText);
// }
// }
// };
// testIndentAction('\t/**', ' */', IndentAction.IndentOutdent, ' * ');
// testIndentAction('\t/**', '', IndentAction.None, ' * ');
// testIndentAction('\t/** * / * / * /', '', IndentAction.None, ' * ');
// testIndentAction('\t/** /*', '', IndentAction.None, ' * ');
// testIndentAction('/**', '', IndentAction.None, ' * ');
// testIndentAction('\t/**/', '', null, null);
// testIndentAction('\t/***/', '', null, null);
// testIndentAction('\t/*******/', '', null, null);
// testIndentAction('\t/** * * * * */', '', null, null);
// testIndentAction('\t/** */', '', null, null);
// testIndentAction('\t/** asdfg */', '', null, null);
// testIndentAction('\t/* asdfg */', '', null, null);
// testIndentAction('\t/* asdfg */', '', null, null);
// testIndentAction('\t/** asdfg */', '', null, null);
// testIndentAction('*/', '', null, null);
// testIndentAction('\t/*', '', null, null);
// testIndentAction('\t*', '', null, null);
// testIndentAction('\t *', '', IndentAction.None, '* ');
// testIndentAction('\t */', '', IndentAction.None, null, 1);
// testIndentAction('\t * */', '', IndentAction.None, null, 1);
// testIndentAction('\t * * / * / * / */', '', null, null);
// testIndentAction('\t * ', '', IndentAction.None, '* ');
// testIndentAction(' * ', '', IndentAction.None, '* ');
// testIndentAction(' * asdfsfagadfg', '', IndentAction.None, '* ');
// testIndentAction(' * asdfsfagadfg * * * ', '', IndentAction.None, '* ');
// testIndentAction(' * /*', '', IndentAction.None, '* ');
// testIndentAction(' * asdfsfagadfg * / * / * /', '', IndentAction.None, '* ');
// testIndentAction(' * asdfsfagadfg * / * / * /*', '', IndentAction.None, '* ');
// testIndentAction(' */', '', IndentAction.None, null, 1);
// testIndentAction('\t */', '', IndentAction.None, null, 1);
// testIndentAction('\t\t */', '', IndentAction.None, null, 1);
// testIndentAction(' */', '', IndentAction.None, null, 1);
// testIndentAction(' */', '', IndentAction.None, null, 1);
// testIndentAction('\t */', '', IndentAction.None, null, 1);
// testIndentAction(' *--------------------------------------------------------------------------------------------*/', '', IndentAction.None, null, 1);
// });
// });
\ No newline at end of file
......@@ -4067,6 +4067,7 @@ declare module monaco.languages {
*/
resolveCompletionItem?(item: CompletionItem, token: CancellationToken): CompletionItem | Thenable<CompletionItem>;
}
/**
* Describes how comments for a language work.
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册