提交 4f870afa 编写于 作者: J Jackson Kearl 提交者: Ramya Rao

Enforce node boundaries in places where it matters (#53192)

* Enfoce node boundries in places where it matters

* Flip defualt emmet includeBoundries to true

Explicitly set getNode's include boundries where needed

* Remove defualt papameter

* Add update image boundry tests

* Add tests for bondries on some of the tag actions

* Rest of tag tests
上级 d8836913
......@@ -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;
}
......
......@@ -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);
......
......@@ -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 [];
}
......
......@@ -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) {
......@@ -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) {
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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)];
......@@ -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();
});
});
});
});
\ No newline at end of file
......@@ -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">
......@@ -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">
......@@ -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 = `
......@@ -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">
......@@ -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">
......@@ -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 = [
......@@ -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">
......@@ -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 = [
......@@ -298,5 +399,6 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
});
// #endregion
});
......@@ -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;
......
......@@ -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 [];
}
......
......@@ -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;
}
......@@ -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; }
......@@ -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;
......@@ -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;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册