import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { append, addDisposableListener, EventType, $ as $$1 } from '../../../../base/browser/dom.js';
import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';
import { Button } from '../../../../base/browser/ui/button/button.js';
import { SelectBox } from '../../../../base/browser/ui/selectBox/selectBox.js';
import { onUnexpectedError } from '../../../../base/common/errors.js';
import { KeyCode, KeyMod as KeyMod$1 } from '../../../../base/common/keyCodes.js';
import { dispose } from '../../../../base/common/lifecycle.js';
import { URI } from '../../../../base/common/uri.js';
import './media/breakpointWidget.css.js';
import { EditorCommand, registerEditorCommand } from '../../../../editor/browser/editorExtensions.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';
import { EditorOption } from '../../../../editor/common/config/editorOptions.js';
import { Position } from '../../../../editor/common/core/position.js';
import { Range } from '../../../../editor/common/core/range.js';
import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';
import { CompletionItemKind } from '../../../../editor/common/languages.js';
import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modesRegistry.js';
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
import { IModelService } from '../../../../editor/common/services/model.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { provideSuggestionItems, CompletionOptions } from '../../../../editor/contrib/suggest/browser/suggest.js';
import { ZoneWidget } from '../../../../editor/contrib/zoneWidget/browser/zoneWidget.js';
import { localizeWithPath } from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.service.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.service.js';
import { IContextViewService } from '../../../../platform/contextview/browser/contextView.service.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.service.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { ILabelService } from '../../../../platform/label/common/label.service.js';
import { defaultSelectBoxStyles, defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import '../../../../platform/theme/common/colorUtils.js';
import '../../../../platform/theme/common/colors/baseColors.js';
import '../../../../platform/theme/common/colors/chartsColors.js';
import { editorForeground } from '../../../../platform/theme/common/colors/editorColors.js';
import '../../../../platform/theme/common/colors/inputColors.js';
import '../../../../platform/theme/common/colors/listColors.js';
import '../../../../platform/theme/common/colors/menuColors.js';
import '../../../../platform/theme/common/colors/minimapColors.js';
import '../../../../platform/theme/common/colors/miscColors.js';
import '../../../../platform/theme/common/colors/quickpickColors.js';
import '../../../../platform/theme/common/colors/searchColors.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.service.js';
import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from '../../codeEditor/browser/simpleEditorOptions.js';
import { CONTEXT_BREAKPOINT_WIDGET_VISIBLE, CONTEXT_IN_BREAKPOINT_WIDGET, BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, DEBUG_SCHEME } from '../common/debug.js';
import { IDebugService } from '../common/debug.service.js';
import { IPrivateBreakpointWidgetService } from './breakpointWidget.service.js';
const _moduleId = "vs/workbench/contrib/debug/browser/breakpointWidget";
const $ = $$1;
const DECORATION_KEY = 'breakpointwidgetdecoration';
function isPositionInCurlyBracketBlock(input) {
    const model = input.getModel();
    const bracketPairs = model.bracketPairs.getBracketPairsInRange(Range.fromPositions(input.getPosition()));
    return (
         (bracketPairs.some(p => p.openingBracketInfo.bracketText === '{'))
    );
}
function createDecorations(theme, placeHolder) {
    const transparentForeground = theme.getColor(editorForeground)?.transparent(0.4);
    return [{
            range: {
                startLineNumber: 0,
                endLineNumber: 0,
                startColumn: 0,
                endColumn: 1
            },
            renderOptions: {
                after: {
                    contentText: placeHolder,
                    color: transparentForeground ? ( (transparentForeground.toString())) : undefined
                }
            }
        }];
}
let BreakpointWidget = class BreakpointWidget extends ZoneWidget {
    constructor(editor, lineNumber, column, context, contextViewService, debugService, themeService, contextKeyService, instantiationService, modelService, codeEditorService, _configurationService, languageFeaturesService, keybindingService, labelService, textModelService) {
        super(editor, { showFrame: true, showArrow: false, frameWidth: 1, isAccessible: true });
        this.lineNumber = lineNumber;
        this.column = column;
        this.contextViewService = contextViewService;
        this.debugService = debugService;
        this.themeService = themeService;
        this.contextKeyService = contextKeyService;
        this.instantiationService = instantiationService;
        this.modelService = modelService;
        this.codeEditorService = codeEditorService;
        this._configurationService = _configurationService;
        this.languageFeaturesService = languageFeaturesService;
        this.keybindingService = keybindingService;
        this.labelService = labelService;
        this.textModelService = textModelService;
        this.conditionInput = '';
        this.hitCountInput = '';
        this.logMessageInput = '';
        this.toDispose = [];
        const model = this.editor.getModel();
        if (model) {
            const uri = model.uri;
            const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, column: this.column, uri });
            this.breakpoint = breakpoints.length ? breakpoints[0] : undefined;
        }
        if (context === undefined) {
            if (this.breakpoint && !this.breakpoint.condition && !this.breakpoint.hitCondition && this.breakpoint.logMessage) {
                this.context = BreakpointWidgetContext.LOG_MESSAGE;
            }
            else if (this.breakpoint && !this.breakpoint.condition && this.breakpoint.hitCondition) {
                this.context = BreakpointWidgetContext.HIT_COUNT;
            }
            else if (this.breakpoint && this.breakpoint.triggeredBy) {
                this.context = BreakpointWidgetContext.TRIGGER_POINT;
            }
            else {
                this.context = BreakpointWidgetContext.CONDITION;
            }
        }
        else {
            this.context = context;
        }
        this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => {
            if (this.breakpoint && e && e.removed && e.removed.indexOf(this.breakpoint) >= 0) {
                this.dispose();
            }
        }));
        this.codeEditorService.registerDecorationType('breakpoint-widget', DECORATION_KEY, {});
        this.create();
    }
    get placeholder() {
        const acceptString = this.keybindingService.lookupKeybinding(AcceptBreakpointWidgetInputAction.ID)?.getLabel() || 'Enter';
        const closeString = this.keybindingService.lookupKeybinding(CloseBreakpointWidgetCommand.ID)?.getLabel() || 'Escape';
        switch (this.context) {
            case BreakpointWidgetContext.LOG_MESSAGE:
                return ( localizeWithPath(
                    _moduleId,
                    0,
                    "Message to log when breakpoint is hit. Expressions within {} are interpolated. '{0}' to accept, '{1}' to cancel.",
                    acceptString,
                    closeString
                ));
            case BreakpointWidgetContext.HIT_COUNT:
                return ( localizeWithPath(
                    _moduleId,
                    1,
                    "Break when hit count condition is met. '{0}' to accept, '{1}' to cancel.",
                    acceptString,
                    closeString
                ));
            default:
                return ( localizeWithPath(
                    _moduleId,
                    2,
                    "Break when expression evaluates to true. '{0}' to accept, '{1}' to cancel.",
                    acceptString,
                    closeString
                ));
        }
    }
    getInputValue(breakpoint) {
        switch (this.context) {
            case BreakpointWidgetContext.LOG_MESSAGE:
                return breakpoint && breakpoint.logMessage ? breakpoint.logMessage : this.logMessageInput;
            case BreakpointWidgetContext.HIT_COUNT:
                return breakpoint && breakpoint.hitCondition ? breakpoint.hitCondition : this.hitCountInput;
            default:
                return breakpoint && breakpoint.condition ? breakpoint.condition : this.conditionInput;
        }
    }
    rememberInput() {
        if (this.context !== BreakpointWidgetContext.TRIGGER_POINT) {
            const value = this.input.getModel().getValue();
            switch (this.context) {
                case BreakpointWidgetContext.LOG_MESSAGE:
                    this.logMessageInput = value;
                    break;
                case BreakpointWidgetContext.HIT_COUNT:
                    this.hitCountInput = value;
                    break;
                default:
                    this.conditionInput = value;
            }
        }
    }
    setInputMode() {
        if (this.editor.hasModel()) {
            const languageId = this.context === BreakpointWidgetContext.LOG_MESSAGE ? PLAINTEXT_LANGUAGE_ID : this.editor.getModel().getLanguageId();
            this.input.getModel().setLanguage(languageId);
        }
    }
    show(rangeOrPos) {
        const lineNum = this.input.getModel().getLineCount();
        super.show(rangeOrPos, lineNum + 1);
    }
    fitHeightToContent() {
        const lineNum = this.input.getModel().getLineCount();
        this._relayout(lineNum + 1);
    }
    _fillContainer(container) {
        this.setCssClass('breakpoint-widget');
        const selectBox = ( (new SelectBox([
            { text: ( localizeWithPath(_moduleId, 3, "Expression")) },
            { text: ( localizeWithPath(_moduleId, 4, "Hit Count")) },
            { text: ( localizeWithPath(_moduleId, 5, "Log Message")) },
            { text: ( localizeWithPath(_moduleId, 6, "Wait for Breakpoint")) },
        ], this.context, this.contextViewService, defaultSelectBoxStyles, { ariaLabel: ( localizeWithPath(_moduleId, 7, 'Breakpoint Type')) })));
        this.selectContainer = $('.breakpoint-select-container');
        selectBox.render(append(container, this.selectContainer));
        selectBox.onDidSelect(e => {
            this.rememberInput();
            this.context = e.index;
            this.updateContextInput();
        });
        this.createModesInput(container);
        this.inputContainer = $('.inputContainer');
        this.createBreakpointInput(append(container, this.inputContainer));
        this.input.getModel().setValue(this.getInputValue(this.breakpoint));
        this.toDispose.push(this.input.getModel().onDidChangeContent(() => {
            this.fitHeightToContent();
        }));
        this.input.setPosition({ lineNumber: 1, column: this.input.getModel().getLineMaxColumn(1) });
        this.createTriggerBreakpointInput(container);
        this.updateContextInput();
        setTimeout(() => this.focusInput(), 150);
    }
    createModesInput(container) {
        const modes = this.debugService.getModel().getBreakpointModes('source');
        if (modes.length <= 1) {
            return;
        }
        const sb = this.selectModeBox = ( (new SelectBox([
            { text: ( localizeWithPath(_moduleId, 8, 'Mode')), isDisabled: true },
            ...( (modes.map(mode => ({ text: mode.label, description: mode.description })))),
        ], modes.findIndex(m => m.mode === this.breakpoint?.mode) + 1, this.contextViewService, defaultSelectBoxStyles)));
        this.toDispose.push(sb);
        this.toDispose.push(sb.onDidSelect(e => {
            this.modeInput = modes[e.index - 1];
        }));
        const modeWrapper = $('.select-mode-container');
        const selectionWrapper = $('.select-box-container');
        append(modeWrapper, selectionWrapper);
        sb.render(selectionWrapper);
        append(container, modeWrapper);
    }
    createTriggerBreakpointInput(container) {
        const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp !== this.breakpoint && !bp.logMessage);
        const breakpointOptions = [
            { text: ( localizeWithPath(_moduleId, 9, 'None')), isDisabled: true },
            ...( (breakpoints.map(bp => ({
                text: `${this.labelService.getUriLabel(bp.uri, { relative: true })}: ${bp.lineNumber}`,
                description: ( localizeWithPath(_moduleId, 10, 'Loading...'))
            })))),
        ];
        const index = breakpoints.findIndex((bp) => this.breakpoint?.triggeredBy === bp.getId());
        for (const [i, bp] of breakpoints.entries()) {
            this.textModelService.createModelReference(bp.uri).then(ref => {
                try {
                    breakpointOptions[i + 1].description = ref.object.textEditorModel.getLineContent(bp.lineNumber).trim();
                }
                finally {
                    ref.dispose();
                }
            }).catch(() => {
                breakpointOptions[i + 1].description = ( localizeWithPath(_moduleId, 11, 'Could not load source.'));
            });
        }
        const selectBreakpointBox = this.selectBreakpointBox = ( (new SelectBox(
            breakpointOptions,
            index + 1,
            this.contextViewService,
            defaultSelectBoxStyles,
            { ariaLabel: ( localizeWithPath(_moduleId, 12, 'Select breakpoint')) }
        )));
        selectBreakpointBox.onDidSelect(e => {
            if (e.index === 0) {
                this.triggeredByBreakpointInput = undefined;
            }
            else {
                this.triggeredByBreakpointInput = breakpoints[e.index - 1];
            }
        });
        this.toDispose.push(selectBreakpointBox);
        this.selectBreakpointContainer = $('.select-breakpoint-container');
        this.toDispose.push(addDisposableListener(this.selectBreakpointContainer, EventType.KEY_DOWN, e => {
            const event = ( (new StandardKeyboardEvent(e)));
            if (event.equals(KeyCode.Escape)) {
                this.close(false);
            }
        }));
        const selectionWrapper = $('.select-box-container');
        append(this.selectBreakpointContainer, selectionWrapper);
        selectBreakpointBox.render(selectionWrapper);
        append(container, this.selectBreakpointContainer);
        const closeButton = ( (new Button(this.selectBreakpointContainer, defaultButtonStyles)));
        closeButton.label = ( localizeWithPath(_moduleId, 13, "Ok"));
        this.toDispose.push(closeButton.onDidClick(() => this.close(true)));
        this.toDispose.push(closeButton);
    }
    updateContextInput() {
        if (this.context === BreakpointWidgetContext.TRIGGER_POINT) {
            this.inputContainer.hidden = true;
            this.selectBreakpointContainer.hidden = false;
        }
        else {
            this.inputContainer.hidden = false;
            this.selectBreakpointContainer.hidden = true;
            this.setInputMode();
            const value = this.getInputValue(this.breakpoint);
            this.input.getModel().setValue(value);
            this.focusInput();
        }
    }
    _doLayout(heightInPixel, widthInPixel) {
        this.heightInPx = heightInPixel;
        this.input.layout({ height: heightInPixel, width: widthInPixel - 113 });
        this.centerInputVertically();
    }
    _onWidth(widthInPixel) {
        if (typeof this.heightInPx === 'number') {
            this._doLayout(this.heightInPx, widthInPixel);
        }
    }
    createBreakpointInput(container) {
        const scopedContextKeyService = this.contextKeyService.createScoped(container);
        this.toDispose.push(scopedContextKeyService);
        const scopedInstatiationService = this.instantiationService.createChild(( (new ServiceCollection(
            [IContextKeyService, scopedContextKeyService],
            [IPrivateBreakpointWidgetService, this]
        ))));
        this.toDispose.push(scopedInstatiationService);
        const options = this.createEditorOptions();
        const codeEditorWidgetOptions = getSimpleCodeEditorWidgetOptions();
        this.input = scopedInstatiationService.createInstance(CodeEditorWidget, container, options, codeEditorWidgetOptions);
        CONTEXT_IN_BREAKPOINT_WIDGET.bindTo(scopedContextKeyService).set(true);
        const model = this.modelService.createModel('', null, ( URI.parse(`${DEBUG_SCHEME}:${this.editor.getId()}:breakpointinput`)), true);
        if (this.editor.hasModel()) {
            model.setLanguage(this.editor.getModel().getLanguageId());
        }
        this.input.setModel(model);
        this.setInputMode();
        this.toDispose.push(model);
        const setDecorations = () => {
            const value = this.input.getModel().getValue();
            const decorations = !!value ? [] : createDecorations(this.themeService.getColorTheme(), this.placeholder);
            this.input.setDecorationsByType('breakpoint-widget', DECORATION_KEY, decorations);
        };
        this.input.getModel().onDidChangeContent(() => setDecorations());
        this.themeService.onDidColorThemeChange(() => setDecorations());
        this.toDispose.push(this.languageFeaturesService.completionProvider.register({ scheme: DEBUG_SCHEME, hasAccessToAllModels: true }, {
            _debugDisplayName: 'breakpointWidget',
            provideCompletionItems: (model, position, _context, token) => {
                let suggestionsPromise;
                const underlyingModel = this.editor.getModel();
                if (underlyingModel && (this.context === BreakpointWidgetContext.CONDITION || (this.context === BreakpointWidgetContext.LOG_MESSAGE && isPositionInCurlyBracketBlock(this.input)))) {
                    suggestionsPromise = provideSuggestionItems(this.languageFeaturesService.completionProvider, underlyingModel, ( (new Position(this.lineNumber, 1))), ( (new CompletionOptions(undefined, ( (new Set())).add(CompletionItemKind.Snippet)))), _context, token).then(suggestions => {
                        let overwriteBefore = 0;
                        if (this.context === BreakpointWidgetContext.CONDITION) {
                            overwriteBefore = position.column - 1;
                        }
                        else {
                            const value = this.input.getModel().getValue();
                            while ((position.column - 2 - overwriteBefore >= 0) && value[position.column - 2 - overwriteBefore] !== '{' && value[position.column - 2 - overwriteBefore] !== ' ') {
                                overwriteBefore++;
                            }
                        }
                        return {
                            suggestions: ( (suggestions.items.map(s => {
                                s.completion.range = Range.fromPositions(position.delta(0, -overwriteBefore), position);
                                return s.completion;
                            })))
                        };
                    });
                }
                else {
                    suggestionsPromise = Promise.resolve({ suggestions: [] });
                }
                return suggestionsPromise;
            }
        }));
        this.toDispose.push(this._configurationService.onDidChangeConfiguration((e) => {
            if (e.affectsConfiguration('editor.fontSize') || e.affectsConfiguration('editor.lineHeight')) {
                this.input.updateOptions(this.createEditorOptions());
                this.centerInputVertically();
            }
        }));
    }
    createEditorOptions() {
        const editorConfig = this._configurationService.getValue('editor');
        const options = getSimpleEditorOptions(this._configurationService);
        options.fontSize = editorConfig.fontSize;
        options.fontFamily = editorConfig.fontFamily;
        options.lineHeight = editorConfig.lineHeight;
        options.fontLigatures = editorConfig.fontLigatures;
        options.ariaLabel = this.placeholder;
        return options;
    }
    centerInputVertically() {
        if (this.container && typeof this.heightInPx === 'number') {
            const lineHeight = this.input.getOption(EditorOption.lineHeight);
            const lineNum = this.input.getModel().getLineCount();
            const newTopMargin = (this.heightInPx - lineNum * lineHeight) / 2;
            this.inputContainer.style.marginTop = newTopMargin + 'px';
        }
    }
    close(success) {
        if (success) {
            let condition = undefined;
            let hitCondition = undefined;
            let logMessage = undefined;
            let triggeredBy = undefined;
            let mode = undefined;
            let modeLabel = undefined;
            this.rememberInput();
            if (this.conditionInput || this.context === BreakpointWidgetContext.CONDITION) {
                condition = this.conditionInput;
            }
            if (this.hitCountInput || this.context === BreakpointWidgetContext.HIT_COUNT) {
                hitCondition = this.hitCountInput;
            }
            if (this.logMessageInput || this.context === BreakpointWidgetContext.LOG_MESSAGE) {
                logMessage = this.logMessageInput;
            }
            if (this.selectModeBox) {
                mode = this.modeInput?.mode;
                modeLabel = this.modeInput?.label;
            }
            if (this.context === BreakpointWidgetContext.TRIGGER_POINT) {
                condition = undefined;
                hitCondition = undefined;
                logMessage = undefined;
                triggeredBy = this.triggeredByBreakpointInput?.getId();
            }
            if (this.breakpoint) {
                const data = ( (new Map()));
                data.set(this.breakpoint.getId(), {
                    condition,
                    hitCondition,
                    logMessage,
                    triggeredBy,
                    mode,
                    modeLabel,
                });
                this.debugService.updateBreakpoints(this.breakpoint.originalUri, data, false).then(undefined, onUnexpectedError);
            }
            else {
                const model = this.editor.getModel();
                if (model) {
                    this.debugService.addBreakpoints(model.uri, [{
                            lineNumber: this.lineNumber,
                            column: this.column,
                            enabled: true,
                            condition,
                            hitCondition,
                            logMessage,
                            triggeredBy,
                            mode,
                            modeLabel,
                        }]);
                }
            }
        }
        this.dispose();
    }
    focusInput() {
        if (this.context === BreakpointWidgetContext.TRIGGER_POINT) {
            this.selectBreakpointBox.focus();
        }
        else {
            this.input.focus();
        }
    }
    dispose() {
        super.dispose();
        this.input.dispose();
        dispose(this.toDispose);
        setTimeout(() => this.editor.focus(), 0);
    }
};
BreakpointWidget = ( (__decorate([
    ( (__param(4, IContextViewService))),
    ( (__param(5, IDebugService))),
    ( (__param(6, IThemeService))),
    ( (__param(7, IContextKeyService))),
    ( (__param(8, IInstantiationService))),
    ( (__param(9, IModelService))),
    ( (__param(10, ICodeEditorService))),
    ( (__param(11, IConfigurationService))),
    ( (__param(12, ILanguageFeaturesService))),
    ( (__param(13, IKeybindingService))),
    ( (__param(14, ILabelService))),
    ( (__param(15, ITextModelService)))
], BreakpointWidget)));
class AcceptBreakpointWidgetInputAction extends EditorCommand {
    static { this.ID = 'breakpointWidget.action.acceptInput'; }
    constructor() {
        super({
            id: AcceptBreakpointWidgetInputAction.ID,
            precondition: CONTEXT_BREAKPOINT_WIDGET_VISIBLE,
            kbOpts: {
                kbExpr: CONTEXT_IN_BREAKPOINT_WIDGET,
                primary: KeyCode.Enter,
                weight: KeybindingWeight.EditorContrib
            }
        });
    }
    runEditorCommand(accessor, editor) {
        accessor.get(IPrivateBreakpointWidgetService).close(true);
    }
}
class CloseBreakpointWidgetCommand extends EditorCommand {
    static { this.ID = 'closeBreakpointWidget'; }
    constructor() {
        super({
            id: CloseBreakpointWidgetCommand.ID,
            precondition: CONTEXT_BREAKPOINT_WIDGET_VISIBLE,
            kbOpts: {
                kbExpr: EditorContextKeys.textInputFocus,
                primary: KeyCode.Escape,
                secondary: [KeyMod$1.Shift | KeyCode.Escape],
                weight: KeybindingWeight.EditorContrib
            }
        });
    }
    runEditorCommand(accessor, editor, args) {
        const debugContribution = editor.getContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID);
        if (debugContribution) {
            return debugContribution.closeBreakpointWidget();
        }
        accessor.get(IPrivateBreakpointWidgetService).close(false);
    }
}
registerEditorCommand(( (new AcceptBreakpointWidgetInputAction())));
registerEditorCommand(( (new CloseBreakpointWidgetCommand())));
export { BreakpointWidget };
