"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = create;
const language_service_1 = require("@volar/language-service");
const featureWorkers_1 = require("@volar/language-service/lib/utils/featureWorkers");
const volar_service_html_1 = require("volar-service-html");
const pug = require("./lib/languageService");
function create({ documentSelector = ['jade'], configurationSections = {
    autoCreateQuotes: 'html.autoCreateQuotes',
    autoClosingTags: '',
}, ...options } = {}) {
    const _htmlService = (0, volar_service_html_1.create)(options);
    return {
        name: 'pug',
        capabilities: {
            completionProvider: {
                triggerCharacters: ['.', ':'],
            },
            diagnosticProvider: {
                interFileDependencies: false,
                workspaceDiagnostics: false,
            },
            hoverProvider: true,
            documentHighlightProvider: true,
            documentLinkProvider: {},
            documentSymbolProvider: true,
            foldingRangeProvider: true,
            selectionRangeProvider: true,
            autoInsertionProvider: {
                triggerCharacters: ['='],
                configurationSections: [configurationSections.autoCreateQuotes],
            },
        },
        create(context) {
            const htmlService = _htmlService.create(context);
            const pugDocuments = new WeakMap();
            const htmlLs = htmlService.provide['html/languageService']();
            const pugLs = pug.getLanguageService(htmlLs);
            const disposable = options.onDidChangeCustomData?.(() => initializing = undefined, context);
            let initializing;
            return {
                dispose() {
                    htmlService.dispose?.();
                    disposable?.dispose();
                },
                provide: {
                    'pug/pugDocument': getPugDocument,
                    'pug/languageService': () => pugLs,
                },
                provideCompletionItems(document, position) {
                    return worker(document, pugDocument => {
                        return pugLs.doComplete(pugDocument, position, context, htmlService.provide['html/documentContext']());
                    });
                },
                provideDiagnostics(document) {
                    return worker(document, (pugDocument) => {
                        if (pugDocument.error) {
                            return [{
                                    source: 'pug',
                                    severity: 1,
                                    code: pugDocument.error.code,
                                    message: pugDocument.error.msg,
                                    range: {
                                        start: { line: pugDocument.error.line, character: pugDocument.error.column },
                                        end: { line: pugDocument.error.line, character: pugDocument.error.column },
                                    },
                                }];
                        }
                        return [];
                    });
                },
                provideHover(document, position) {
                    return worker(document, async (pugDocument) => {
                        const hoverSettings = await context.env.getConfiguration?.('html.hover');
                        return pugLs.doHover(pugDocument, position, hoverSettings);
                    });
                },
                provideDocumentHighlights(document, position) {
                    return worker(document, pugDocument => {
                        return pugLs.findDocumentHighlights(pugDocument, position);
                    });
                },
                provideDocumentLinks(document) {
                    return worker(document, pugDocument => {
                        return pugLs.findDocumentLinks(pugDocument, htmlService.provide['html/documentContext']());
                    });
                },
                provideDocumentSymbols(document, token) {
                    return worker(document, async (pugDoc) => {
                        const htmlResult = await htmlService.provideDocumentSymbols?.(pugDoc.docs[1], token) ?? [];
                        const pugResult = htmlResult.map(htmlSymbol => (0, language_service_1.transformDocumentSymbol)(htmlSymbol, range => (0, featureWorkers_1.getSourceRange)(pugDoc.docs, range))).filter((symbol) => symbol !== undefined);
                        return pugResult;
                    });
                },
                provideFoldingRanges(document) {
                    return worker(document, pugDocument => {
                        return pugLs.getFoldingRanges(pugDocument);
                    });
                },
                provideSelectionRanges(document, positions) {
                    return worker(document, pugDocument => {
                        return pugLs.getSelectionRanges(pugDocument, positions);
                    });
                },
                provideAutoInsertSnippet(document, selection, change) {
                    // selection must at end of change
                    if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) {
                        return;
                    }
                    return worker(document, async (pugDocument) => {
                        if (change.rangeLength === 0 && change.text.endsWith('=')) {
                            const enabled = (await context.env.getConfiguration?.(configurationSections.autoCreateQuotes))
                                ?? true;
                            if (enabled) {
                                const text = pugLs.doQuoteComplete(pugDocument, selection, await context.env.getConfiguration?.('html.completion'));
                                if (text) {
                                    return text;
                                }
                            }
                        }
                    });
                },
            };
            async function worker(document, callback) {
                const pugDocument = getPugDocument(document);
                if (!pugDocument) {
                    return;
                }
                await (initializing ??= initialize());
                return await callback(pugDocument);
            }
            async function initialize() {
                if (!options.getCustomData) {
                    return;
                }
                const customData = await options.getCustomData(context);
                htmlLs.setDataProviders(options.useDefaultDataProvider ?? true, customData);
            }
            function getPugDocument(document) {
                if (!matchDocument(documentSelector, document)) {
                    return;
                }
                const cache = pugDocuments.get(document);
                if (cache) {
                    const [cacheVersion, cacheDoc] = cache;
                    if (cacheVersion === document.version) {
                        return cacheDoc;
                    }
                }
                const doc = pugLs.parsePugDocument(document.getText());
                pugDocuments.set(document, [document.version, doc]);
                return doc;
            }
        },
    };
}
function matchDocument(selector, document) {
    for (const sel of selector) {
        if (sel === document.languageId || (typeof sel === 'object' && sel.language === document.languageId)) {
            return true;
        }
    }
    return false;
}
//# sourceMappingURL=index.js.map