import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { KeyChord } from '../../../../base/common/keyCodes.js';
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { registerEditorContribution, registerEditorAction, EditorAction } from '../../../browser/editorExtensions.js';
import { Range } from '../../../common/core/range.js';
import { EditorContextKeys } from '../../../common/editorContextKeys.js';
import { ILanguageService } from '../../../common/languages/language.js';
import { GotoDefinitionAtPositionEditorContribution } from '../../gotoSymbol/browser/link/goToDefinitionAtPosition.js';
import { ContentHoverWidget, ContentHoverController } from './contentHover.js';
import { MarginHoverWidget } from './marginHover.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.service.js';
import '../../../../platform/theme/common/colorUtils.js';
import '../../../../platform/theme/common/colors/baseColors.js';
import '../../../../platform/theme/common/colors/chartsColors.js';
import { editorHoverBorder } 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 { registerThemingParticipant } from '../../../../platform/theme/common/themeService.js';
import { HoverParticipantRegistry } from './hoverTypes.js';
import { MarkdownHoverParticipant } from './markdownHoverParticipant.js';
import { MarkerHoverParticipant } from './markerHoverParticipant.js';
import { InlineSuggestionHintsContentWidget } from '../../inlineCompletions/browser/inlineCompletionsHintsWidget.js';
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.service.js';
import { RunOnceScheduler } from '../../../../base/common/async.js';
import { localizeWithPath } from '../../../../nls.js';
import './hover.css.js';
var HoverController_1;
const _moduleId = "vs/editor/contrib/hover/browser/hover";
const _sticky = false;
let HoverController = class HoverController extends Disposable {
    static { HoverController_1 = this; }
    static { this.ID = 'editor.contrib.hover'; }
    constructor(_editor, _instantiationService, _openerService, _languageService, _keybindingService) {
        super();
        this._editor = _editor;
        this._instantiationService = _instantiationService;
        this._openerService = _openerService;
        this._languageService = _languageService;
        this._keybindingService = _keybindingService;
        this._listenersStore = ( (new DisposableStore()));
        this._hoverState = {
            mouseDown: false,
            contentHoverFocused: false,
            activatedByDecoratorClick: false
        };
        this._reactToEditorMouseMoveRunner = this._register(( (new RunOnceScheduler(() => this._reactToEditorMouseMove(this._mouseMoveEvent), 0))));
        this._hookListeners();
        this._register(this._editor.onDidChangeConfiguration((e) => {
            if (e.hasChanged(60 )) {
                this._unhookListeners();
                this._hookListeners();
            }
        }));
    }
    static get(editor) {
        return editor.getContribution(HoverController_1.ID);
    }
    _hookListeners() {
        const hoverOpts = this._editor.getOption(60 );
        this._hoverSettings = {
            enabled: hoverOpts.enabled,
            sticky: hoverOpts.sticky,
            hidingDelay: hoverOpts.delay
        };
        if (hoverOpts.enabled) {
            this._listenersStore.add(this._editor.onMouseDown((e) => this._onEditorMouseDown(e)));
            this._listenersStore.add(this._editor.onMouseUp(() => this._onEditorMouseUp()));
            this._listenersStore.add(this._editor.onMouseMove((e) => this._onEditorMouseMove(e)));
            this._listenersStore.add(this._editor.onKeyDown((e) => this._onKeyDown(e)));
        }
        else {
            this._listenersStore.add(this._editor.onMouseMove((e) => this._onEditorMouseMove(e)));
            this._listenersStore.add(this._editor.onKeyDown((e) => this._onKeyDown(e)));
        }
        this._listenersStore.add(this._editor.onMouseLeave((e) => this._onEditorMouseLeave(e)));
        this._listenersStore.add(this._editor.onDidChangeModel(() => {
            this._cancelScheduler();
            this._hideWidgets();
        }));
        this._listenersStore.add(this._editor.onDidChangeModelContent(() => this._cancelScheduler()));
        this._listenersStore.add(this._editor.onDidScrollChange((e) => this._onEditorScrollChanged(e)));
    }
    _unhookListeners() {
        this._listenersStore.clear();
    }
    _cancelScheduler() {
        this._mouseMoveEvent = undefined;
        this._reactToEditorMouseMoveRunner.cancel();
    }
    _onEditorScrollChanged(e) {
        if (e.scrollTopChanged || e.scrollLeftChanged) {
            this._hideWidgets();
        }
    }
    _onEditorMouseDown(mouseEvent) {
        this._hoverState.mouseDown = true;
        const target = mouseEvent.target;
        if (target.type === 9  && target.detail === ContentHoverWidget.ID) {
            this._hoverState.contentHoverFocused = true;
            return;
        }
        if (target.type === 12  && target.detail === MarginHoverWidget.ID) {
            return;
        }
        if (target.type !== 12 ) {
            this._hoverState.contentHoverFocused = false;
        }
        if (this._contentWidget?.widget.isResizing) {
            return;
        }
        this._hideWidgets();
    }
    _onEditorMouseUp() {
        this._hoverState.mouseDown = false;
    }
    _onEditorMouseLeave(mouseEvent) {
        this._cancelScheduler();
        const targetElement = (mouseEvent.event.browserEvent.relatedTarget);
        if (this._contentWidget?.widget.isResizing || this._contentWidget?.containsNode(targetElement)) {
            return;
        }
        this._hideWidgets();
    }
    _isMouseOverWidget(mouseEvent) {
        const target = mouseEvent.target;
        const sticky = this._hoverSettings.sticky;
        if (sticky
            && target.type === 9
            && target.detail === ContentHoverWidget.ID) {
            return true;
        }
        if (sticky
            && this._contentWidget?.containsNode(mouseEvent.event.browserEvent.view?.document.activeElement)
            && !mouseEvent.event.browserEvent.view?.getSelection()?.isCollapsed) {
            return true;
        }
        if (!sticky
            && target.type === 9
            && target.detail === ContentHoverWidget.ID
            && this._contentWidget?.isColorPickerVisible) {
            return true;
        }
        if (sticky
            && target.type === 12
            && target.detail === MarginHoverWidget.ID) {
            return true;
        }
        return false;
    }
    _onEditorMouseMove(mouseEvent) {
        this._mouseMoveEvent = mouseEvent;
        if (this._contentWidget?.isFocused || this._contentWidget?.isResizing) {
            return;
        }
        if (this._hoverState.mouseDown && this._hoverState.contentHoverFocused) {
            return;
        }
        const sticky = this._hoverSettings.sticky;
        if (sticky && this._contentWidget?.isVisibleFromKeyboard) {
            return;
        }
        const mouseIsOverWidget = this._isMouseOverWidget(mouseEvent);
        if (mouseIsOverWidget) {
            this._reactToEditorMouseMoveRunner.cancel();
            return;
        }
        const hidingDelay = this._hoverSettings.hidingDelay;
        if (this._contentWidget?.isVisible && sticky && hidingDelay > 0) {
            if (!this._reactToEditorMouseMoveRunner.isScheduled()) {
                this._reactToEditorMouseMoveRunner.schedule(hidingDelay);
            }
            return;
        }
        this._reactToEditorMouseMove(mouseEvent);
    }
    _reactToEditorMouseMove(mouseEvent) {
        if (!mouseEvent) {
            return;
        }
        const target = mouseEvent.target;
        const mouseOnDecorator = target.element?.classList.contains('colorpicker-color-decoration');
        const decoratorActivatedOn = this._editor.getOption(148 );
        const enabled = this._hoverSettings.enabled;
        const activatedByDecoratorClick = this._hoverState.activatedByDecoratorClick;
        if ((mouseOnDecorator && ((decoratorActivatedOn === 'click' && !activatedByDecoratorClick) ||
            (decoratorActivatedOn === 'hover' && !enabled && !_sticky) ||
            (decoratorActivatedOn === 'clickAndHover' && !enabled && !activatedByDecoratorClick))) || (!mouseOnDecorator && !enabled && !activatedByDecoratorClick)) {
            this._hideWidgets();
            return;
        }
        const contentWidget = this._getOrCreateContentWidget();
        if (contentWidget.showsOrWillShow(mouseEvent)) {
            this._glyphWidget?.hide();
            return;
        }
        if (target.type === 2  && target.position && target.detail.glyphMarginLane) {
            this._contentWidget?.hide();
            const glyphWidget = this._getOrCreateGlyphWidget();
            glyphWidget.startShowingAt(target.position.lineNumber, target.detail.glyphMarginLane);
            return;
        }
        if (target.type === 3  && target.position) {
            this._contentWidget?.hide();
            const glyphWidget = this._getOrCreateGlyphWidget();
            glyphWidget.startShowingAt(target.position.lineNumber, 'lineNo');
            return;
        }
        this._hideWidgets();
    }
    _onKeyDown(e) {
        if (!this._editor.hasModel()) {
            return;
        }
        const resolvedKeyboardEvent = this._keybindingService.softDispatch(e, this._editor.getDomNode());
        const mightTriggerFocus = (resolvedKeyboardEvent.kind === 1  ||
            (resolvedKeyboardEvent.kind === 2
                && resolvedKeyboardEvent.commandId === 'editor.action.showHover'
                && this._contentWidget?.isVisible));
        if (e.keyCode === 5
            || e.keyCode === 6
            || e.keyCode === 57
            || e.keyCode === 4
            || mightTriggerFocus) {
            return;
        }
        this._hideWidgets();
    }
    _hideWidgets() {
        if ((this._hoverState.mouseDown
            && this._hoverState.contentHoverFocused
            && this._contentWidget?.isColorPickerVisible)
            || InlineSuggestionHintsContentWidget.dropDownVisible) {
            return;
        }
        this._hoverState.activatedByDecoratorClick = false;
        this._hoverState.contentHoverFocused = false;
        this._glyphWidget?.hide();
        this._contentWidget?.hide();
    }
    _getOrCreateContentWidget() {
        if (!this._contentWidget) {
            this._contentWidget = this._instantiationService.createInstance(ContentHoverController, this._editor);
        }
        return this._contentWidget;
    }
    _getOrCreateGlyphWidget() {
        if (!this._glyphWidget) {
            this._glyphWidget = ( (new MarginHoverWidget(this._editor, this._languageService, this._openerService)));
        }
        return this._glyphWidget;
    }
    hideContentHover() {
        this._hideWidgets();
    }
    showContentHover(range, mode, source, focus, activatedByColorDecoratorClick = false) {
        this._hoverState.activatedByDecoratorClick = activatedByColorDecoratorClick;
        this._getOrCreateContentWidget().startShowingAtRange(range, mode, source, focus);
    }
    focus() {
        this._contentWidget?.focus();
    }
    scrollUp() {
        this._contentWidget?.scrollUp();
    }
    scrollDown() {
        this._contentWidget?.scrollDown();
    }
    scrollLeft() {
        this._contentWidget?.scrollLeft();
    }
    scrollRight() {
        this._contentWidget?.scrollRight();
    }
    pageUp() {
        this._contentWidget?.pageUp();
    }
    pageDown() {
        this._contentWidget?.pageDown();
    }
    goToTop() {
        this._contentWidget?.goToTop();
    }
    goToBottom() {
        this._contentWidget?.goToBottom();
    }
    getWidgetContent() {
        return this._contentWidget?.getWidgetContent();
    }
    get isColorPickerVisible() {
        return this._contentWidget?.isColorPickerVisible;
    }
    get isHoverVisible() {
        return this._contentWidget?.isVisible;
    }
    dispose() {
        super.dispose();
        this._unhookListeners();
        this._listenersStore.dispose();
        this._glyphWidget?.dispose();
        this._contentWidget?.dispose();
    }
};
HoverController = HoverController_1 = ( (__decorate([
    ( (__param(1, IInstantiationService))),
    ( (__param(2, IOpenerService))),
    ( (__param(3, ILanguageService))),
    ( (__param(4, IKeybindingService)))
], HoverController)));
var HoverFocusBehavior;
( ((function(HoverFocusBehavior) {
    HoverFocusBehavior["NoAutoFocus"] = "noAutoFocus";
    HoverFocusBehavior["FocusIfVisible"] = "focusIfVisible";
    HoverFocusBehavior["AutoFocusImmediately"] = "autoFocusImmediately";
})(HoverFocusBehavior || (HoverFocusBehavior = {}))));
class ShowOrFocusHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.showHover',
            label: ( localizeWithPath(_moduleId, 0, "Show or Focus Hover")),
            metadata: {
                description: `Show or Focus Hover`,
                args: [{
                        name: 'args',
                        schema: {
                            type: 'object',
                            properties: {
                                'focus': {
                                    description: 'Controls if and when the hover should take focus upon being triggered by this action.',
                                    enum: [HoverFocusBehavior.NoAutoFocus, HoverFocusBehavior.FocusIfVisible, HoverFocusBehavior.AutoFocusImmediately],
                                    enumDescriptions: [
                                        ( localizeWithPath(_moduleId, 1, 'The hover will not automatically take focus.')),
                                        ( localizeWithPath(_moduleId, 2, 'The hover will take focus only if it is already visible.')),
                                        ( localizeWithPath(_moduleId, 3, 'The hover will automatically take focus when it appears.')),
                                    ],
                                    default: HoverFocusBehavior.FocusIfVisible,
                                }
                            },
                        }
                    }]
            },
            alias: 'Show or Focus Hover',
            precondition: undefined,
            kbOpts: {
                kbExpr: EditorContextKeys.editorTextFocus,
                primary: KeyChord(2048  | 41 , 2048  | 39 ),
                weight: 100
            }
        });
    }
    run(accessor, editor, args) {
        if (!editor.hasModel()) {
            return;
        }
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        const focusArgument = args?.focus;
        let focusOption = HoverFocusBehavior.FocusIfVisible;
        if (( (Object.values(HoverFocusBehavior))).includes(focusArgument)) {
            focusOption = focusArgument;
        }
        else if (typeof focusArgument === 'boolean' && focusArgument) {
            focusOption = HoverFocusBehavior.AutoFocusImmediately;
        }
        const showContentHover = (focus) => {
            const position = editor.getPosition();
            const range = ( (new Range(position.lineNumber, position.column, position.lineNumber, position.column)));
            controller.showContentHover(range, 1 , 1 , focus);
        };
        const accessibilitySupportEnabled = editor.getOption(2 ) === 2 ;
        if (controller.isHoverVisible) {
            if (focusOption !== HoverFocusBehavior.NoAutoFocus) {
                controller.focus();
            }
            else {
                showContentHover(accessibilitySupportEnabled);
            }
        }
        else {
            showContentHover(accessibilitySupportEnabled || focusOption === HoverFocusBehavior.AutoFocusImmediately);
        }
    }
}
class ShowDefinitionPreviewHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.showDefinitionPreviewHover',
            label: ( localizeWithPath(_moduleId, 4, "Show Definition Preview Hover")),
            alias: 'Show Definition Preview Hover',
            precondition: undefined
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        const position = editor.getPosition();
        if (!position) {
            return;
        }
        const range = ( (new Range(position.lineNumber, position.column, position.lineNumber, position.column)));
        const goto = GotoDefinitionAtPositionEditorContribution.get(editor);
        if (!goto) {
            return;
        }
        const promise = goto.startFindDefinitionFromCursor(position);
        promise.then(() => {
            controller.showContentHover(range, 1 , 1 , true);
        });
    }
}
class ScrollUpHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.scrollUpHover',
            label: ( localizeWithPath(_moduleId, 5, "Scroll Up Hover")),
            alias: 'Scroll Up Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 16 ,
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.scrollUp();
    }
}
class ScrollDownHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.scrollDownHover',
            label: ( localizeWithPath(_moduleId, 6, "Scroll Down Hover")),
            alias: 'Scroll Down Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 18 ,
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.scrollDown();
    }
}
class ScrollLeftHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.scrollLeftHover',
            label: ( localizeWithPath(_moduleId, 7, "Scroll Left Hover")),
            alias: 'Scroll Left Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 15 ,
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.scrollLeft();
    }
}
class ScrollRightHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.scrollRightHover',
            label: ( localizeWithPath(_moduleId, 8, "Scroll Right Hover")),
            alias: 'Scroll Right Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 17 ,
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.scrollRight();
    }
}
class PageUpHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.pageUpHover',
            label: ( localizeWithPath(_moduleId, 9, "Page Up Hover")),
            alias: 'Page Up Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 11 ,
                secondary: [512  | 16 ],
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.pageUp();
    }
}
class PageDownHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.pageDownHover',
            label: ( localizeWithPath(_moduleId, 10, "Page Down Hover")),
            alias: 'Page Down Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 12 ,
                secondary: [512  | 18 ],
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.pageDown();
    }
}
class GoToTopHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.goToTopHover',
            label: ( localizeWithPath(_moduleId, 11, "Go To Top Hover")),
            alias: 'Go To Bottom Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 14 ,
                secondary: [2048  | 16 ],
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.goToTop();
    }
}
class GoToBottomHoverAction extends EditorAction {
    constructor() {
        super({
            id: 'editor.action.goToBottomHover',
            label: ( localizeWithPath(_moduleId, 12, "Go To Bottom Hover")),
            alias: 'Go To Bottom Hover',
            precondition: EditorContextKeys.hoverFocused,
            kbOpts: {
                kbExpr: EditorContextKeys.hoverFocused,
                primary: 13 ,
                secondary: [2048  | 18 ],
                weight: 100
            }
        });
    }
    run(accessor, editor) {
        const controller = HoverController.get(editor);
        if (!controller) {
            return;
        }
        controller.goToBottom();
    }
}
registerEditorContribution(HoverController.ID, HoverController, 2 );
registerEditorAction(ShowOrFocusHoverAction);
registerEditorAction(ShowDefinitionPreviewHoverAction);
registerEditorAction(ScrollUpHoverAction);
registerEditorAction(ScrollDownHoverAction);
registerEditorAction(ScrollLeftHoverAction);
registerEditorAction(ScrollRightHoverAction);
registerEditorAction(PageUpHoverAction);
registerEditorAction(PageDownHoverAction);
registerEditorAction(GoToTopHoverAction);
registerEditorAction(GoToBottomHoverAction);
HoverParticipantRegistry.register(MarkdownHoverParticipant);
HoverParticipantRegistry.register(MarkerHoverParticipant);
registerThemingParticipant((theme, collector) => {
    const hoverBorder = theme.getColor(editorHoverBorder);
    if (hoverBorder) {
        collector.addRule(`.monaco-editor .monaco-hover .hover-row:not(:first-child):not(:empty) { border-top: 1px solid ${( (hoverBorder.transparent(0.5)))}; }`);
        collector.addRule(`.monaco-editor .monaco-hover hr { border-top: 1px solid ${( (hoverBorder.transparent(0.5)))}; }`);
        collector.addRule(`.monaco-editor .monaco-hover hr { border-bottom: 0px solid ${( (hoverBorder.transparent(0.5)))}; }`);
    }
});
export { HoverController };
