"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MainThreadDebug = void 0;
const tslib_1 = require("tslib");
const di_1 = require("@opensumi/di");
const ide_connection_1 = require("@opensumi/ide-connection");
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
const services_1 = require("@opensumi/ide-core-browser/lib/services");
const ide_debug_1 = require("@opensumi/ide-debug");
const breakpoint_1 = require("@opensumi/ide-debug/lib/browser/breakpoint");
const debug_configuration_manager_1 = require("@opensumi/ide-debug/lib/browser/debug-configuration-manager");
const debug_preferences_1 = require("@opensumi/ide-debug/lib/browser/debug-preferences");
const debug_session_contribution_1 = require("@opensumi/ide-debug/lib/browser/debug-session-contribution");
const debug_session_manager_1 = require("@opensumi/ide-debug/lib/browser/debug-session-manager");
const debug_console_tree_model_service_1 = require("@opensumi/ide-debug/lib/browser/view/console/debug-console-tree.model.service");
const debug_service_1 = require("@opensumi/ide-debug/lib/common/debug-service");
const debug_session_1 = require("@opensumi/ide-debug/lib/common/debug-session");
const ide_editor_1 = require("@opensumi/ide-editor");
const ide_file_service_1 = require("@opensumi/ide-file-service");
const output_service_1 = require("@opensumi/ide-output/lib/browser/output.service");
const ide_overlay_1 = require("@opensumi/ide-overlay");
const ide_terminal_next_1 = require("@opensumi/ide-terminal-next");
const vscode_1 = require("../../../common/vscode");
const types_1 = require("../../types");
const debug_1 = require("./debug");
const extension_debug_adapter_contribution_1 = require("./debug/extension-debug-adapter-contribution");
const extension_debug_service_1 = require("./debug/extension-debug-service");
let MainThreadDebug = class MainThreadDebug {
    constructor(rpcProtocol, mainThreadConnection) {
        this.rpcProtocol = rpcProtocol;
        this.mainThreadConnection = mainThreadConnection;
        this.toDispose = new Map();
        this.listenerDispose = new ide_core_browser_1.DisposableCollection();
        this.proxy = this.rpcProtocol.getProxy(vscode_1.ExtHostAPIIdentifier.ExtHostDebug);
        this.listen();
        this.registerDebugContributions();
    }
    dispose() {
        this.toDispose.forEach((disposable) => {
            disposable.dispose();
        });
        this.toDispose.clear();
        this.listenerDispose.dispose();
    }
    listen() {
        this.listenerDispose.pushAll([
            this.breakpointManager.onDidChangeBreakpoints(({ added, removed, changed }) => {
                const all = this.breakpointManager.getBreakpoints();
                this.proxy.$breakpointsDidChange(this.toCustomApiBreakpoints(all), this.toCustomApiBreakpoints(added), this.toCustomApiBreakpoints(removed), this.toCustomApiBreakpoints(changed));
            }),
            this.sessionManager.onDidStartDebugSession((debugSession) => {
                this.proxy.$sessionDidStart(debugSession.id);
            }),
            this.sessionManager.onDidDestroyDebugSession((debugSession) => {
                this.proxy.$sessionDidDestroy(debugSession.id);
            }),
            this.sessionManager.onDidChangeActiveDebugSession((event) => {
                this.proxy.$sessionDidChange(event.current && event.current.id);
            }),
            this.sessionManager.onDidReceiveDebugSessionCustomEvent((event) => {
                this.proxy.$onSessionCustomEvent(event.session.id, event.event, event.body);
            }),
            this.debugService.onDidDebugContributionPointChange(({ path, contributions, removed }) => {
                // 新增调试插件时注册对应调试能力
                if (removed) {
                    this.proxy.$unregisterDebuggerContributions(contributions);
                    contributions.forEach((contribution) => {
                        this.$unregisterDebuggerContribution({
                            type: contribution.type,
                            label: contribution.label || contribution.type,
                        });
                        this.logger.log(`Debugger contribution has been unregistered: ${contribution.type}`);
                    });
                }
                else {
                    this.proxy.$registerDebuggerContributions(path, contributions);
                    contributions.forEach((contribution) => {
                        this.$registerDebuggerContribution({
                            type: contribution.type,
                            label: contribution.label || contribution.type,
                        });
                        this.logger.log(`Debugger contribution has been registered: ${contribution.type}`);
                    });
                }
            }),
        ]);
    }
    registerDebugContributions() {
        const debugContributionPoints = this.debugService.debugContributionPoints;
        // 需确保在贡献点注册完后执行
        // 将ContributionPoints中的debuggers数据传递给插件
        // 后续时序若发生调整，这块逻辑也需要调整
        for (const [folder, contributions] of debugContributionPoints) {
            this.proxy.$registerDebuggerContributions(folder, contributions);
            contributions.forEach((contribution) => {
                this.$registerDebuggerContribution({
                    type: contribution.type,
                    label: contribution.label || contribution.type,
                });
                this.logger.log(`Debugger contribution has been registered: ${contribution.type}`);
            });
        }
    }
    async $appendToDebugConsole(value) {
        if (this.debugConsoleModelService.debugConsoleSession) {
            this.debugConsoleModelService.debugConsoleSession.append(value);
        }
    }
    async $appendLineToDebugConsole(value) {
        if (this.debugConsoleModelService.debugConsoleSession) {
            this.debugConsoleModelService.debugConsoleSession.appendLine(value);
        }
    }
    async $unregisterDebuggerContribution(description) {
        const disposable = this.toDispose.get(description.type);
        disposable === null || disposable === void 0 ? void 0 : disposable.dispose();
    }
    async $registerDebuggerContribution(description) {
        const disposable = new ide_core_browser_1.DisposableCollection();
        const terminalOptionsExt = await this.proxy.$getTerminalCreationOptions(description.type);
        this.toDispose.set(description.type, disposable);
        const debugSessionFactory = new debug_1.ExtensionDebugSessionFactory(this.editorService, this.breakpointManager, this.modelManager, this.terminalService, this.labelService, this.messageService, this.debugPreferences, async (sessionId) => await this.mainThreadConnection.ensureConnection(sessionId), this.fileService, terminalOptionsExt, this.debugPreferences, this.outputService, this.injector, this.sessionManager);
        disposable.pushAll([
            this.adapterContributionRegister.registerDebugAdapterContribution(new extension_debug_adapter_contribution_1.ExtensionDebugAdapterContribution(description, this.proxy, this.activationEventService)),
            this.sessionContributionRegistry.registerDebugSessionContribution({
                debugType: description.type,
                debugSessionFactory: () => debugSessionFactory,
            }),
        ]);
    }
    async $addBreakpoints(breakpoints) {
        const newBreakpoints = new Map();
        breakpoints.forEach((b) => newBreakpoints.set(b.id, b));
        this.breakpointManager.findMarkers({
            dataFilter: (data) => {
                // 至存储未被标记的断点信息
                if (newBreakpoints.has(data.id)) {
                    newBreakpoints.delete(data.id);
                }
                return false;
            },
        });
        for (const breakpoint of newBreakpoints.values()) {
            if (breakpoint.location) {
                const location = breakpoint.location;
                this.breakpointManager.addBreakpoint(breakpoint_1.DebugBreakpoint.create(ide_core_browser_1.Uri.revive(location.uri), {
                    line: breakpoint.location.range.startLineNumber + 1,
                    column: 1,
                    condition: breakpoint.condition,
                    hitCondition: breakpoint.hitCondition,
                    logMessage: breakpoint.logMessage,
                }, true));
            }
        }
    }
    async $removeBreakpoints(breakpoints) {
        const ids = new Set();
        breakpoints.forEach((b) => ids.add(b.id));
        for (const origin of this.breakpointManager.findMarkers({ dataFilter: (data) => ids.has(data.id) })) {
            const model = this.modelManager.resolve(new ide_core_browser_1.URI(origin.data.uri));
            if (model && model[0].breakpoint) {
                this.breakpointManager.delBreakpoint(model[0].breakpoint);
            }
        }
    }
    async $customRequest(sessionId, command, args) {
        const session = this.sessionManager.getSession(sessionId);
        if (session) {
            return session.sendCustomRequest(command, args);
        }
        throw new Error(`Debug session '${sessionId}' not found`);
    }
    $getDebugProtocolBreakpoint(sessionId, breakpoinId) {
        const session = this.sessionManager.getSession(sessionId);
        if (session) {
            return Promise.resolve(session.getDebugProtocolBreakpoint(breakpoinId));
        }
        return Promise.reject(new Error('debug session not found'));
    }
    async $startDebugging(folder, nameOrConfiguration, options) {
        let configuration;
        let index = 0;
        if (typeof nameOrConfiguration === 'string') {
            for (const options of this.debugConfigurationManager.all) {
                if (options.configuration.name === nameOrConfiguration) {
                    configuration = options.configuration;
                    break;
                }
                index++;
            }
        }
        else {
            configuration = nameOrConfiguration;
        }
        if (!configuration) {
            throw new Error(`No configuration ${nameOrConfiguration}`);
        }
        const debugOptions = {
            noDebug: false,
            parentSession: this.sessionManager.getSession(options.parentSessionID),
            repl: options.repl,
            compact: options.compact,
            lifecycleManagedByParent: options.lifecycleManagedByParent,
        };
        const session = await this.sessionManager.start({
            configuration,
            workspaceFolderUri: folder && ide_core_browser_1.Uri.revive(folder.uri).toString(),
            index,
            ...debugOptions,
        });
        return !!session;
    }
    $stopDebugging(sessionId) {
        if (sessionId) {
            const session = this.sessionManager.getSession(sessionId);
            if (session) {
                return this.sessionManager.stopSession(session);
            }
        }
        else {
            // stop all
            return this.sessionManager.stopSession(undefined);
        }
        throw new Error(`Debug session '${sessionId}' not found`);
    }
    toCustomApiBreakpoints(sourceBreakpoints) {
        return sourceBreakpoints.map((b) => ({
            id: b.id,
            enabled: b.enabled,
            condition: b.raw.condition,
            hitCondition: b.raw.hitCondition,
            logMessage: b.raw.logMessage,
            location: {
                uri: ide_core_browser_1.Uri.parse(b.uri),
                range: {
                    startLineNumber: b.raw.line - 1,
                    startColumn: (b.raw.column || 1) - 1,
                    endLineNumber: b.raw.line - 1,
                    endColumn: (b.raw.column || 1) - 1,
                },
            },
        }));
    }
};
exports.MainThreadDebug = MainThreadDebug;
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_session_1.IDebugSessionManager),
    tslib_1.__metadata("design:type", debug_session_manager_1.DebugSessionManager)
], MainThreadDebug.prototype, "sessionManager", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(services_1.LabelService),
    tslib_1.__metadata("design:type", services_1.LabelService)
], MainThreadDebug.prototype, "labelService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(breakpoint_1.BreakpointManager),
    tslib_1.__metadata("design:type", breakpoint_1.BreakpointManager)
], MainThreadDebug.prototype, "breakpointManager", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_debug_1.IDebugModelManager),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "modelManager", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_configuration_manager_1.DebugConfigurationManager),
    tslib_1.__metadata("design:type", debug_configuration_manager_1.DebugConfigurationManager)
], MainThreadDebug.prototype, "debugConfigurationManager", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_preferences_1.DebugPreferences),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "debugPreferences", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_editor_1.WorkbenchEditorService),
    tslib_1.__metadata("design:type", ide_editor_1.WorkbenchEditorService)
], MainThreadDebug.prototype, "editorService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_overlay_1.IMessageService),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "messageService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_file_service_1.IFileServiceClient),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "fileService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_service_1.IDebugServer),
    tslib_1.__metadata("design:type", extension_debug_service_1.ExtensionDebugService)
], MainThreadDebug.prototype, "adapterContributionRegister", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(types_1.IActivationEventService),
    tslib_1.__metadata("design:type", types_1.IActivationEventService)
], MainThreadDebug.prototype, "activationEventService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_session_contribution_1.DebugSessionContributionRegistry),
    tslib_1.__metadata("design:type", debug_1.ExtensionDebugSessionContributionRegistry)
], MainThreadDebug.prototype, "sessionContributionRegistry", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_core_browser_1.ILogger),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "logger", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_terminal_next_1.ITerminalApiService),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "terminalService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_debug_1.IDebugConsoleModelService),
    tslib_1.__metadata("design:type", debug_console_tree_model_service_1.DebugConsoleModelService)
], MainThreadDebug.prototype, "debugConsoleModelService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(output_service_1.OutputService),
    tslib_1.__metadata("design:type", output_service_1.OutputService)
], MainThreadDebug.prototype, "outputService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(debug_service_1.IDebugService),
    tslib_1.__metadata("design:type", Object)
], MainThreadDebug.prototype, "debugService", void 0);
tslib_1.__decorate([
    (0, di_1.Autowired)(di_1.INJECTOR_TOKEN),
    tslib_1.__metadata("design:type", di_1.Injector)
], MainThreadDebug.prototype, "injector", void 0);
exports.MainThreadDebug = MainThreadDebug = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__param(0, (0, di_1.Optional)(ide_connection_1.IRPCProtocol)),
    tslib_1.__param(1, (0, di_1.Optional)(vscode_1.IInterProcessConnectionService)),
    tslib_1.__metadata("design:paramtypes", [Object, Object])
], MainThreadDebug);
//# sourceMappingURL=main.thread.debug.js.map