"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startCommonLanguageServer = void 0;
const language_service_1 = require("@volar/language-service");
const l10n = require("@vscode/l10n");
const vscode = require("vscode-languageserver");
const vscode_uri_1 = require("vscode-uri");
const types_1 = require("../types");
const cancellationPipe_1 = require("./cancellationPipe");
const configurationHost_1 = require("./configurationHost");
const documents_1 = require("./documents");
const registerFeatures_1 = require("./utils/registerFeatures");
const serverConfig_1 = require("./utils/serverConfig");
const workspaces_1 = require("./workspaces");
function startCommonLanguageServer(connection, getCtx) {
    let initParams;
    let options;
    let roots = [];
    let fsHost;
    let projects;
    let configurationHost;
    let plugins;
    let documents;
    let context;
    connection.onInitialize(async (_params) => {
        initParams = _params;
        options = initParams.initializationOptions;
        context = getCtx(options);
        plugins = context.plugins.map(plugin => plugin(options, {
            typescript: options.typescript ? context.runtimeEnv.loadTypescript(options.typescript.tsdk) : undefined
        }));
        documents = (0, documents_1.createDocuments)(context.runtimeEnv, connection);
        if (options.l10n) {
            await l10n.config({ uri: options.l10n.location });
        }
        if (initParams.capabilities.workspace?.workspaceFolders && initParams.workspaceFolders) {
            roots = initParams.workspaceFolders.map(folder => vscode_uri_1.URI.parse(folder.uri));
        }
        else if (initParams.rootUri) {
            roots = [vscode_uri_1.URI.parse(initParams.rootUri)];
        }
        else if (initParams.rootPath) {
            roots = [vscode_uri_1.URI.file(initParams.rootPath)];
        }
        const result = {
            capabilities: {
                textDocumentSync: vscode.TextDocumentSyncKind.Incremental,
                workspace: {
                    // #18
                    workspaceFolders: {
                        supported: true,
                        changeNotifications: true,
                    },
                },
            },
        };
        configurationHost = initParams.capabilities.workspace?.configuration ? (0, configurationHost_1.createConfigurationHost)(initParams, connection) : undefined;
        let lsPlugins = {};
        for (const root of roots) {
            if (root.scheme === 'file') {
                let config = (0, serverConfig_1.loadConfig)(root.path, options.configFilePath) ?? {};
                for (const plugin of plugins) {
                    if (plugin.resolveConfig) {
                        config = plugin.resolveConfig(config, undefined);
                    }
                }
                if (config.plugins) {
                    lsPlugins = {
                        ...lsPlugins,
                        ...config.plugins,
                    };
                }
            }
        }
        (0, registerFeatures_1.setupCapabilities)(result.capabilities, options, plugins, getSemanticTokensLegend(), lsPlugins);
        await createLanguageServiceHost();
        try {
            // show version on LSP logs
            const packageJson = require('../package.json');
            result.serverInfo = {
                name: packageJson.name,
                version: packageJson.version,
            };
        }
        catch { }
        return result;
    });
    connection.onInitialized(() => {
        fsHost?.ready(connection);
        configurationHost?.ready();
        if (initParams.capabilities.workspace?.workspaceFolders) {
            connection.workspace.onDidChangeWorkspaceFolders(e => {
                for (const folder of e.added) {
                    projects?.add(vscode_uri_1.URI.parse(folder.uri));
                }
                for (const folder of e.removed) {
                    projects?.remove(vscode_uri_1.URI.parse(folder.uri));
                }
            });
        }
        if (options.serverMode !== types_1.ServerMode.Syntactic
            && initParams.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration) {
            const exts = plugins.map(plugin => plugin.watchFileExtensions).flat();
            if (exts.length) {
                connection.client.register(vscode.DidChangeWatchedFilesNotification.type, {
                    watchers: [
                        {
                            globPattern: `**/*.{${exts.join(',')}}`
                        },
                    ]
                });
            }
        }
    });
    connection.onShutdown(async () => {
        if (projects) {
            for (const workspace of projects.workspaces) {
                (await workspace[1]).dispose();
            }
        }
    });
    connection.listen();
    async function createLanguageServiceHost() {
        const ts = options.typescript ? context.runtimeEnv.loadTypescript(options.typescript.tsdk) : undefined;
        fsHost = ts ? context.runtimeEnv.createFileSystemHost(ts, initParams.capabilities, context.runtimeEnv, options) : undefined;
        const tsLocalized = options.typescript && initParams.locale ? await context.runtimeEnv.loadTypescriptLocalized(options.typescript.tsdk, initParams.locale) : undefined;
        const cancelTokenHost = (0, cancellationPipe_1.createCancellationTokenHost)(options.cancellationPipeName);
        const _projects = (0, workspaces_1.createWorkspaces)({
            server: context,
            fileSystemHost: fsHost,
            configurationHost,
            ts,
            tsLocalized,
            initParams: initParams,
            initOptions: options,
            documents,
            cancelTokenHost,
            plugins,
        });
        projects = _projects;
        for (const root of roots) {
            projects.add(root);
        }
        (await Promise.resolve().then(() => require('./features/customFeatures'))).register(connection, projects, context.runtimeEnv);
        (await Promise.resolve().then(() => require('./features/languageFeatures'))).register(connection, projects, initParams, options, cancelTokenHost, getSemanticTokensLegend(), context.runtimeEnv, documents);
        for (const plugin of plugins) {
            plugin.onInitialized?.(getLanguageService, context.runtimeEnv);
        }
        async function getLanguageService(uri) {
            const project = (await projects.getProject(uri))?.project;
            return project?.getLanguageService();
        }
    }
    function getSemanticTokensLegend() {
        if (!options.semanticTokensLegend) {
            return language_service_1.standardSemanticTokensLegend;
        }
        return {
            tokenTypes: [...language_service_1.standardSemanticTokensLegend.tokenTypes, ...options.semanticTokensLegend.tokenTypes],
            tokenModifiers: [...language_service_1.standardSemanticTokensLegend.tokenModifiers, ...options.semanticTokensLegend.tokenModifiers],
        };
    }
}
exports.startCommonLanguageServer = startCommonLanguageServer;
//# sourceMappingURL=server.js.map