"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLanguageService = void 0;
const language_core_1 = require("@volar/language-core");
const tsFaster = require("typescript-auto-import-cache");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const documents_1 = require("./documents");
const autoInsert = require("./languageFeatures/autoInsert");
const callHierarchy = require("./languageFeatures/callHierarchy");
const codeActionResolve = require("./languageFeatures/codeActionResolve");
const codeActions = require("./languageFeatures/codeActions");
const codeLens = require("./languageFeatures/codeLens");
const codeLensResolve = require("./languageFeatures/codeLensResolve");
const completions = require("./languageFeatures/complete");
const completionResolve = require("./languageFeatures/completeResolve");
const definition = require("./languageFeatures/definition");
const documentHighlight = require("./languageFeatures/documentHighlights");
const documentLink = require("./languageFeatures/documentLinks");
const documentLinkResolve = require("./languageFeatures/documentLinkResolve");
const semanticTokens = require("./languageFeatures/documentSemanticTokens");
const fileReferences = require("./languageFeatures/fileReferences");
const fileRename = require("./languageFeatures/fileRename");
const hover = require("./languageFeatures/hover");
const inlayHints = require("./languageFeatures/inlayHints");
const inlayHintResolve = require("./languageFeatures/inlayHintResolve");
const references = require("./languageFeatures/references");
const rename = require("./languageFeatures/rename");
const renamePrepare = require("./languageFeatures/renamePrepare");
const signatureHelp = require("./languageFeatures/signatureHelp");
const diagnostics = require("./languageFeatures/validation");
const workspaceSymbol = require("./languageFeatures/workspaceSymbols");
const colorPresentations = require("./documentFeatures/colorPresentations");
const documentColors = require("./documentFeatures/documentColors");
const documentSymbols = require("./documentFeatures/documentSymbols");
const foldingRanges = require("./documentFeatures/foldingRanges");
const format = require("./documentFeatures/format");
const linkedEditingRanges = require("./documentFeatures/linkedEditingRanges");
const selectionRanges = require("./documentFeatures/selectionRanges");
const vscode = require("vscode-languageserver-protocol");
// fix build
const common_1 = require("./utils/common");
function createLanguageService(ctx, documentRegistry) {
    const languageContext = (0, language_core_1.createLanguageContext)(ctx.host, ctx.modules, Object.values(ctx.config.languages ?? {}).filter(common_1.notEmpty));
    const context = createLanguageServicePluginContext(ctx, languageContext, documentRegistry);
    return createLanguageServiceBase(context);
}
exports.createLanguageService = createLanguageService;
function createLanguageServicePluginContext(ctx, languageContext, documentRegistry) {
    const ts = ctx.modules.typescript;
    let tsLs;
    if (ts) {
        const created = tsFaster.createLanguageService(ts, languageContext.typescript.languageServiceHost, proxiedHost => ts.createLanguageService(proxiedHost, documentRegistry), ctx.rootUri.path);
        tsLs = created.languageService;
        if (created.setPreferences && ctx.configurationHost) {
            const configHost = ctx.configurationHost;
            updatePreferences();
            ctx.configurationHost?.onDidChangeConfiguration?.(updatePreferences);
            async function updatePreferences() {
                const preferences = await configHost.getConfiguration('typescript.preferences');
                if (preferences) {
                    created.setPreferences?.(preferences);
                }
            }
        }
        if (created.projectUpdated) {
            let scriptFileNames = new Set(ctx.host.getScriptFileNames());
            ctx.fileSystemHost?.onDidChangeWatchedFiles((params) => {
                if (params.changes.some(change => change.type !== vscode.FileChangeType.Changed)) {
                    scriptFileNames = new Set(ctx.host.getScriptFileNames());
                }
                for (const change of params.changes) {
                    if (scriptFileNames.has(ctx.uriToFileName(change.uri))) {
                        created.projectUpdated?.(ctx.uriToFileName(context.rootUri.fsPath));
                    }
                }
            });
        }
    }
    const textDocumentMapper = (0, documents_1.createDocumentsAndSourceMaps)(ctx, languageContext.virtualFiles);
    const documents = new WeakMap();
    const documentVersions = new Map();
    const context = {
        ...ctx,
        core: languageContext,
        plugins: {},
        typescript: ts && tsLs ? {
            module: ts,
            languageServiceHost: languageContext.typescript.languageServiceHost,
            languageService: tsLs,
        } : undefined,
        documents: textDocumentMapper,
        commands: {
            createRenameCommand(uri, position) {
                const source = toSourceLocation(uri, position, data => typeof data.rename === 'object' ? !!data.rename.normalize : !!data.rename);
                if (!source) {
                    return;
                }
                return vscode.Command.create('', 'editor.action.rename', source.uri, source.position);
            },
            createShowReferencesCommand(uri, position, locations) {
                const source = toSourceLocation(uri, position);
                if (!source) {
                    return;
                }
                const sourceReferences = [];
                for (const reference of locations) {
                    if (context.documents.isVirtualFileUri(reference.uri)) {
                        for (const [_, map] of context.documents.getMapsByVirtualFileUri(reference.uri)) {
                            const range = map.toSourceRange(reference.range);
                            if (range) {
                                sourceReferences.push({ uri: map.sourceFileDocument.uri, range });
                            }
                        }
                    }
                    else {
                        sourceReferences.push(reference);
                    }
                }
                return vscode.Command.create(locations.length === 1 ? '1 reference' : `${locations.length} references`, 'editor.action.showReferences', source.uri, source.position, sourceReferences);
            },
            createSetSelectionCommand(position) {
                return vscode.Command.create('', 'setSelection', {
                    selection: {
                        selectionStartLineNumber: position.line + 1,
                        positionLineNumber: position.line + 1,
                        selectionStartColumn: position.character + 1,
                        positionColumn: position.character + 1,
                    },
                });
            },
        },
        getTextDocument,
    };
    for (const pluginId in ctx.config.plugins ?? {}) {
        const plugin = ctx.config.plugins?.[pluginId];
        if (plugin instanceof Function) {
            const _plugin = plugin(context);
            context.plugins[pluginId] = _plugin;
        }
        else if (plugin) {
            context.plugins[pluginId] = plugin;
        }
    }
    return context;
    function toSourceLocation(uri, position, filter) {
        if (!textDocumentMapper.isVirtualFileUri(uri)) {
            return { uri, position };
        }
        const map = textDocumentMapper.getVirtualFileByUri(uri);
        if (map) {
            for (const [_, map] of context.documents.getMapsByVirtualFileUri(uri)) {
                const sourcePosition = map.toSourcePosition(position, filter);
                if (sourcePosition) {
                    return {
                        uri: map.sourceFileDocument.uri,
                        position: sourcePosition,
                    };
                }
            }
        }
    }
    function getTextDocument(uri) {
        const fileName = ctx.uriToFileName(uri);
        const scriptSnapshot = ctx.host.getScriptSnapshot(fileName);
        if (scriptSnapshot) {
            let document = documents.get(scriptSnapshot);
            if (!document) {
                const newVersion = (documentVersions.get(uri.toLowerCase()) ?? 0) + 1;
                documentVersions.set(uri.toLowerCase(), newVersion);
                document = vscode_languageserver_textdocument_1.TextDocument.create(uri, ctx.host.getScriptLanguageId?.(fileName) ?? (0, common_1.resolveCommonLanguageId)(uri), newVersion, scriptSnapshot.getText(0, scriptSnapshot.getLength()));
                documents.set(scriptSnapshot, document);
            }
            return document;
        }
    }
}
function createLanguageServiceBase(context) {
    return {
        triggerCharacters: Object.values(context.plugins).map(plugin => plugin?.triggerCharacters ?? []).flat(),
        autoFormatTriggerCharacters: Object.values(context.plugins).map(plugin => plugin?.autoFormatTriggerCharacters ?? []).flat(),
        signatureHelpTriggerCharacters: Object.values(context.plugins).map(plugin => plugin?.signatureHelpTriggerCharacters ?? []).flat(),
        signatureHelpRetriggerCharacters: Object.values(context.plugins).map(plugin => plugin?.signatureHelpRetriggerCharacters ?? []).flat(),
        format: format.register(context),
        getFoldingRanges: foldingRanges.register(context),
        getSelectionRanges: selectionRanges.register(context),
        findLinkedEditingRanges: linkedEditingRanges.register(context),
        findDocumentSymbols: documentSymbols.register(context),
        findDocumentColors: documentColors.register(context),
        getColorPresentations: colorPresentations.register(context),
        doValidation: diagnostics.register(context),
        findReferences: references.register(context),
        findFileReferences: fileReferences.register(context),
        findDefinition: definition.register(context, 'provideDefinition', data => !!data.definition, data => !!data.definition),
        findTypeDefinition: definition.register(context, 'provideTypeDefinition', data => !!data.definition, data => !!data.definition),
        findImplementations: definition.register(context, 'provideImplementation', data => !!data.references, () => false),
        prepareRename: renamePrepare.register(context),
        doRename: rename.register(context),
        getEditsForFileRename: fileRename.register(context),
        getSemanticTokens: semanticTokens.register(context),
        doHover: hover.register(context),
        doComplete: completions.register(context),
        doCodeActions: codeActions.register(context),
        doCodeActionResolve: codeActionResolve.register(context),
        doCompletionResolve: completionResolve.register(context),
        getSignatureHelp: signatureHelp.register(context),
        doCodeLens: codeLens.register(context),
        doCodeLensResolve: codeLensResolve.register(context),
        findDocumentHighlights: documentHighlight.register(context),
        findDocumentLinks: documentLink.register(context),
        doDocumentLinkResolve: documentLinkResolve.register(context),
        findWorkspaceSymbols: workspaceSymbol.register(context),
        doAutoInsert: autoInsert.register(context),
        getInlayHints: inlayHints.register(context),
        doInlayHintResolve: inlayHintResolve.register(context),
        callHierarchy: callHierarchy.register(context),
        dispose: () => context.typescript?.languageService.dispose(),
        context,
    };
}
//# sourceMappingURL=baseLanguageService.js.map