diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 65d3709f5d2..362ac4fde7c 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -391,13 +391,13 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen && position.isAfterOrEqual(propertyNode.separatorToken.end) && position.isBeforeOrEqual(propertyNode.terminatorToken.start) && abbreviation.indexOf(':') === -1) { - return hexColorRegex.test(abbreviation); + return hexColorRegex.test(abbreviation) || abbreviation === '!'; } if (!propertyNode.terminatorToken && propertyNode.separator && position.isAfterOrEqual(propertyNode.separatorToken.end) && abbreviation.indexOf(':') === -1) { - return hexColorRegex.test(abbreviation); + return hexColorRegex.test(abbreviation) || abbreviation === '!'; } } diff --git a/extensions/emmet/src/test/cssAbbreviationAction.test.ts b/extensions/emmet/src/test/cssAbbreviationAction.test.ts index 78dd6c7c3ba..733d325aa62 100644 --- a/extensions/emmet/src/test/cssAbbreviationAction.test.ts +++ b/extensions/emmet/src/test/cssAbbreviationAction.test.ts @@ -151,32 +151,41 @@ nav# }); }); - test('Allow hex color when typing property values when there is a property in the next line (CSS)', () => { + test('Allow hex color or !important when typing property values when there is a property in the next line (CSS)', () => { const testContent = ` .foo { - margin: #12 + margin: #12 ! margin: 10px; } `; return withRandomFileEditor(testContent, 'css', (editor, doc) => { - editor.selection = new Selection(2, 12, 2, 12); - return expandEmmetAbbreviation(null).then(() => { - assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); - const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); - if (!completionPromise) { - assert.fail('Completion promise wasnt returned'); - return Promise.resolve(); - } - completionPromise.then(result => { - if (!result || !result.items || !result.items.length) { - assert.fail('Completion promise came back empty'); - return Promise.resolve(); - } - assert.equal(result.items[0].label, '#121212'); - }); + const cancelSrc = new CancellationTokenSource(); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(2, 14), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + + if (!completionPromise1 || !completionPromise2) { + assert.equal(1, 2, `Completion promise wasnt returned`); return Promise.resolve(); + } + + const callBack = (completionList: CompletionList, expandedText: string) => { + if (!completionList.items || !completionList.items.length) { + assert.equal(1, 2, `Empty Completions`); + return; + } + const emmetCompletionItem = completionList.items[0]; + assert.equal(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`); + assert.equal((emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`); + }; + + return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => { + callBack(result1, '#121212'); + callBack(result2, '!important'); + editor.selections = [new Selection(2, 12, 2, 12), new Selection(2, 14, 2, 14)]; + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important')); + }); }); }); }); @@ -203,32 +212,41 @@ nav# }); }); - test('Allow hex color when typing property values when there is a property in the previous line (CSS)', () => { + test('Allow hex color or !important when typing property values when there is a property in the previous line (CSS)', () => { const testContent = ` .foo { margin: 10px; - margin: #12 + margin: #12 ! } `; return withRandomFileEditor(testContent, 'css', (editor, doc) => { - editor.selection = new Selection(3, 12, 3, 12); - return expandEmmetAbbreviation(null).then(() => { - assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); - const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); - if (!completionPromise) { - assert.fail('Completion promise wasnt returned'); - return Promise.resolve(); - } - completionPromise.then(result => { - if (!result || !result.items || !result.items.length) { - assert.fail('Completion promise came back empty'); - return Promise.resolve(); - } - assert.equal(result.items[0].label, '#121212'); - }); + const cancelSrc = new CancellationTokenSource(); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(3, 14), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + + if (!completionPromise1 || !completionPromise2) { + assert.equal(1, 2, `Completion promise wasnt returned`); return Promise.resolve(); + } + + const callBack = (completionList: CompletionList, expandedText: string) => { + if (!completionList.items || !completionList.items.length) { + assert.equal(1, 2, `Empty Completions`); + return; + } + const emmetCompletionItem = completionList.items[0]; + assert.equal(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`); + assert.equal((emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`); + }; + + return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => { + callBack(result1, '#121212'); + callBack(result2, '!important'); + editor.selections = [new Selection(3, 12, 3, 12), new Selection(3, 14, 3, 14)]; + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important')); + }); }); }); }); @@ -254,31 +272,40 @@ nav# }); }); - test('Allow hex colors when typing property values when it is the only property in the rule (CSS)', () => { + test('Allow hex colors or !important when typing property values when it is the only property in the rule (CSS)', () => { const testContent = ` .foo { - margin: #12 + margin: #12 ! } `; return withRandomFileEditor(testContent, 'css', (editor, doc) => { - editor.selection = new Selection(2, 12, 2, 12); - return expandEmmetAbbreviation(null).then(() => { - assert.equal(editor.document.getText(), testContent.replace('#12', '#121212')); - const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); - if (!completionPromise) { - assert.fail('Completion promise wasnt returned'); - return Promise.resolve(); - } - completionPromise.then(result => { - if (!result || !result.items || !result.items.length) { - assert.fail('Completion promise came back empty'); - return Promise.resolve(); - } - assert.equal(result.items[0].label, '#121212'); - }); + const cancelSrc = new CancellationTokenSource(); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(2, 12), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(2, 14), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + + if (!completionPromise1 || !completionPromise2) { + assert.equal(1, 2, `Completion promise wasnt returned`); return Promise.resolve(); + } + + const callBack = (completionList: CompletionList, expandedText: string) => { + if (!completionList.items || !completionList.items.length) { + assert.equal(1, 2, `Empty Completions`); + return; + } + const emmetCompletionItem = completionList.items[0]; + assert.equal(emmetCompletionItem.label, expandedText, `Label of completion item doesnt match.`); + assert.equal((emmetCompletionItem.documentation || '').replace(/\|/g, ''), expandedText, `Docs of completion item doesnt match.`); + }; + + return Promise.all([completionPromise1, completionPromise2]).then(([result1, result2]) => { + callBack(result1, '#121212'); + callBack(result2, '!important'); + editor.selections = [new Selection(2, 12, 2, 12), new Selection(2, 14, 2, 14)]; + return expandEmmetAbbreviation(null).then(() => { + assert.equal(editor.document.getText(), testContent.replace('#12', '#121212').replace('!', '!important')); + }); }); }); });