提交 21c02bad 编写于 作者: J Jackson Kearl 提交者: Ramya Rao

Enable emmet to function inside script templates. #51180 (#51256)

上级 0493de9e
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { HtmlNode } from 'EmmetNode';
import { getNode, parseDocument, validate } from './util';
import { getHtmlNode, parseDocument, validate } from './util';
let balanceOutStack: Array<vscode.Selection[]> = [];
let lastOut = false;
......@@ -61,7 +61,7 @@ function balance(out: boolean) {
}
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start);
let nodeToBalance = getHtmlNode(document, rootNode, selection.start);
if (!nodeToBalance) {
return selection;
}
......@@ -82,7 +82,7 @@ function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.S
}
function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start, true);
let nodeToBalance = getHtmlNode(document, rootNode, selection.start, true);
if (!nodeToBalance) {
return selection;
}
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { parseDocument, validate, getNode } from './util';
import { parseDocument, validate, getHtmlNode } from './util';
import { HtmlNode } from 'EmmetNode';
export function removeTag() {
......@@ -38,7 +38,7 @@ export function removeTag() {
function getRangeToRemove(editor: vscode.TextEditor, rootNode: HtmlNode, selection: vscode.Selection, indentInSpaces: string): vscode.Range[] {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
if (!nodeToUpdate) {
return [];
}
......
......@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
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 = <HtmlNode>getNode(rootNode, selectionEnd);
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd);
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 = <HtmlNode>getNode(rootNode, selectionStart);
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart);
let prevNode: HtmlNode | undefined = undefined;
if (!currentNode) {
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { HtmlNode } from 'EmmetNode';
import { getNode, parseDocument, validate, getEmmetMode, getEmmetConfiguration } from './util';
import { getHtmlNode, parseDocument, validate, getEmmetMode, getEmmetConfiguration } from './util';
export function splitJoinTag() {
if (!validate(false) || !vscode.window.activeTextEditor) {
......@@ -20,7 +20,7 @@ export function splitJoinTag() {
return editor.edit(editBuilder => {
editor.selections.reverse().forEach(selection => {
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
if (nodeToUpdate) {
let textEdit = getRangesToReplace(editor.document, nodeToUpdate);
editBuilder.replace(textEdit.range, textEdit.newText);
......
......@@ -19,7 +19,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
margin: 20px 10px;
background-image: url('tryme.png');
}
.boo .hoo {
margin: 10px;
}
......@@ -46,7 +46,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
</head>
<body>
<div>
\t\t
</div>
<div class="header">
<ul class="nav main">
......@@ -113,6 +113,43 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
});
});
test('Emmet Next/Prev Item in html template', function (): any {
const templateContents = `
<script type="text/template">
<div class="header">
<ul class="nav main">
</ul>
</div>
</script>
`;
return withRandomFileEditor(templateContents, '.html', (editor, doc) => {
editor.selections = [new Selection(2, 2, 2, 2)];
let expectedNextItemPoints: [number, number, number][] = [
[2, 2, 5], // div
[2, 6, 20], // class="header"
[2, 13, 19], // header
[3, 3, 5], // ul
[3, 6, 22], // class="nav main"
[3, 13, 21], // nav main
[3, 13, 16], // nav
[3, 17, 21], // main
];
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
fetchSelectItem('next');
testSelection(editor.selection, colstart, line, colend);
});
editor.selections = [new Selection(4, 1, 4, 1)];
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
fetchSelectItem('prev');
testSelection(editor.selection, colstart, line, colend);
});
return Promise.resolve();
});
});
test('Emmet Select Next/Prev Item in css file', function (): any {
return withRandomFileEditor(cssContents, '.css', (editor, doc) => {
editor.selections = [new Selection(0, 0, 0, 0)];
......@@ -240,6 +277,42 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
});
});
test('Emmet Balance In/Out in html template', function (): any {
const htmlTemplate = `
<script type="text/html">
<div class="header">
<ul class="nav main">
<li class="item1">Item 1</li>
<li class="item2">Item 2</li>
</ul>
</div>
</script>`;
return withRandomFileEditor(htmlTemplate, 'html', (editor, doc) => {
editor.selections = [new Selection(5, 24, 5, 24)];
let expectedBalanceOutRanges: [number, number, number, number][] = [
[5, 20, 5, 26], // <li class="item1">``Item 2''</li>
[5, 2, 5, 31], // ``<li class="item1">Item 2</li>''
[3, 22, 6, 1], // inner contents of ul
[3, 1, 6, 6], // outer contents of ul
[2, 20, 7, 0], // inner contents of div
[2, 0, 7, 6], // outer contents of div
];
expectedBalanceOutRanges.forEach(([linestart, colstart, lineend, colend]) => {
balanceOut();
testSelection(editor.selection, colstart, linestart, colend, lineend);
});
expectedBalanceOutRanges.pop();
expectedBalanceOutRanges.reverse().forEach(([linestart, colstart, lineend, colend]) => {
balanceIn();
testSelection(editor.selection, colstart, linestart, colend, lineend);
});
return Promise.resolve();
});
});
});
function testSelection(selection: Selection, startChar: number, startline: number, endChar?: number, endLine?: number) {
......
......@@ -30,6 +30,17 @@ suite('Tests for Emmet actions on html tags', () => {
</div>
`;
let contentsWithTemplate = `
<script type="text/template">
<ul>
<li><span>Hello</span></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
</ul>
<span/>
</script>
`;
test('update tag with multiple cursors', () => {
const expectedContents = `
<div class="hello">
......@@ -55,6 +66,30 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('update tag with template', () => {
const expectedContents = `
<script type="text/template">
<section>
<li><span>Hello</span></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
</section>
<span/>
</script>
`;
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
editor.selections = [
new Selection(2, 4, 2, 4), // cursor inside ul tag
];
return updateTag('section')!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('remove tag with mutliple cursors', () => {
const expectedContents = `
......@@ -81,6 +116,30 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('remove tag with template', () => {
const expectedContents = `
<script type="text/template">
\t\t
<li><span>Hello</span></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
\t
<span/>
</script>
`;
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
editor.selections = [
new Selection(2, 4, 2, 4), // cursor inside ul tag
];
return removeTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('split/join tag with mutliple cursors', () => {
const expectedContents = `
<div class="hello">
......@@ -105,6 +164,30 @@ suite('Tests for Emmet actions on html tags', () => {
});
});
test('split/join tag with templates', () => {
const expectedContents = `
<script type="text/template">
<ul>
<li><span/></li>
<li><span>There</span></li>
<div><li><span>Bye</span></li></div>
</ul>
<span></span>
</script>
`;
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
editor.selections = [
new Selection(3, 17, 3, 17), // join tag
new Selection(7, 5, 7, 5), // split tag
];
return splitJoinTag()!.then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
test('split/join tag in jsx with xhtml self closing tag', () => {
const expectedContents = `
<div class="hello">
......
......@@ -247,6 +247,36 @@ suite('Tests for Toggle Comment action from Emmet (HTML)', () => {
});
});
});
test('toggle comment within script template', () => {
const templateContents = `
<script type="text/template">
<li><span>Hello</span></li>
<li><!--<span>There</span>--></li>
<div><li><span>Bye</span></li></div>
<span/>
</script>
`;
const expectedContents = `
<script type="text/template">
<!--<li><span>Hello</span></li>-->
<li><span>There</span></li>
<div><li><!--<span>Bye</span>--></li></div>
<span/>
</script>
`;
return withRandomFileEditor(templateContents, 'html', (editor, doc) => {
editor.selections = [
new Selection(2, 2, 2, 28), // select entire li element
new Selection(3, 17, 3, 17), // cursor inside the commented span
new Selection(4, 18, 4, 18), // cursor inside the noncommented span
];
return toggleComment().then(() => {
assert.equal(doc.getText(), expectedContents);
return Promise.resolve();
});
});
});
});
suite('Tests for Toggle Comment action from Emmet (CSS)', () => {
......@@ -541,7 +571,7 @@ suite('Tests for Toggle Comment action from Emmet in nested css (SCSS)', () => {
assert.equal(doc.getText(), expectedContents);
return toggleComment().then(() => {
assert.equal(doc.getText(), contents);
return Promise.resolve();
return Promise.resolve();
});
});
});
......
......@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getNodesInBetween, getNode, parseDocument, sameNodes, isStyleSheet, validate } from './util';
import { Node, Stylesheet, Rule, HtmlNode } from 'EmmetNode';
import { getNodesInBetween, getNode, getHtmlNode, parseDocument, sameNodes, isStyleSheet, validate } from './util';
import { Node, Stylesheet, Rule } from 'EmmetNode';
import parseStylesheet from '@emmetio/css-parser';
import { DocumentStreamReader } from './bufferStream';
......@@ -63,8 +63,8 @@ function toggleCommentHTML(document: vscode.TextDocument, selection: vscode.Sele
const selectionStart = selection.isReversed ? selection.active : selection.anchor;
const selectionEnd = selection.isReversed ? selection.anchor : selection.active;
let startNode = <HtmlNode>getNode(rootNode, selectionStart, true);
let endNode = <HtmlNode>getNode(rootNode, selectionEnd, true);
let startNode = getHtmlNode(document, rootNode, selectionStart, true);
let endNode = getHtmlNode(document, rootNode, selectionEnd, true);
if (!startNode || !endNode) {
return [];
......
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { HtmlNode } from 'EmmetNode';
import { getNode, parseDocument, validate } from './util';
import { getHtmlNode, parseDocument, validate } from './util';
export function updateTag(tagName: string): Thenable<boolean> | undefined {
if (!validate(false) || !vscode.window.activeTextEditor) {
......@@ -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 = <HtmlNode>getNode(rootNode, selection.start);
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
if (!nodeToUpdate) {
return [];
}
......
......@@ -311,7 +311,7 @@ export function getNode(root: Node | undefined, position: vscode.Position, inclu
}
export function getHtmlNode(document: vscode.TextDocument, root: Node | undefined, position: vscode.Position, includeNodeBoundary: boolean = false): HtmlNode | undefined {
let currentNode = <HtmlNode>getNode(root, position, true);
let currentNode = <HtmlNode>getNode(root, position, includeNodeBoundary);
if (!currentNode) { return; }
if (isTemplateScript(currentNode) && currentNode.close &&
......@@ -321,7 +321,7 @@ export function getHtmlNode(document: vscode.TextDocument, root: Node | undefine
try {
let scriptInnerNodes = parse(buffer);
currentNode = <HtmlNode>getNode(scriptInnerNodes, position, true) || currentNode;
currentNode = <HtmlNode>getNode(scriptInnerNodes, position, includeNodeBoundary) || currentNode;
} catch (e) { }
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册