mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Emmet identify CDATA for wrap, fixes #123136
This commit is contained in:
parent
97740a7d25
commit
9627b4ea63
|
@ -6,7 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Node, HtmlNode, Rule, Property, Stylesheet } from 'EmmetFlatNode';
|
||||
import { getEmmetHelper, getFlatNode, getMappingForIncludedLanguages, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode, parsePartialStylesheet, isStyleAttribute, getEmbeddedCssNodeIfAny, allowedMimeTypesInScriptTag, toLSTextDocument, isOffsetInsideOpenOrCloseTag } from './util';
|
||||
import { getEmmetHelper, getFlatNode, getHtmlFlatNode, getMappingForIncludedLanguages, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode, parsePartialStylesheet, isStyleAttribute, getEmbeddedCssNodeIfAny, allowedMimeTypesInScriptTag, toLSTextDocument, isOffsetInsideOpenOrCloseTag } from './util';
|
||||
import { getRootNode as parseDocument } from './parseDocument';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
@ -56,7 +56,8 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
|
|||
let { start, end } = rangeToReplace;
|
||||
|
||||
const startOffset = document.offsetAt(start);
|
||||
const startNode = getFlatNode(rootNode, startOffset, true);
|
||||
const documentText = document.getText();
|
||||
const startNode = getHtmlFlatNode(documentText, rootNode, startOffset, true);
|
||||
if (startNode && isOffsetInsideOpenOrCloseTag(startNode, startOffset)) {
|
||||
start = document.positionAt(startNode.start);
|
||||
const nodeEndPosition = document.positionAt(startNode.end);
|
||||
|
@ -64,7 +65,7 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
|
|||
}
|
||||
|
||||
const endOffset = document.offsetAt(end);
|
||||
const endNode = getFlatNode(rootNode, endOffset, true);
|
||||
const endNode = getHtmlFlatNode(documentText, rootNode, endOffset, true);
|
||||
if (endNode && isOffsetInsideOpenOrCloseTag(endNode, endOffset)) {
|
||||
const nodeStartPosition = document.positionAt(endNode.start);
|
||||
start = nodeStartPosition.isBefore(start) ? nodeStartPosition : start;
|
||||
|
|
|
@ -219,6 +219,79 @@ suite('Tests for Wrap with Abbreviations', () => {
|
|||
return testWrapWithAbbreviation([new Selection(3, 2, 3, 2)], 'div', expectedContents, contents);
|
||||
});
|
||||
|
||||
test('Wrap with abbreviation inner node in cdata', () => {
|
||||
const contents = `
|
||||
<div class="nav main">
|
||||
<![CDATA[
|
||||
<div>
|
||||
<p>Test 1</p>
|
||||
</div>
|
||||
<p>Test 2</p>
|
||||
]]>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
const expectedContents = `
|
||||
<div class="nav main">
|
||||
<![CDATA[
|
||||
<div>
|
||||
<p>Test 1</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Test 2</p>
|
||||
</div>
|
||||
]]>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
return testWrapWithAbbreviation([new Selection(6, 5, 6, 5)], 'div', expectedContents, contents);
|
||||
});
|
||||
|
||||
test('Wrap with abbreviation inner node in script in cdata', () => {
|
||||
const contents = `
|
||||
<div class="nav main">
|
||||
<![CDATA[
|
||||
<script type="text/plain">
|
||||
<p>Test 1</p>
|
||||
</script>
|
||||
<p>Test 2</p>
|
||||
]]>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
const expectedContents = `
|
||||
<div class="nav main">
|
||||
<![CDATA[
|
||||
<script type="text/plain">
|
||||
<div>
|
||||
<p>Test 1</p>
|
||||
</div>
|
||||
</script>
|
||||
<p>Test 2</p>
|
||||
]]>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
return testWrapWithAbbreviation([new Selection(4, 10, 4, 10)], 'div', expectedContents, contents);
|
||||
});
|
||||
|
||||
test('Wrap with abbreviation inner node in cdata one-liner', () => {
|
||||
const contents = `
|
||||
<div class="nav main">
|
||||
<![CDATA[<p>Test here</p>]]>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
// this result occurs because no selection on the open/close p tag was given
|
||||
const expectedContents = `
|
||||
<div class="nav main">
|
||||
<div><![CDATA[<p>Test here</p>]]></div>
|
||||
hello
|
||||
</div>
|
||||
`;
|
||||
return testWrapWithAbbreviation([new Selection(2, 15, 2, 15)], 'div', expectedContents, contents);
|
||||
});
|
||||
|
||||
test('Wrap with multiline abbreviation doesnt add extra spaces', () => {
|
||||
// Issue #29898
|
||||
const contents = `
|
||||
|
|
|
@ -381,13 +381,19 @@ export function getHtmlFlatNode(documentText: string, root: FlatNode | undefined
|
|||
|
||||
// If the currentNode is a script one, first set up its subtree and then find HTML node.
|
||||
if (currentNode.name === 'script' && currentNode.children.length === 0) {
|
||||
setUpScriptNodeSubtree(documentText, currentNode);
|
||||
currentNode = <HtmlFlatNode | undefined>getFlatNode(currentNode, offset, includeNodeBoundary) ?? currentNode;
|
||||
const scriptNodeBody = setupScriptNodeSubtree(documentText, currentNode);
|
||||
if (scriptNodeBody) {
|
||||
currentNode = getHtmlFlatNode(scriptNodeBody, currentNode, offset, includeNodeBoundary) ?? currentNode;
|
||||
}
|
||||
}
|
||||
else if (currentNode.type === 'cdata') {
|
||||
const cdataBody = setupCdataNodeSubtree(documentText, currentNode);
|
||||
currentNode = getHtmlFlatNode(cdataBody, currentNode, offset, includeNodeBoundary) ?? currentNode;
|
||||
}
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
export function setUpScriptNodeSubtree(documentText: string, scriptNode: HtmlFlatNode): void {
|
||||
export function setupScriptNodeSubtree(documentText: string, scriptNode: HtmlFlatNode): string {
|
||||
const isTemplateScript = scriptNode.name === 'script' &&
|
||||
(scriptNode.attributes &&
|
||||
scriptNode.attributes.some(x => x.name.toString() === 'type'
|
||||
|
@ -403,7 +409,25 @@ export function setUpScriptNodeSubtree(documentText: string, scriptNode: HtmlFla
|
|||
scriptNode.children.push(child);
|
||||
child.parent = scriptNode;
|
||||
});
|
||||
return scriptBodyText;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function setupCdataNodeSubtree(documentText: string, cdataNode: HtmlFlatNode): string {
|
||||
// blank out the rest of the document and generate the subtree.
|
||||
const cdataStart = '<![CDATA[';
|
||||
const cdataEnd = ']]>';
|
||||
const startToUse = cdataNode.start + cdataStart.length;
|
||||
const endToUse = cdataNode.end - cdataEnd.length;
|
||||
const beforePadding = ' '.repeat(startToUse);
|
||||
const cdataBody = beforePadding + documentText.substring(startToUse, endToUse);
|
||||
const innerRoot: HtmlFlatNode = parse(cdataBody);
|
||||
innerRoot.children.forEach(child => {
|
||||
cdataNode.children.push(child);
|
||||
child.parent = cdataNode;
|
||||
});
|
||||
return cdataBody;
|
||||
}
|
||||
|
||||
export function isOffsetInsideOpenOrCloseTag(node: FlatNode, offset: number): boolean {
|
||||
|
|
Loading…
Reference in a new issue