diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 9441ccdebdea8ae7b17b48fff67b70d22f2aa19a..dbde92a485eb5e49afcfbde806368aabc4edb5b0 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Node, HtmlNode, Rule, Property } from 'EmmetNode'; +import { Node, HtmlNode, Rule, Property, Stylesheet } from 'EmmetNode'; import { getEmmetHelper, getNode, getInnerRange, getMappingForIncludedLanguages, parseDocument, validate, getEmmetConfiguration, isStyleSheet, getEmmetMode } from './util'; const trimRegex = /[\u00a0]*[\d|#|\-|\*|\u2022]+\.?/; @@ -290,8 +290,7 @@ export function expandEmmetAbbreviation(args: any): Thenable { * Checks if given position is a valid location to expand emmet abbreviation. * Works only on html and css/less/scss syntax * @param document current Text Document - * @param currentNode parsed node at given position + * @param rootNode parsed document * @param syntax syntax of the abbreviation * @param position position to validate * @param abbreviationRange The range of the abbreviation for which given position is being validated */ -export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocument, currentNode: Node | null, syntax: string, position: vscode.Position, abbreviationRange: vscode.Range): boolean { +export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocument, rootNode: Node | undefined, syntax: string, position: vscode.Position, abbreviationRange: vscode.Range): boolean { + const currentNode = rootNode ? getNode(rootNode, position, true) : null; if (isStyleSheet(syntax)) { + const stylesheet = rootNode; + if (stylesheet && (stylesheet.comments || []).some(x => position.isAfterOrEqual(x.start) && position.isBeforeOrEqual(x.end))) { + return false; + } // Continue validation only if the file was parse-able and the currentNode has been found if (!currentNode) { return true; diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index fb60c7124cc6fb71b0b4442cc1e672e14686f662..57f2d46ea812d36c5a699176e3e2cb6db6e1d583 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -34,22 +34,20 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi } let validateLocation = false; - let currentNode: Node | null = null; + let rootNode: Stylesheet | undefined = undefined; if (context.triggerKind !== vscode.CompletionTriggerKind.TriggerForIncompleteCompletions) { validateLocation = syntax === 'html' || isStyleSheet(document.languageId); // If document can be css parsed, get currentNode if (isStyleSheet(document.languageId)) { - const rootNode = document.lineCount > 1000 ? parsePartialStylesheet(document, position) : parseDocument(document, false); - if (!rootNode || (rootNode.comments || []).some(x => position.isAfterOrEqual(x.start) && position.isBeforeOrEqual(x.end))) { + rootNode = document.lineCount > 1000 ? parsePartialStylesheet(document, position) : parseDocument(document, false); + if (!rootNode) { return; } - - currentNode = getNode(rootNode, position, true); } } - if (validateLocation && !isValidLocationForEmmetAbbreviation(document, currentNode, syntax, position, extractAbbreviationResults.abbreviationRange)) { + if (validateLocation && !isValidLocationForEmmetAbbreviation(document, rootNode, syntax, position, extractAbbreviationResults.abbreviationRange)) { return; } diff --git a/extensions/emmet/src/test/cssAbbreviationAction.test.ts b/extensions/emmet/src/test/cssAbbreviationAction.test.ts index d80a5d31dd03c1ca150a23e16f6ff4c8a5738ff6..78dd6c7c3ba0cf2e3515d019b86fc26eaaf013de 100644 --- a/extensions/emmet/src/test/cssAbbreviationAction.test.ts +++ b/extensions/emmet/src/test/cssAbbreviationAction.test.ts @@ -65,6 +65,30 @@ suite('Tests for Expand Abbreviations (CSS)', () => { }); }); + test('No emmet when cursor inside comment (CSS)', () => { + const testContent = ` +.foo { + /*margin: 10px; + m10 + padding: 10px;*/ + display: auto; +} +`; + + return withRandomFileEditor(testContent, 'css', (editor, doc) => { + editor.selection = new Selection(3, 4, 3, 4); + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent); + const cancelSrc = new CancellationTokenSource(); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + if (completionPromise) { + assert.equal(1, 2, `Invalid completion at property value`); + } + return Promise.resolve(); + }); + }); + }); + test('No emmet when cursor in selector of a rule (CSS)', () => { const testContent = ` .foo {