Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce node boundaries in places where it matters #53192

Merged
merged 6 commits into from
Jun 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/emmet/src/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function balance(out: boolean) {
}

function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = getHtmlNode(document, rootNode, selection.start);
let nodeToBalance = getHtmlNode(document, rootNode, selection.start, false);
if (!nodeToBalance) {
return selection;
}
Expand Down
2 changes: 1 addition & 1 deletion extensions/emmet/src/mergeLines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function getRangesToReplace(document: vscode.TextDocument, selection: vscode.Sel
let endNodeToUpdate: Node | null;

if (selection.isEmpty) {
startNodeToUpdate = endNodeToUpdate = getNode(rootNode, selection.start);
startNodeToUpdate = endNodeToUpdate = getNode(rootNode, selection.start, true);
} else {
startNodeToUpdate = getNode(rootNode, selection.start, true);
endNodeToUpdate = getNode(rootNode, selection.end, true);
Expand Down
2 changes: 1 addition & 1 deletion extensions/emmet/src/removeTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function removeTag() {

function getRangeToRemove(editor: vscode.TextEditor, rootNode: HtmlNode, selection: vscode.Selection, indentInSpaces: string): vscode.Range[] {

let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (!nodeToUpdate) {
return [];
}
Expand Down
4 changes: 2 additions & 2 deletions extensions/emmet/src/selectItemHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getDeepestNode, findNextWord, findPrevWord, getHtmlNode } from './util'
import { HtmlNode } from 'EmmetNode';

export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd);
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd, false);
let nextNode: HtmlNode | undefined = undefined;

if (!currentNode) {
Expand Down Expand Up @@ -54,7 +54,7 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
}

export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart);
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart, false);
let prevNode: HtmlNode | undefined = undefined;

if (!currentNode) {
Expand Down
2 changes: 1 addition & 1 deletion extensions/emmet/src/selectItemStylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function nextItemStylesheet(startOffset: vscode.Position, endOffset: vsco
}

export function prevItemStylesheet(startOffset: vscode.Position, endOffset: vscode.Position, editor: vscode.TextEditor, rootNode: CssNode): vscode.Selection | undefined {
let currentNode = <CssNode>getNode(rootNode, startOffset);
let currentNode = <CssNode>getNode(rootNode, startOffset, false);
if (!currentNode) {
currentNode = rootNode;
}
Expand Down
2 changes: 1 addition & 1 deletion extensions/emmet/src/splitJoinTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function splitJoinTag() {

return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (nodeToUpdate) {
let textEdit = getRangesToReplace(editor.document, nodeToUpdate);
editBuilder.replace(textEdit.range, textEdit.newText);
Expand Down
20 changes: 20 additions & 0 deletions extensions/emmet/src/test/reflectCssValue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ suite('Tests for Emmet: Reflect CSS Value command', () => {
});
});

test('Reflect Css Value in css file, selecting entire property', function (): any {
return withRandomFileEditor(cssContents, '.css', (editor, doc) => {
editor.selections = [new Selection(5, 2, 5, 32)];
return reflectCssValue().then(() => {
assert.equal(doc.getText(), cssContents.replace(/\(50deg\)/g, '(20deg)'));
return Promise.resolve();
});
});
});

test('Reflect Css Value in html file', function (): any {
return withRandomFileEditor(htmlContents, '.html', (editor, doc) => {
editor.selections = [new Selection(7, 20, 7, 20)];
Expand All @@ -66,4 +76,14 @@ suite('Tests for Emmet: Reflect CSS Value command', () => {
});
});

test('Reflect Css Value in html file, selecting entire property', function (): any {
return withRandomFileEditor(htmlContents, '.html', (editor, doc) => {
editor.selections = [new Selection(7, 4, 7, 34)];
return reflectCssValue().then(() => {
assert.equal(doc.getText(), htmlContents.replace(/\(50deg\)/g, '(20deg)'));
return Promise.resolve();
});
});
});

});
104 changes: 103 additions & 1 deletion extensions/emmet/src/test/tagActions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,31 @@ suite('Tests for Emmet actions on html tags', () => {
});
});

// #region update tag
test('update tag with entire node selected', () => {
const expectedContents = `
<div class="hello">
<ul>
<li><section>Hello</section></li>
<li><span>There</span></li>
<section><li><span>Bye</span></li></section>
</ul>
<span/>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25),
new Selection(5, 3, 5, 39),
];

return updateTag('section')!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});

test('update tag with template', () => {
const expectedContents = `
<script type="text/template">
Expand All @@ -89,8 +114,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion


// #region remove tag
test('remove tag with mutliple cursors', () => {
const expectedContents = `
<div class="hello">
Expand All @@ -116,6 +142,31 @@ suite('Tests for Emmet actions on html tags', () => {
});
});

test('remove tag with boundary conditions', () => {
const expectedContents = `
<div class="hello">
<ul>
<li>Hello</li>
<li><span>There</span></li>
<li><span>Bye</span></li>
</ul>
<span/>
</div>
`;

return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25),
new Selection(5, 3, 5, 39),
];

return removeTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});


test('remove tag with template', () => {
const expectedContents = `
Expand All @@ -139,7 +190,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion

// #region split/join tag
test('split/join tag with mutliple cursors', () => {
const expectedContents = `
<div class="hello">
Expand All @@ -164,6 +217,30 @@ suite('Tests for Emmet actions on html tags', () => {
});
});

test('split/join tag with boundary selection', () => {
const expectedContents = `
<div class="hello">
<ul>
<li><span/></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
</ul>
<span></span>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 7, 3, 25), // join tag
new Selection(7, 2, 7, 9), // split tag
];

return splitJoinTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});

test('split/join tag with templates', () => {
const expectedContents = `
<script type="text/template">
Expand Down Expand Up @@ -214,7 +291,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion

// #region match tag
test('match tag with mutliple cursors', () => {
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
Expand Down Expand Up @@ -265,6 +344,9 @@ suite('Tests for Emmet actions on html tags', () => {
});
});

// #endregion

// #region merge lines
test('merge lines of tag with children when empty selection', () => {
const expectedContents = `
<div class="hello">
Expand All @@ -284,6 +366,25 @@ suite('Tests for Emmet actions on html tags', () => {
});
});

test('merge lines of tag with children when full node selection', () => {
const expectedContents = `
<div class="hello">
<ul><li><span>Hello</span></li><li><span>There</span></li><div><li><span>Bye</span></li></div></ul>
<span/>
</div>
`;
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
new Selection(2, 3, 6, 7)
];

return mergeLines()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});

test('merge lines is no-op when start and end nodes are on the same line', () => {
return withRandomFileEditor(contents, 'html', (editor, doc) => {
editor.selections = [
Expand All @@ -298,5 +399,6 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
});

4 changes: 2 additions & 2 deletions extensions/emmet/src/updateImageSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ function updateImageSizeHTML(editor: TextEditor, position: Position): Promise<Te
function updateImageSizeStyleTag(editor: TextEditor, position: Position): Promise<TextEdit[] | undefined> {
const getPropertyInsiderStyleTag = (editor: TextEditor): Property | null => {
const rootNode = parseDocument(editor.document);
const currentNode = <HtmlNode>getNode(rootNode, position);
const currentNode = <HtmlNode>getNode(rootNode, position, true);
if (currentNode && currentNode.name === 'style'
&& currentNode.open.end.isBefore(position)
&& currentNode.close.start.isAfter(position)) {
let buffer = new DocumentStreamReader(editor.document, currentNode.open.end, new Range(currentNode.open.end, currentNode.close.start));
let rootNode = parseStylesheet(buffer);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);
return (node && node.type === 'property') ? <Property>node : null;
}
return null;
Expand Down
2 changes: 1 addition & 1 deletion extensions/emmet/src/updateTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function updateTag(tagName: string): Thenable<boolean> | undefined {
}

function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: HtmlNode): vscode.Range[] {
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start, true);
if (!nodeToUpdate) {
return [];
}
Expand Down
8 changes: 4 additions & 4 deletions extensions/emmet/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function findClosingCommentAfterPosition(document: vscode.TextDocument, position
/**
* Returns node corresponding to given position in the given root node
*/
export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false) {
export function getNode(root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean) {
if (!root) {
return null;
}
Expand All @@ -310,7 +310,7 @@ export function getNode(root: Node | undefined, position: vscode.Position, inclu
return foundNode;
}

export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false): HtmlNode | undefined {
export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean): HtmlNode | undefined {
let currentNode = <HtmlNode>getNode(root, position, includeNodeBoundary);
if (!currentNode) { return; }

Expand Down Expand Up @@ -532,7 +532,7 @@ export function getCssPropertyFromRule(rule: Rule, name: string): Property | und
*/
export function getCssPropertyFromDocument(editor: vscode.TextEditor, position: vscode.Position): Property | null | undefined {
const rootNode = parseDocument(editor.document);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);

if (isStyleSheet(editor.document.languageId)) {
return node && node.type === 'property' ? <Property>node : null;
Expand All @@ -545,7 +545,7 @@ export function getCssPropertyFromDocument(editor: vscode.TextEditor, position:
&& htmlNode.close.start.isAfter(position)) {
let buffer = new DocumentStreamReader(editor.document, htmlNode.start, new vscode.Range(htmlNode.start, htmlNode.end));
let rootNode = parseStylesheet(buffer);
const node = getNode(rootNode, position);
const node = getNode(rootNode, position, true);
return (node && node.type === 'property') ? <Property>node : null;
}
}
Expand Down