Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)

This commit is contained in:
Anthony Dresser
2019-08-20 21:07:47 -07:00
committed by GitHub
parent 1f00249646
commit ecb80f14f0
221 changed files with 3140 additions and 1552 deletions

View File

@@ -3998,8 +3998,12 @@ suite('autoClosingPairs', () => {
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
{ open: '\"', close: '\"', notIn: ['string'] },
{ open: '`', close: '`', notIn: ['string', 'comment'] },
{ open: '/**', close: ' */', notIn: ['string'] }
{ open: '/**', close: ' */', notIn: ['string'] },
{ open: 'begin', close: 'end', notIn: ['string'] }
],
__electricCharacterSupport: {
docComment: { open: '/**', close: ' */' }
}
}));
}
@@ -4439,6 +4443,28 @@ suite('autoClosingPairs', () => {
mode.dispose();
});
test('multi-character autoclose', () => {
let mode = new AutoClosingMode();
usingCursor({
text: [
'',
],
languageIdentifier: mode.getLanguageIdentifier()
}, (model, cursor) => {
model.setValue('begi');
cursor.setSelections('test', [new Selection(1, 5, 1, 5)]);
cursorCommand(cursor, H.Type, { text: 'n' }, 'keyboard');
assert.strictEqual(model.getLineContent(1), 'beginend');
model.setValue('/*');
cursor.setSelections('test', [new Selection(1, 3, 1, 3)]);
cursorCommand(cursor, H.Type, { text: '*' }, 'keyboard');
assert.strictEqual(model.getLineContent(1), '/** */');
});
mode.dispose();
});
test('issue #55314: Do not auto-close when ending with open', () => {
const languageId = new LanguageIdentifier('myElectricMode', 5);
class ElectricMode extends MockMode {
@@ -4477,7 +4503,7 @@ suite('autoClosingPairs', () => {
model.forceTokenization(model.getLineCount());
assertType(model, cursor, 3, 4, '"', '"', `does not double quote when ending with open`);
model.forceTokenization(model.getLineCount());
assertType(model, cursor, 4, 2, '"', '""', `double quote when ending with open`);
assertType(model, cursor, 4, 2, '"', '"', `does not double quote when ending with open`);
model.forceTokenization(model.getLineCount());
assertType(model, cursor, 4, 3, '"', '"', `does not double quote when ending with open`);
});
@@ -4772,31 +4798,18 @@ suite('autoClosingPairs', () => {
// on the mac US intl kb layout
// Typing ` + space
// Typing ' + space
cursorCommand(cursor, H.CompositionStart, null, 'keyboard');
cursorCommand(cursor, H.Type, { text: '\'' }, 'keyboard');
cursorCommand(cursor, H.ReplacePreviousChar, { replaceCharCnt: 1, text: '\'' }, 'keyboard');
cursorCommand(cursor, H.CompositionEnd, null, 'keyboard');
assert.equal(model.getValue(), '\'\'');
// Typing " + space within string
cursor.setSelections('test', [new Selection(1, 2, 1, 2)]);
cursorCommand(cursor, H.CompositionStart, null, 'keyboard');
cursorCommand(cursor, H.Type, { text: '"' }, 'keyboard');
cursorCommand(cursor, H.ReplacePreviousChar, { replaceCharCnt: 1, text: '"' }, 'keyboard');
cursorCommand(cursor, H.CompositionEnd, null, 'keyboard');
assert.equal(model.getValue(), '\'"\'');
// Typing ' + space after '
model.setValue('\'');
cursor.setSelections('test', [new Selection(1, 2, 1, 2)]);
// Typing one more ' + space
cursorCommand(cursor, H.CompositionStart, null, 'keyboard');
cursorCommand(cursor, H.Type, { text: '\'' }, 'keyboard');
cursorCommand(cursor, H.ReplacePreviousChar, { replaceCharCnt: 1, text: '\'' }, 'keyboard');
cursorCommand(cursor, H.CompositionEnd, null, 'keyboard');
assert.equal(model.getValue(), '\'\'');
// Typing ' as a closing tag

View File

@@ -7,6 +7,10 @@ import { URI } from 'vs/base/common/uri';
import { OpenerService } from 'vs/editor/browser/services/openerService';
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands';
import { deepClone } from 'vs/base/common/objects';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IProductService } from 'vs/platform/product/common/product';
import { IStorageService } from 'vs/platform/storage/common/storage';
suite('OpenerService', function () {
@@ -24,19 +28,77 @@ suite('OpenerService', function () {
}
};
function getStorageService(trustedDomainsSetting: string[]) {
let _settings = deepClone(trustedDomainsSetting);
return new class implements IStorageService {
get = () => JSON.stringify(_settings);
store = (key: string, val: string) => _settings = JSON.parse(val);
// Don't care
_serviceBrand: any;
onDidChangeStorage = () => ({ dispose: () => { } });
onWillSaveState = () => ({ dispose: () => { } });
getBoolean = () => true;
getNumber = () => 0;
remove = () => { };
logStorage = () => { };
};
}
function getDialogService() {
return new class implements IDialogService {
_showInvoked = 0;
show = () => {
this._showInvoked++;
return Promise.resolve({} as any);
}
get confirmInvoked() { return this._showInvoked; }
// Don't care
_serviceBrand: any;
confirm = () => {
return Promise.resolve({} as any);
}
};
}
function getProductService(): IProductService {
return new class {
nameShort: 'VS Code';
_serviceBrand: any;
} as IProductService;
}
setup(function () {
lastCommand = undefined;
});
test('delegate to editorService, scheme:///fff', function () {
const openerService = new OpenerService(editorService, NullCommandService);
const openerService = new OpenerService(
editorService,
NullCommandService,
getStorageService([]),
getDialogService(),
getProductService()
);
openerService.open(URI.parse('another:///somepath'));
assert.equal(editorService.lastInput!.options!.selection, undefined);
});
test('delegate to editorService, scheme:///fff#L123', function () {
const openerService = new OpenerService(editorService, NullCommandService);
const openerService = new OpenerService(
editorService,
NullCommandService,
getStorageService([]),
getDialogService(),
getProductService()
);
openerService.open(URI.parse('file:///somepath#L23'));
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
@@ -59,7 +121,13 @@ suite('OpenerService', function () {
test('delegate to editorService, scheme:///fff#123,123', function () {
const openerService = new OpenerService(editorService, NullCommandService);
const openerService = new OpenerService(
editorService,
NullCommandService,
getStorageService([]),
getDialogService(),
getProductService()
);
openerService.open(URI.parse('file:///somepath#23'));
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
@@ -78,7 +146,13 @@ suite('OpenerService', function () {
test('delegate to commandsService, command:someid', function () {
const openerService = new OpenerService(editorService, commandService);
const openerService = new OpenerService(
editorService,
commandService,
getStorageService([]),
getDialogService(),
getProductService()
);
const id = `aCommand${Math.random()}`;
CommandsRegistry.registerCommand(id, function () { });
@@ -98,4 +172,70 @@ suite('OpenerService', function () {
assert.equal(lastCommand!.args[0], 12);
assert.equal(lastCommand!.args[1], true);
});
test('links are protected by dialog.show', function () {
const dialogService = getDialogService();
const openerService = new OpenerService(
editorService,
commandService,
getStorageService([]),
dialogService,
getProductService()
);
openerService.open(URI.parse('https://www.microsoft.com'));
assert.equal(dialogService.confirmInvoked, 1);
});
test('links on the whitelisted domains can be opened without dialog.show', function () {
const dialogService = getDialogService();
const openerService = new OpenerService(
editorService,
commandService,
getStorageService(['https://microsoft.com']),
dialogService,
getProductService()
);
openerService.open(URI.parse('https://microsoft.com'));
openerService.open(URI.parse('https://microsoft.com/'));
openerService.open(URI.parse('https://microsoft.com/en-us/'));
openerService.open(URI.parse('https://microsoft.com/en-us/?foo=bar'));
openerService.open(URI.parse('https://microsoft.com/en-us/?foo=bar#baz'));
assert.equal(dialogService.confirmInvoked, 0);
});
test('variations of links are protected by dialog confirmation', function () {
const dialogService = getDialogService();
const openerService = new OpenerService(
editorService,
commandService,
getStorageService(['https://microsoft.com']),
dialogService,
getProductService()
);
openerService.open(URI.parse('http://microsoft.com'));
openerService.open(URI.parse('https://www.microsoft.com'));
assert.equal(dialogService.confirmInvoked, 2);
});
test('* removes all link protection', function () {
const dialogService = getDialogService();
const openerService = new OpenerService(
editorService,
commandService,
getStorageService(['*']),
dialogService,
getProductService()
);
openerService.open(URI.parse('https://code.visualstudio.com/'));
openerService.open(URI.parse('https://www.microsoft.com'));
openerService.open(URI.parse('https://www.github.com'));
assert.equal(dialogService.confirmInvoked, 0);
});
});

View File

@@ -7,6 +7,7 @@ import * as assert from 'assert';
import { StandardTokenType } from 'vs/editor/common/modes';
import { CharacterPairSupport } from 'vs/editor/common/modes/supports/characterPair';
import { TokenText, createFakeScopedLineTokens } from 'vs/editor/test/common/modesTestUtils';
import { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
suite('CharacterPairSupport', () => {
@@ -52,8 +53,21 @@ suite('CharacterPairSupport', () => {
assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []);
});
function findAutoClosingPair(characterPairSupport: CharacterPairSupport, character: string): StandardAutoClosingPairConditional | null {
for (const autoClosingPair of characterPairSupport.getAutoClosingPairs()) {
if (autoClosingPair.open === character) {
return autoClosingPair;
}
}
return null;
}
function testShouldAutoClose(characterPairSupport: CharacterPairSupport, line: TokenText[], character: string, column: number): boolean {
return characterPairSupport.shouldAutoClosePair(character, createFakeScopedLineTokens(line), column);
const autoClosingPair = findAutoClosingPair(characterPairSupport, character);
if (!autoClosingPair) {
return false;
}
return CharacterPairSupport.shouldAutoClosePair(autoClosingPair, createFakeScopedLineTokens(line), column);
}
test('shouldAutoClosePair in empty line', () => {

View File

@@ -21,86 +21,20 @@ suite('Editor Modes - Auto Indentation', () => {
assert.deepEqual(actual, null);
}
function testAppends(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, appendText: string): void {
let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset);
assert.deepEqual(actual, { appendText: appendText });
}
function testMatchBracket(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, matchOpenBracket: string): void {
let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset);
assert.deepEqual(actual, { matchOpenBracket: matchOpenBracket });
}
test('Doc comments', () => {
let brackets = new BracketElectricCharacterSupport(null, [{ open: '/**', close: ' */' }], null);
testAppends(brackets, [
{ text: '/*', type: StandardTokenType.Other },
], '*', 3, ' */');
testDoesNothing(brackets, [
{ text: '/*', type: StandardTokenType.Other },
{ text: ' ', type: StandardTokenType.Other },
{ text: '*/', type: StandardTokenType.Other },
], '*', 3);
});
test('getElectricCharacters uses all sources and dedups', () => {
let sup = new BracketElectricCharacterSupport(
new RichEditBrackets(fakeLanguageIdentifier, [
['{', '}'],
['(', ')']
]), [
{ open: '{', close: '}', notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string', 'comment'] },
{ open: 'begin', close: 'end', notIn: ['string'] }
],
{ docComment: { open: '/**', close: ' */' } }
])
);
assert.deepEqual(sup.getElectricCharacters(), ['}', ')', 'n', '*']);
});
test('auto-close', () => {
let sup = new BracketElectricCharacterSupport(
new RichEditBrackets(fakeLanguageIdentifier, [
['{', '}'],
['(', ')']
]), [
{ open: '{', close: '}', notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string', 'comment'] },
{ open: 'begin', close: 'end', notIn: ['string'] }
],
{ docComment: { open: '/**', close: ' */' } }
);
testDoesNothing(sup, [], 'a', 0);
testDoesNothing(sup, [{ text: 'egi', type: StandardTokenType.Other }], 'b', 1);
testDoesNothing(sup, [{ text: 'bgi', type: StandardTokenType.Other }], 'e', 2);
testDoesNothing(sup, [{ text: 'bei', type: StandardTokenType.Other }], 'g', 3);
testDoesNothing(sup, [{ text: 'beg', type: StandardTokenType.Other }], 'i', 4);
testDoesNothing(sup, [{ text: 'egin', type: StandardTokenType.Other }], 'b', 1);
testDoesNothing(sup, [{ text: 'bgin', type: StandardTokenType.Other }], 'e', 2);
testDoesNothing(sup, [{ text: 'bein', type: StandardTokenType.Other }], 'g', 3);
testDoesNothing(sup, [{ text: 'begn', type: StandardTokenType.Other }], 'i', 4);
testAppends(sup, [{ text: 'begi', type: StandardTokenType.Other }], 'n', 5, 'end');
testDoesNothing(sup, [{ text: '3gin', type: StandardTokenType.Other }], 'b', 1);
testDoesNothing(sup, [{ text: 'bgin', type: StandardTokenType.Other }], '3', 2);
testDoesNothing(sup, [{ text: 'b3in', type: StandardTokenType.Other }], 'g', 3);
testDoesNothing(sup, [{ text: 'b3gn', type: StandardTokenType.Other }], 'i', 4);
testDoesNothing(sup, [{ text: 'b3gi', type: StandardTokenType.Other }], 'n', 5);
testDoesNothing(sup, [{ text: 'begi', type: StandardTokenType.String }], 'n', 5);
testAppends(sup, [{ text: '"', type: StandardTokenType.String }, { text: 'begi', type: StandardTokenType.Other }], 'n', 6, 'end');
testDoesNothing(sup, [{ text: '"', type: StandardTokenType.String }, { text: 'begi', type: StandardTokenType.String }], 'n', 6);
testAppends(sup, [{ text: '/*', type: StandardTokenType.String }], '*', 3, ' */');
testDoesNothing(sup, [{ text: 'begi', type: StandardTokenType.Other }, { text: 'end', type: StandardTokenType.Other }], 'n', 5);
assert.deepEqual(sup.getElectricCharacters(), ['}', ')']);
});
test('matchOpenBracket', () => {
@@ -108,12 +42,7 @@ suite('Editor Modes - Auto Indentation', () => {
new RichEditBrackets(fakeLanguageIdentifier, [
['{', '}'],
['(', ')']
]), [
{ open: '{', close: '}', notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string', 'comment'] },
{ open: 'begin', close: 'end', notIn: ['string'] }
],
{ docComment: { open: '/**', close: ' */' } }
])
);
testDoesNothing(sup, [{ text: '\t{', type: StandardTokenType.Other }], '\t', 1);