提交 bca2236b 编写于 作者: J Johannes Rieken

normalize selected text variable when resolving it, #31124

上级 24d0f5f8
......@@ -8,7 +8,8 @@
import { basename, dirname } from 'vs/base/common/paths';
import { IModel } from 'vs/editor/common/editorCommon';
import { Selection } from 'vs/editor/common/core/selection';
import { VariableResolver, Variable } from 'vs/editor/contrib/snippet/browser/snippetParser';
import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/browser/snippetParser';
import { getLeadingWhitespace, commonPrefixLength } from 'vs/base/common/strings';
export class EditorSnippetVariableResolver implements VariableResolver {
......@@ -36,7 +37,34 @@ export class EditorSnippetVariableResolver implements VariableResolver {
const { name } = variable;
if (name === 'SELECTION' || name === 'TM_SELECTED_TEXT') {
return this._model.getValueInRange(this._selection) || undefined;
let value = this._model.getValueInRange(this._selection) || undefined;
if (value && this._selection.startLineNumber !== this._selection.endLineNumber) {
// Selection is a multiline string which we indentation we now
// need to adjust. We compare the indentation of this variable
// with the indentation at the editor position and add potential
// extra indentation to the value
const line = this._model.getLineContent(this._selection.startLineNumber);
const lineLeadingWhitespace = getLeadingWhitespace(line, 0, this._selection.startColumn - 1);
let varLeadingWhitespace = lineLeadingWhitespace;
variable.snippet.walk(marker => {
if (marker === variable) {
return false;
}
if (marker instanceof Text) {
varLeadingWhitespace = getLeadingWhitespace(marker.value.split(/\r\n|\r|\n/).pop());
}
return true;
});
const whitespaceCommonLength = commonPrefixLength(varLeadingWhitespace, lineLeadingWhitespace);
value = value.replace(
/(\r\n|\r|\n)(.*)/g,
(m, newline, rest) => `${newline}${varLeadingWhitespace.substr(whitespaceCommonLength)}${rest}`
);
}
return value;
} else if (name === 'TM_CURRENT_LINE') {
return this._model.getLineContent(this._selection.positionLineNumber);
......
......@@ -462,5 +462,53 @@ suite('SnippetSession', function () {
assert.equal(editor.getModel().getValue(), 'test 1\ntest 2\ntest 3\ntest 4\n');
});
test('Snippet variable text isn\'t whitespace normalised, #31124', function () {
editor.getModel().setValue([
'start',
'\t\t-one',
'\t\t-two',
'end'
].join('\n'));
editor.getModel().updateOptions({ insertSpaces: false });
editor.setSelection(new Selection(2, 2, 3, 7));
new SnippetSession(editor, '<div>\n\t$TM_SELECTED_TEXT\n</div>$0').insert();
let expected = [
'start',
'\t<div>',
'\t\t\t-one',
'\t\t\t-two',
'\t</div>',
'end'
].join('\n');
assert.equal(editor.getModel().getValue(), expected);
editor.getModel().setValue([
'start',
'\t\t-one',
'\t-two',
'end'
].join('\n'));
editor.getModel().updateOptions({ insertSpaces: false });
editor.setSelection(new Selection(2, 2, 3, 7));
new SnippetSession(editor, '<div>\n\t$TM_SELECTED_TEXT\n</div>$0').insert();
expected = [
'start',
'\t<div>',
'\t\t\t-one',
'\t\t-two',
'\t</div>',
'end'
].join('\n');
assert.equal(editor.getModel().getValue(), expected);
});
});
......@@ -31,59 +31,70 @@ suite('Snippet Variables Resolver', function () {
model.dispose();
});
function assertVariableResolve(resolver: EditorSnippetVariableResolver, varName: string, expected: string) {
const snippet = new SnippetParser().parse(`$${varName}`);
const variable = <Variable>snippet.children[0];
variable.resolve(resolver);
if (variable.children.length === 0) {
assert.equal(undefined, expected);
} else {
assert.equal(variable.toString(), expected);
}
}
test('editor variables, basics', function () {
assert.equal(resolver.resolve(new Variable('TM_FILENAME')), 'text.txt');
assert.equal(resolver.resolve(new Variable('something')), undefined);
assertVariableResolve(resolver, 'TM_FILENAME', 'text.txt');
assertVariableResolve(resolver, 'something', undefined);
});
test('editor variables, file/dir', function () {
assert.equal(resolver.resolve(new Variable('TM_FILENAME')), 'text.txt');
assertVariableResolve(resolver, 'TM_FILENAME', 'text.txt');
if (!isWindows) {
assert.equal(resolver.resolve(new Variable('TM_DIRECTORY')), '/foo/files');
assert.equal(resolver.resolve(new Variable('TM_FILEPATH')), '/foo/files/text.txt');
assertVariableResolve(resolver, 'TM_DIRECTORY', '/foo/files');
assertVariableResolve(resolver, 'TM_FILEPATH', '/foo/files/text.txt');
}
resolver = new EditorSnippetVariableResolver(
Model.createFromString('', undefined, undefined, URI.parse('http://www.pb.o/abc/def/ghi')),
new Selection(1, 1, 1, 1)
);
assert.equal(resolver.resolve(new Variable('TM_FILENAME')), 'ghi');
assertVariableResolve(resolver, 'TM_FILENAME', 'ghi');
if (!isWindows) {
assert.equal(resolver.resolve(new Variable('TM_DIRECTORY')), '/abc/def');
assert.equal(resolver.resolve(new Variable('TM_FILEPATH')), '/abc/def/ghi');
assertVariableResolve(resolver, 'TM_DIRECTORY', '/abc/def');
assertVariableResolve(resolver, 'TM_FILEPATH', '/abc/def/ghi');
}
resolver = new EditorSnippetVariableResolver(
Model.createFromString('', undefined, undefined, URI.parse('mem:fff.ts')),
new Selection(1, 1, 1, 1)
);
assert.equal(resolver.resolve(new Variable('TM_DIRECTORY')), '');
assert.equal(resolver.resolve(new Variable('TM_FILEPATH')), 'fff.ts');
assertVariableResolve(resolver, 'TM_DIRECTORY', '');
assertVariableResolve(resolver, 'TM_FILEPATH', 'fff.ts');
});
test('editor variables, selection', function () {
resolver = new EditorSnippetVariableResolver(model, new Selection(1, 2, 2, 3));
assert.equal(resolver.resolve(new Variable('TM_SELECTED_TEXT')), 'his is line one\nth');
assert.equal(resolver.resolve(new Variable('TM_CURRENT_LINE')), 'this is line two');
assert.equal(resolver.resolve(new Variable('TM_LINE_INDEX')), '1');
assert.equal(resolver.resolve(new Variable('TM_LINE_NUMBER')), '2');
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', 'his is line one\nth');
assertVariableResolve(resolver, 'TM_CURRENT_LINE', 'this is line two');
assertVariableResolve(resolver, 'TM_LINE_INDEX', '1');
assertVariableResolve(resolver, 'TM_LINE_NUMBER', '2');
resolver = new EditorSnippetVariableResolver(model, new Selection(2, 3, 1, 2));
assert.equal(resolver.resolve(new Variable('TM_SELECTED_TEXT')), 'his is line one\nth');
assert.equal(resolver.resolve(new Variable('TM_CURRENT_LINE')), 'this is line one');
assert.equal(resolver.resolve(new Variable('TM_LINE_INDEX')), '0');
assert.equal(resolver.resolve(new Variable('TM_LINE_NUMBER')), '1');
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', 'his is line one\nth');
assertVariableResolve(resolver, 'TM_CURRENT_LINE', 'this is line one');
assertVariableResolve(resolver, 'TM_LINE_INDEX', '0');
assertVariableResolve(resolver, 'TM_LINE_NUMBER', '1');
resolver = new EditorSnippetVariableResolver(model, new Selection(1, 2, 1, 2));
assert.equal(resolver.resolve(new Variable('TM_SELECTED_TEXT')), undefined);
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', undefined);
assert.equal(resolver.resolve(new Variable('TM_CURRENT_WORD')), 'this');
assertVariableResolve(resolver, 'TM_CURRENT_WORD', 'this');
resolver = new EditorSnippetVariableResolver(model, new Selection(3, 1, 3, 1));
assert.equal(resolver.resolve(new Variable('TM_CURRENT_WORD')), undefined);
assertVariableResolve(resolver, 'TM_CURRENT_WORD', undefined);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册