diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index c63f97918588e..5974d63911d3c 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -337,7 +337,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", "@emmetio/math-expression": "^0.1.1", - "vscode-emmet-helper": "^1.1.32", + "vscode-emmet-helper": "^1.1.36", "vscode-languageserver-types": "^3.5.0", "image-size": "^0.5.2", "vscode-nls": "3.2.1" diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 0fdfacd411602..309b345c28a89 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -10,6 +10,12 @@ import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, const trimRegex = /[\u00a0]*[\d|#|\-|\*|\u2022]+\.?/; const hexColorRegex = /^#\d+$/; +const inlineElements = ['a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', + 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', + 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'object', 'q', + 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', + 'textarea', 'tt', 'u', 'var']; + interface ExpandAbbreviationInput { syntax: string; abbreviation: string; @@ -62,7 +68,8 @@ export function wrapWithAbbreviation(args: any) { const preceedingWhiteSpace = matches ? matches[1].length : 0; rangeToReplace = new vscode.Range(rangeToReplace.start.line, rangeToReplace.start.character + preceedingWhiteSpace, rangeToReplace.end.line, rangeToReplace.end.character); - expandAbbrList.push({ syntax, abbreviation, rangeToReplace, textToWrap: ['\n\t$TM_SELECTED_TEXT\n'], filter }); + let textToWrap = rangeToReplace.isSingleLine ? ['$TM_SELECTED_TEXT'] : ['\n\t$TM_SELECTED_TEXT\n']; + expandAbbrList.push({ syntax, abbreviation, rangeToReplace, textToWrap, filter }); }); return expandAbbreviationInRange(editor, expandAbbrList, true); @@ -435,17 +442,29 @@ function expandAbbr(input: ExpandAbbreviationInput): string | undefined { try { // Expand the abbreviation - let expandedText = helper.expandAbbreviation(input.abbreviation, expandOptions); + let expandedText; if (input.textToWrap) { + let parsedAbbr = helper.parseAbbreviation(input.abbreviation, expandOptions); + if (input.rangeToReplace.isSingleLine && input.textToWrap.length === 1) { + + // Fetch rightmost element in the parsed abbreviation (i.e the element that will contain the wrapped text). + let wrappingNode = parsedAbbr; + while (wrappingNode && wrappingNode.children && wrappingNode.children.length > 0) { + wrappingNode = wrappingNode.children[wrappingNode.children.length - 1]; + } + + // If wrapping with a block element, insert newline in the text to wrap. + if (wrappingNode && inlineElements.indexOf(wrappingNode.name) === -1) { + wrappingNode.value = '\n\t' + wrappingNode.value + '\n'; + } + } + expandedText = helper.expandAbbreviation(parsedAbbr, expandOptions); // All $anyword would have been escaped by the emmet helper. // Remove the escaping backslash from $TM_SELECTED_TEXT so that VS Code Snippet controller can treat it as a variable expandedText = expandedText.replace('\\$TM_SELECTED_TEXT', '$TM_SELECTED_TEXT'); - - // If the expanded text is single line then we dont need the \t and \n we added to $TM_SELECTED_TEXT earlier - if (input.textToWrap.length === 1 && expandedText.indexOf('\n') === -1) { - expandedText = expandedText.replace(/\s*\$TM_SELECTED_TEXT\s*/, '$TM_SELECTED_TEXT'); - } + } else { + expandedText = helper.expandAbbreviation(input.abbreviation, expandOptions); } return expandedText; diff --git a/extensions/emmet/src/test/wrapWithAbbreviation.test.ts b/extensions/emmet/src/test/wrapWithAbbreviation.test.ts index 801b24b273ef1..0862af36db98a 100644 --- a/extensions/emmet/src/test/wrapWithAbbreviation.test.ts +++ b/extensions/emmet/src/test/wrapWithAbbreviation.test.ts @@ -197,6 +197,31 @@ suite('Tests for Wrap with Abbreviations', () => { }); }); + test('Wrap with multiline abbreviation doesnt add extra spaces', () => { + // Issue #29898 + const contents = ` + hello + `; + const expectedContents = ` +