"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.create = create; const vscode_uri_1 = require("vscode-uri"); const abbreviationActions_1 = require("./lib/abbreviationActions"); const parseDocument_1 = require("./lib/parseDocument"); const util_1 = require("./lib/util"); function create({ mappedLanguages = {}, } = {}) { return { name: 'emmet', capabilities: { completionProvider: { // https://docs.emmet.io/abbreviations/syntax/ triggerCharacters: '>+^*()#.[]$@-{}'.split(''), }, }, create(context) { let lastCompletionType; return { isAdditionalCompletion: true, provideCompletionItems(document, position, completionContext) { const completionResult = provideCompletionItemsInternal(document, position, completionContext); if (!completionResult) { lastCompletionType = undefined; return; } return completionResult.then(completionList => { if (!completionList || !completionList.items.length) { lastCompletionType = undefined; return completionList; } const item = completionList.items[0]; const expandedText = item.documentation ? item.documentation.toString() : ''; if (expandedText.startsWith('<')) { lastCompletionType = 'html'; } else if (expandedText.indexOf(':') > 0 && expandedText.endsWith(';')) { lastCompletionType = 'css'; } else { lastCompletionType = undefined; } return completionList; }); }, }; async function provideCompletionItemsInternal(document, position, completionContext) { const emmetConfig = await context.env.getConfiguration?.('emmet') ?? {}; const excludedLanguages = emmetConfig['excludeLanguages'] ?? []; if (excludedLanguages.includes(document.languageId)) { return; } const isSyntaxMapped = mappedLanguages[document.languageId] ? true : false; const emmetMode = (0, util_1.getEmmetMode)(mappedLanguages[document.languageId] ?? document.languageId, mappedLanguages, excludedLanguages); if (!emmetMode || emmetConfig['showExpandedAbbreviation'] === 'never' || ((isSyntaxMapped || emmetMode === 'jsx') && emmetConfig['showExpandedAbbreviation'] !== 'always')) { return; } let syntax = emmetMode; let validateLocation = syntax === 'html' || syntax === 'jsx' || syntax === 'xml'; let rootNode; let currentNode; // Don't show completions if there's a comment at the beginning of the line const lineRange = { start: { line: position.line, character: 0 }, end: position, }; if (document.getText(lineRange).trimStart().startsWith('//')) { return; } const helper = (0, util_1.getEmmetHelper)(); if (syntax === 'html') { if (completionContext.triggerKind === 3) { switch (lastCompletionType) { case 'html': validateLocation = false; break; case 'css': validateLocation = false; syntax = 'css'; break; default: break; } } if (validateLocation) { const positionOffset = document.offsetAt(position); const emmetRootNode = (0, parseDocument_1.getRootNode)(document, true); const foundNode = (0, util_1.getHtmlFlatNode)(document.getText(), emmetRootNode, positionOffset, false); if (foundNode) { if (foundNode.name === 'script') { const typeNode = foundNode.attributes.find(attr => attr.name.toString() === 'type'); if (typeNode) { const typeAttrValue = typeNode.value.toString(); if (typeAttrValue === 'application/javascript' || typeAttrValue === 'text/javascript') { if (!await (0, abbreviationActions_1.getSyntaxFromArgs)(context, { language: 'javascript' })) { return; } else { validateLocation = false; } } else if (util_1.allowedMimeTypesInScriptTag.includes(typeAttrValue)) { validateLocation = false; } } else { return; } } else if (foundNode.name === 'style') { syntax = 'css'; validateLocation = false; } else { const styleNode = foundNode.attributes.find(attr => attr.name.toString() === 'style'); if (styleNode && styleNode.value.start <= positionOffset && positionOffset <= styleNode.value.end) { syntax = 'css'; validateLocation = false; } } } } } const expandOptions = (0, util_1.isStyleSheet)(syntax) ? { lookAhead: false, syntax: 'stylesheet' } : { lookAhead: true, syntax: 'markup' }; const extractAbbreviationResults = helper.extractAbbreviation(document, position, expandOptions); if (!extractAbbreviationResults || !helper.isAbbreviationValid(syntax, extractAbbreviationResults.abbreviation)) { return; } const offset = document.offsetAt(position); if ((0, util_1.isStyleSheet)(document.languageId) && completionContext.triggerKind !== 3) { validateLocation = true; const usePartialParsing = await context.env.getConfiguration?.('emmet.optimizeStylesheetParsing') === true; rootNode = usePartialParsing && document.lineCount > 1000 ? (0, util_1.parsePartialStylesheet)(document, position) : (0, parseDocument_1.getRootNode)(document, true); if (!rootNode) { return; } currentNode = (0, util_1.getFlatNode)(rootNode, offset, true); } // Fix for https://github.com/microsoft/vscode/issues/107578 // Validate location if syntax is of styleSheet type to ensure that location is valid for emmet abbreviation. // For an html document containing a