From 7db6419d78ebdad77844919a5c2c0dc109e279fc Mon Sep 17 00:00:00 2001 From: Ramya Achutha Rao Date: Mon, 26 Mar 2018 13:33:05 -0700 Subject: [PATCH] Avoid re-parsing for emmet completions when triggered for incomplete completions --- .../emmet/src/defaultCompletionProvider.ts | 22 ++++++------ .../emmet/src/test/abbreviationAction.test.ts | 14 ++++---- .../src/test/cssAbbreviationAction.test.ts | 36 +++++++++---------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts index 29fdcd860b1..458d1fc6d43 100644 --- a/extensions/emmet/src/defaultCompletionProvider.ts +++ b/extensions/emmet/src/defaultCompletionProvider.ts @@ -10,7 +10,7 @@ import { getEmmetHelper, getNode, getMappingForIncludedLanguages, parseDocument, export class DefaultCompletionItemProvider implements vscode.CompletionItemProvider { - public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Thenable | undefined { + public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Thenable | undefined { const emmetConfig = vscode.workspace.getConfiguration('emmet'); const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : []; if (excludedLanguages.indexOf(document.languageId) > -1) { @@ -33,18 +33,20 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return; } - let validateLocation = syntax === 'html'; + let validateLocation = false; let currentNode: Node | null = null; - // If document can be css parsed, get currentNode - if (isStyleSheet(document.languageId)) { - const rootNode = parseDocument(document, false); - if (!rootNode) { - return; - } + 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 = parseDocument(document, false); + if (!rootNode) { + return; + } - currentNode = getNode(rootNode, position, true); - validateLocation = true; + currentNode = getNode(rootNode, position, true); + } } if (validateLocation && !isValidLocationForEmmetAbbreviation(document, currentNode, syntax, position, extractAbbreviationResults.abbreviationRange)) { diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index 4f914717061..cf4ba401a23 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { Selection, workspace, CompletionList, CancellationTokenSource } from 'vscode'; +import { Selection, workspace, CompletionList, CancellationTokenSource, CompletionTriggerKind } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { expandEmmetAbbreviation } from '../abbreviationActions'; import { DefaultCompletionItemProvider } from '../defaultCompletionProvider'; @@ -63,7 +63,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor('img', 'html', (editor, doc) => { editor.selection = new Selection(0, 3, 0, 3); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { assert.equal(!completionPromise, false, `Got unexpected undefined instead of a completion promise`); return Promise.resolve(); @@ -165,7 +165,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = new Selection(2, 4, 2, 4); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -185,7 +185,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = new Selection(9, 8, 9, 8); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -207,7 +207,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { return withRandomFileEditor(fileContents, 'html', (editor, doc) => { editor.selection = new Selection(0, 6, 0, 6); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); return Promise.resolve(); }); @@ -234,7 +234,7 @@ suite('Tests for Expand Abbreviations (HTML)', () => { // return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { // editor.selection = new Selection(13, 3, 13, 6); // const cancelSrc = new CancellationTokenSource(); - // const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + // const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); // if (!completionPromise) { // assert.equal(1, 2, `Problem with expanding m10`); // return Promise.resolve(); @@ -347,7 +347,7 @@ function testHtmlCompletionProvider(selection: Selection, abbreviation: string, return withRandomFileEditor(htmlContents, 'html', (editor, doc) => { editor.selection = selection; const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise) { if (!shouldFail) { assert.equal(1, 2, `Problem with expanding ${abbreviation} to ${expandedText}`); diff --git a/extensions/emmet/src/test/cssAbbreviationAction.test.ts b/extensions/emmet/src/test/cssAbbreviationAction.test.ts index 9d53d8599f1..d80a5d31dd0 100644 --- a/extensions/emmet/src/test/cssAbbreviationAction.test.ts +++ b/extensions/emmet/src/test/cssAbbreviationAction.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { Selection, CompletionList, CancellationTokenSource, Position } from 'vscode'; +import { Selection, CompletionList, CancellationTokenSource, Position, CompletionTriggerKind } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { expandEmmetAbbreviation } from '../abbreviationActions'; import { DefaultCompletionItemProvider } from '../defaultCompletionProvider'; @@ -79,7 +79,7 @@ nav# 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); + 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`); } @@ -101,7 +101,7 @@ nav# 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); + 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`); } @@ -118,7 +118,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(0, 30), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(0, 30), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -140,7 +140,7 @@ nav# 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); + 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(); @@ -170,7 +170,7 @@ nav# return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), testContent); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(3, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); } @@ -192,7 +192,7 @@ nav# 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); + 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(); @@ -221,7 +221,7 @@ nav# 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); + 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`); } @@ -242,7 +242,7 @@ nav# 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); + 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(); @@ -266,8 +266,8 @@ nav# return withRandomFileEditor(cssContents, 'css', (editor, doc) => { editor.selection = new Selection(3, 1, 3, 6); const cancelSrc = new CancellationTokenSource(); - const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 6), cancelSrc.token); - const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 6), cancelSrc.token); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 6), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 6), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise1 || !completionPromise2) { assert.equal(1, 2, `Problem with expanding pos:f`); return Promise.resolve(); @@ -312,10 +312,10 @@ nav# return withRandomFileEditor(scssContents, 'scss', (editor, doc) => { editor.selection = new Selection(3, 4, 3, 4); const cancelSrc = new CancellationTokenSource(); - const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 4), cancelSrc.token); - const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 5), cancelSrc.token); - const completionPromise3 = completionProvider.provideCompletionItems(editor.document, new Position(11, 4), cancelSrc.token); - const completionPromise4 = completionProvider.provideCompletionItems(editor.document, new Position(14, 5), cancelSrc.token); + const completionPromise1 = completionProvider.provideCompletionItems(editor.document, new Position(3, 4), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise2 = completionProvider.provideCompletionItems(editor.document, new Position(5, 5), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise3 = completionProvider.provideCompletionItems(editor.document, new Position(11, 4), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); + const completionPromise4 = completionProvider.provideCompletionItems(editor.document, new Position(14, 5), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (!completionPromise1) { assert.equal(1, 2, `Problem with expanding padding abbreviations at line 3 col 4`); } @@ -392,13 +392,13 @@ m10 return withRandomFileEditor(scssContentsNoExpand, 'scss', (editor, doc) => { editor.selection = new Selection(1, 3, 1, 3); // outside rule const cancelSrc = new CancellationTokenSource(); - let completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + let completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `m10 gets expanded in invalid location (outside rule)`); } editor.selection = new Selection(5, 15, 5, 15); // in the value part of property value - completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token); + completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { return completionPromise.then((completionList: CompletionList) => { if (completionList && completionList.items && completionList.items.length > 0) { @@ -419,7 +419,7 @@ m10 return expandEmmetAbbreviation(null).then(() => { assert.equal(editor.document.getText(), scssContents); const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(19, 10), cancelSrc.token); + const completionPromise = completionProvider.provideCompletionItems(editor.document, new Position(19, 10), cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); if (completionPromise) { assert.equal(1, 2, `Invalid completion at property value`); }