Skip to content

Commit 21c02ba

Browse files
Jackson Kearlramya-rao-a
authored andcommitted
Enable emmet to function inside script templates. microsoft#51180 (microsoft#51256)
1 parent 0493de9 commit 21c02ba

10 files changed

Lines changed: 207 additions & 21 deletions

extensions/emmet/src/balance.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode';
77
import { HtmlNode } from 'EmmetNode';
8-
import { getNode, parseDocument, validate } from './util';
8+
import { getHtmlNode, parseDocument, validate } from './util';
99

1010
let balanceOutStack: Array<vscode.Selection[]> = [];
1111
let lastOut = false;
@@ -61,7 +61,7 @@ function balance(out: boolean) {
6161
}
6262

6363
function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
64-
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start);
64+
let nodeToBalance = getHtmlNode(document, rootNode, selection.start);
6565
if (!nodeToBalance) {
6666
return selection;
6767
}
@@ -82,7 +82,7 @@ function getRangeToBalanceOut(document: vscode.TextDocument, selection: vscode.S
8282
}
8383

8484
function getRangeToBalanceIn(document: vscode.TextDocument, selection: vscode.Selection, rootNode: HtmlNode): vscode.Selection {
85-
let nodeToBalance = <HtmlNode>getNode(rootNode, selection.start, true);
85+
let nodeToBalance = getHtmlNode(document, rootNode, selection.start, true);
8686
if (!nodeToBalance) {
8787
return selection;
8888
}

extensions/emmet/src/removeTag.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { parseDocument, validate, getNode } from './util';
7+
import { parseDocument, validate, getHtmlNode } from './util';
88
import { HtmlNode } from 'EmmetNode';
99

1010
export function removeTag() {
@@ -38,7 +38,7 @@ export function removeTag() {
3838

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

41-
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
41+
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
4242
if (!nodeToUpdate) {
4343
return [];
4444
}

extensions/emmet/src/selectItemHTML.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { getDeepestNode, findNextWord, findPrevWord, getNode } from './util';
7+
import { getDeepestNode, findNextWord, findPrevWord, getHtmlNode } from './util';
88
import { HtmlNode } from 'EmmetNode';
99

1010
export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
11-
let currentNode = <HtmlNode>getNode(rootNode, selectionEnd);
11+
let currentNode = getHtmlNode(editor.document, rootNode, selectionEnd);
1212
let nextNode: HtmlNode | undefined = undefined;
1313

1414
if (!currentNode) {
@@ -54,7 +54,7 @@ export function nextItemHTML(selectionStart: vscode.Position, selectionEnd: vsco
5454
}
5555

5656
export function prevItemHTML(selectionStart: vscode.Position, selectionEnd: vscode.Position, editor: vscode.TextEditor, rootNode: HtmlNode): vscode.Selection | undefined {
57-
let currentNode = <HtmlNode>getNode(rootNode, selectionStart);
57+
let currentNode = getHtmlNode(editor.document, rootNode, selectionStart);
5858
let prevNode: HtmlNode | undefined = undefined;
5959

6060
if (!currentNode) {

extensions/emmet/src/splitJoinTag.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode';
77
import { HtmlNode } from 'EmmetNode';
8-
import { getNode, parseDocument, validate, getEmmetMode, getEmmetConfiguration } from './util';
8+
import { getHtmlNode, parseDocument, validate, getEmmetMode, getEmmetConfiguration } from './util';
99

1010
export function splitJoinTag() {
1111
if (!validate(false) || !vscode.window.activeTextEditor) {
@@ -20,7 +20,7 @@ export function splitJoinTag() {
2020

2121
return editor.edit(editBuilder => {
2222
editor.selections.reverse().forEach(selection => {
23-
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
23+
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
2424
if (nodeToUpdate) {
2525
let textEdit = getRangesToReplace(editor.document, nodeToUpdate);
2626
editBuilder.replace(textEdit.range, textEdit.newText);

extensions/emmet/src/test/editPointSelectItemBalance.test.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
1919
margin: 20px 10px;
2020
background-image: url('tryme.png');
2121
}
22-
22+
2323
.boo .hoo {
2424
margin: 10px;
2525
}
@@ -46,7 +46,7 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
4646
</head>
4747
<body>
4848
<div>
49-
49+
\t\t
5050
</div>
5151
<div class="header">
5252
<ul class="nav main">
@@ -113,6 +113,43 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
113113
});
114114
});
115115

116+
test('Emmet Next/Prev Item in html template', function (): any {
117+
const templateContents = `
118+
<script type="text/template">
119+
<div class="header">
120+
<ul class="nav main">
121+
</ul>
122+
</div>
123+
</script>
124+
`;
125+
return withRandomFileEditor(templateContents, '.html', (editor, doc) => {
126+
editor.selections = [new Selection(2, 2, 2, 2)];
127+
128+
let expectedNextItemPoints: [number, number, number][] = [
129+
[2, 2, 5], // div
130+
[2, 6, 20], // class="header"
131+
[2, 13, 19], // header
132+
[3, 3, 5], // ul
133+
[3, 6, 22], // class="nav main"
134+
[3, 13, 21], // nav main
135+
[3, 13, 16], // nav
136+
[3, 17, 21], // main
137+
];
138+
expectedNextItemPoints.forEach(([line, colstart, colend]) => {
139+
fetchSelectItem('next');
140+
testSelection(editor.selection, colstart, line, colend);
141+
});
142+
143+
editor.selections = [new Selection(4, 1, 4, 1)];
144+
expectedNextItemPoints.reverse().forEach(([line, colstart, colend]) => {
145+
fetchSelectItem('prev');
146+
testSelection(editor.selection, colstart, line, colend);
147+
});
148+
149+
return Promise.resolve();
150+
});
151+
});
152+
116153
test('Emmet Select Next/Prev Item in css file', function (): any {
117154
return withRandomFileEditor(cssContents, '.css', (editor, doc) => {
118155
editor.selections = [new Selection(0, 0, 0, 0)];
@@ -240,6 +277,42 @@ suite('Tests for Next/Previous Select/Edit point and Balance actions', () => {
240277
});
241278
});
242279

280+
test('Emmet Balance In/Out in html template', function (): any {
281+
const htmlTemplate = `
282+
<script type="text/html">
283+
<div class="header">
284+
<ul class="nav main">
285+
<li class="item1">Item 1</li>
286+
<li class="item2">Item 2</li>
287+
</ul>
288+
</div>
289+
</script>`;
290+
291+
return withRandomFileEditor(htmlTemplate, 'html', (editor, doc) => {
292+
293+
editor.selections = [new Selection(5, 24, 5, 24)];
294+
let expectedBalanceOutRanges: [number, number, number, number][] = [
295+
[5, 20, 5, 26], // <li class="item1">``Item 2''</li>
296+
[5, 2, 5, 31], // ``<li class="item1">Item 2</li>''
297+
[3, 22, 6, 1], // inner contents of ul
298+
[3, 1, 6, 6], // outer contents of ul
299+
[2, 20, 7, 0], // inner contents of div
300+
[2, 0, 7, 6], // outer contents of div
301+
];
302+
expectedBalanceOutRanges.forEach(([linestart, colstart, lineend, colend]) => {
303+
balanceOut();
304+
testSelection(editor.selection, colstart, linestart, colend, lineend);
305+
});
306+
307+
expectedBalanceOutRanges.pop();
308+
expectedBalanceOutRanges.reverse().forEach(([linestart, colstart, lineend, colend]) => {
309+
balanceIn();
310+
testSelection(editor.selection, colstart, linestart, colend, lineend);
311+
});
312+
313+
return Promise.resolve();
314+
});
315+
});
243316
});
244317

245318
function testSelection(selection: Selection, startChar: number, startline: number, endChar?: number, endLine?: number) {

extensions/emmet/src/test/tagActions.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ suite('Tests for Emmet actions on html tags', () => {
3030
</div>
3131
`;
3232

33+
let contentsWithTemplate = `
34+
<script type="text/template">
35+
<ul>
36+
<li><span>Hello</span></li>
37+
<li><span>There</span></li>
38+
<div><li><span>Bye</span></li></div>
39+
</ul>
40+
<span/>
41+
</script>
42+
`;
43+
3344
test('update tag with multiple cursors', () => {
3445
const expectedContents = `
3546
<div class="hello">
@@ -55,6 +66,30 @@ suite('Tests for Emmet actions on html tags', () => {
5566
});
5667
});
5768

69+
test('update tag with template', () => {
70+
const expectedContents = `
71+
<script type="text/template">
72+
<section>
73+
<li><span>Hello</span></li>
74+
<li><span>There</span></li>
75+
<div><li><span>Bye</span></li></div>
76+
</section>
77+
<span/>
78+
</script>
79+
`;
80+
81+
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
82+
editor.selections = [
83+
new Selection(2, 4, 2, 4), // cursor inside ul tag
84+
];
85+
86+
return updateTag('section')!.then(() => {
87+
assert.equal(doc.getText(), expectedContents);
88+
return Promise.resolve();
89+
});
90+
});
91+
});
92+
5893

5994
test('remove tag with mutliple cursors', () => {
6095
const expectedContents = `
@@ -81,6 +116,30 @@ suite('Tests for Emmet actions on html tags', () => {
81116
});
82117
});
83118

119+
120+
test('remove tag with template', () => {
121+
const expectedContents = `
122+
<script type="text/template">
123+
\t\t
124+
<li><span>Hello</span></li>
125+
<li><span>There</span></li>
126+
<div><li><span>Bye</span></li></div>
127+
\t
128+
<span/>
129+
</script>
130+
`;
131+
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
132+
editor.selections = [
133+
new Selection(2, 4, 2, 4), // cursor inside ul tag
134+
];
135+
136+
return removeTag()!.then(() => {
137+
assert.equal(doc.getText(), expectedContents);
138+
return Promise.resolve();
139+
});
140+
});
141+
});
142+
84143
test('split/join tag with mutliple cursors', () => {
85144
const expectedContents = `
86145
<div class="hello">
@@ -105,6 +164,30 @@ suite('Tests for Emmet actions on html tags', () => {
105164
});
106165
});
107166

167+
test('split/join tag with templates', () => {
168+
const expectedContents = `
169+
<script type="text/template">
170+
<ul>
171+
<li><span/></li>
172+
<li><span>There</span></li>
173+
<div><li><span>Bye</span></li></div>
174+
</ul>
175+
<span></span>
176+
</script>
177+
`;
178+
return withRandomFileEditor(contentsWithTemplate, 'html', (editor, doc) => {
179+
editor.selections = [
180+
new Selection(3, 17, 3, 17), // join tag
181+
new Selection(7, 5, 7, 5), // split tag
182+
];
183+
184+
return splitJoinTag()!.then(() => {
185+
assert.equal(doc.getText(), expectedContents);
186+
return Promise.resolve();
187+
});
188+
});
189+
});
190+
108191
test('split/join tag in jsx with xhtml self closing tag', () => {
109192
const expectedContents = `
110193
<div class="hello">

extensions/emmet/src/test/toggleComment.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,36 @@ suite('Tests for Toggle Comment action from Emmet (HTML)', () => {
247247
});
248248
});
249249
});
250+
251+
test('toggle comment within script template', () => {
252+
const templateContents = `
253+
<script type="text/template">
254+
<li><span>Hello</span></li>
255+
<li><!--<span>There</span>--></li>
256+
<div><li><span>Bye</span></li></div>
257+
<span/>
258+
</script>
259+
`;
260+
const expectedContents = `
261+
<script type="text/template">
262+
<!--<li><span>Hello</span></li>-->
263+
<li><span>There</span></li>
264+
<div><li><!--<span>Bye</span>--></li></div>
265+
<span/>
266+
</script>
267+
`;
268+
return withRandomFileEditor(templateContents, 'html', (editor, doc) => {
269+
editor.selections = [
270+
new Selection(2, 2, 2, 28), // select entire li element
271+
new Selection(3, 17, 3, 17), // cursor inside the commented span
272+
new Selection(4, 18, 4, 18), // cursor inside the noncommented span
273+
];
274+
return toggleComment().then(() => {
275+
assert.equal(doc.getText(), expectedContents);
276+
return Promise.resolve();
277+
});
278+
});
279+
});
250280
});
251281

252282
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)', () => {
541571
assert.equal(doc.getText(), expectedContents);
542572
return toggleComment().then(() => {
543573
assert.equal(doc.getText(), contents);
544-
return Promise.resolve();
574+
return Promise.resolve();
545575
});
546576
});
547577
});

extensions/emmet/src/toggleComment.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { getNodesInBetween, getNode, parseDocument, sameNodes, isStyleSheet, validate } from './util';
8-
import { Node, Stylesheet, Rule, HtmlNode } from 'EmmetNode';
7+
import { getNodesInBetween, getNode, getHtmlNode, parseDocument, sameNodes, isStyleSheet, validate } from './util';
8+
import { Node, Stylesheet, Rule } from 'EmmetNode';
99
import parseStylesheet from '@emmetio/css-parser';
1010
import { DocumentStreamReader } from './bufferStream';
1111

@@ -63,8 +63,8 @@ function toggleCommentHTML(document: vscode.TextDocument, selection: vscode.Sele
6363
const selectionStart = selection.isReversed ? selection.active : selection.anchor;
6464
const selectionEnd = selection.isReversed ? selection.anchor : selection.active;
6565

66-
let startNode = <HtmlNode>getNode(rootNode, selectionStart, true);
67-
let endNode = <HtmlNode>getNode(rootNode, selectionEnd, true);
66+
let startNode = getHtmlNode(document, rootNode, selectionStart, true);
67+
let endNode = getHtmlNode(document, rootNode, selectionEnd, true);
6868

6969
if (!startNode || !endNode) {
7070
return [];

extensions/emmet/src/updateTag.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode';
77
import { HtmlNode } from 'EmmetNode';
8-
import { getNode, parseDocument, validate } from './util';
8+
import { getHtmlNode, parseDocument, validate } from './util';
99

1010
export function updateTag(tagName: string): Thenable<boolean> | undefined {
1111
if (!validate(false) || !vscode.window.activeTextEditor) {
@@ -30,7 +30,7 @@ export function updateTag(tagName: string): Thenable<boolean> | undefined {
3030
}
3131

3232
function getRangesToUpdate(editor: vscode.TextEditor, selection: vscode.Selection, rootNode: HtmlNode): vscode.Range[] {
33-
let nodeToUpdate = <HtmlNode>getNode(rootNode, selection.start);
33+
let nodeToUpdate = getHtmlNode(editor.document, rootNode, selection.start);
3434
if (!nodeToUpdate) {
3535
return [];
3636
}

0 commit comments

Comments
 (0)