"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCodemirror = createCodemirror;
exports.withLogger = withLogger;
const autocomplete_1 = require("@codemirror/autocomplete");
const commands_1 = require("@codemirror/commands");
const language_1 = require("@codemirror/language");
const view_1 = require("@codemirror/view");
const action_names_1 = require("../../bundle/config/action-names.js");
const logger_1 = require("../../logger.js");
const shortcuts_1 = require("../../shortcuts/index.js");
const clipboard_1 = require("../../utils/clipboard.js");
const commands_2 = require("../commands/index.js");
const directive_facet_1 = require("./directive-facet.js");
const files_upload_facet_1 = require("./files-upload-facet.js");
const gravity_1 = require("./gravity.js");
const converters_1 = require("./html-to-markdown/converters.js");
const logger_facet_1 = require("./logger-facet.js");
const pairing_chars_1 = require("./pairing-chars.js");
const react_facet_1 = require("./react-facet.js");
const plugin_1 = require("./search-plugin/plugin.js");
const smart_reindent_1 = require("./smart-reindent/index.js");
const yfm_1 = require("./yfm.js");
function createCodemirror(params) {
    const { logger, doc, reactRenderer, onCancel, onScroll, onSubmit, onChange, onDocChange, disabledExtensions = {}, keymaps = [], receiver, yfmLangOptions, extensions: extraExtensions, placeholder: placeholderContent, autocompletion: autocompletionConfig, parseHtmlOnPaste, parseInsertedUrlAsImage, directiveSyntax, preserveEmptyRows, } = params;
    const extensions = [gravity_1.gravityTheme, (0, view_1.placeholder)(placeholderContent)];
    if (!disabledExtensions.history) {
        extensions.push((0, commands_1.history)());
    }
    extensions.push((0, language_1.syntaxHighlighting)(gravity_1.gravityHighlightStyle), logger_facet_1.LoggerFacet.of(logger), view_1.keymap.of([
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Bold), run: withLogger(action_names_1.ActionName.bold, commands_2.toggleBold) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Italic), run: withLogger(action_names_1.ActionName.italic, commands_2.toggleItalic) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Strike), run: withLogger(action_names_1.ActionName.strike, commands_2.toggleStrikethrough) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Underline), run: withLogger(action_names_1.ActionName.underline, commands_2.toggleUnderline) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Link), run: withLogger(action_names_1.ActionName.link, commands_2.insertLink) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading1), run: withLogger(action_names_1.ActionName.heading1, commands_2.toH1) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading2), run: withLogger(action_names_1.ActionName.heading2, commands_2.toH2) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading3), run: withLogger(action_names_1.ActionName.heading3, commands_2.toH3) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading4), run: withLogger(action_names_1.ActionName.heading4, commands_2.toH4) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading5), run: withLogger(action_names_1.ActionName.heading5, commands_2.toH5) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Heading6), run: withLogger(action_names_1.ActionName.heading6, commands_2.toH6) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Code), run: withLogger(action_names_1.ActionName.code_inline, commands_2.wrapToInlineCode) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.CodeBlock), run: withLogger(action_names_1.ActionName.code_block, commands_2.wrapToCodeBlock) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Cut), run: withLogger(action_names_1.ActionName.yfm_cut, commands_2.wrapToYfmCut) },
        { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Note), run: withLogger(action_names_1.ActionName.yfm_note, commands_2.wrapToYfmNote) },
        {
            key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Cancel),
            preventDefault: true,
            run: () => {
                onCancel();
                return true;
            },
        },
        {
            key: shortcuts_1.formatter.toCM(shortcuts_1.Action.Submit),
            preventDefault: true,
            run: () => {
                onSubmit();
                return true;
            },
        },
        { key: 'Tab', preventDefault: true, run: commands_1.insertTab },
        {
            key: 'Enter',
            shift: commands_1.insertNewlineKeepIndent,
        },
        commands_1.indentWithTab,
        ...commands_1.defaultKeymap,
        ...(disabledExtensions.history ? [] : commands_1.historyKeymap),
        ...keymaps,
    ]), (0, autocomplete_1.autocompletion)(autocompletionConfig), (0, yfm_1.yfmLang)(yfmLangOptions), react_facet_1.ReactRendererFacet.of(reactRenderer), directive_facet_1.DirectiveSyntaxFacet.of(directiveSyntax), pairing_chars_1.PairingCharactersExtension, view_1.EditorView.lineWrapping, view_1.EditorView.contentAttributes.of({ spellcheck: 'true' }), view_1.EditorView.domEventHandlers({
        scroll(event) {
            onScroll(event);
        },
        paste(event, editor) {
            if (!event.clipboardData)
                return;
            const pasteLogger = logger.nested({
                domEvent: 'paste',
                dataTypes: event.clipboardData.types,
            });
            const { from } = editor.state.selection.main;
            const line = editor.state.doc.lineAt(from);
            const currentLine = line.text;
            // if clipboard contains YFM content - avoid any meddling with pasted content
            // since text/yfm will contain valid markdown
            const yfmContent = event.clipboardData.getData(clipboard_1.DataTransferType.Yfm);
            if (yfmContent) {
                event.preventDefault();
                logger.event({ event: 'paste-markup' });
                const reindentedYfmContent = (0, smart_reindent_1.smartReindent)(yfmContent, currentLine);
                editor.dispatch(editor.state.replaceSelection(reindentedYfmContent));
                return;
            }
            // checking if a copy buffer content is suitable for convertion
            const shouldSkipHtml = (0, clipboard_1.shouldSkipHtmlConversion)(event.clipboardData);
            // if we have text/html inside copy/paste buffer
            const htmlContent = event.clipboardData.getData(clipboard_1.DataTransferType.Html);
            // if we pasting markdown from VsCode we need skip html transformation
            if (htmlContent && parseHtmlOnPaste && !shouldSkipHtml) {
                let parsedMarkdownMarkup;
                try {
                    const parser = new DOMParser();
                    const htmlDoc = parser.parseFromString(htmlContent, 'text/html');
                    const converter = new converters_1.MarkdownConverter();
                    parsedMarkdownMarkup = converter.processNode(htmlDoc.body).trim();
                }
                catch (e) {
                    // The code is pretty new and there might be random issues we haven't caught yet,
                    // especially with invalid HTML or weird DOM parsing errors.
                    // If something goes wrong, I just want to fall back to the "default pasting"
                    // rather than break the entire experience for the user.
                    pasteLogger.error(e, { event: 'parse-html-to-md' });
                    logger_1.globalLogger.error(e);
                }
                if (parsedMarkdownMarkup !== undefined) {
                    event.preventDefault();
                    logger.event({ event: 'paste-parsed-html' });
                    const reindentedHtmlContent = (0, smart_reindent_1.smartReindent)(parsedMarkdownMarkup, currentLine);
                    editor.dispatch(editor.state.replaceSelection(reindentedHtmlContent));
                    return;
                }
            }
            if (parseInsertedUrlAsImage) {
                const { imageUrl, title } = parseInsertedUrlAsImage(event.clipboardData.getData(clipboard_1.DataTransferType.Text) ?? '') || {};
                if (imageUrl) {
                    event.preventDefault();
                    logger.event({ event: 'paste-url-as-image' });
                    (0, commands_2.insertImages)([
                        {
                            url: imageUrl,
                            alt: title,
                            title,
                        },
                    ])(editor);
                }
            }
            // Reindenting pasted plain text
            const pastedText = event.clipboardData.getData(clipboard_1.DataTransferType.Text);
            const reindentedText = (0, smart_reindent_1.smartReindent)(pastedText, currentLine);
            // but only if there is a need for reindentation
            if (pastedText !== reindentedText) {
                editor.dispatch(editor.state.replaceSelection(reindentedText));
                event.preventDefault();
            }
        },
    }), (0, plugin_1.SearchPanelPlugin)({
        anchorSelector: '.g-md-search-anchor',
        receiver,
    }));
    if (preserveEmptyRows) {
        extensions.push(view_1.keymap.of([
            { key: shortcuts_1.formatter.toCM(shortcuts_1.Action.EmptyRow), run: withLogger(action_names_1.ActionName.emptyRow, commands_2.insertEmptyRow) },
        ]));
    }
    if (params.uploadHandler) {
        extensions.push(files_upload_facet_1.FileUploadHandlerFacet.of({
            fn: params.uploadHandler,
            imageWithDimensions: params.needImageDimensions,
            enableNewImageSizeCalculation: params.enableNewImageSizeCalculation,
        }));
    }
    if (extraExtensions) {
        extensions.push(...extraExtensions);
    }
    return new view_1.EditorView({
        doc,
        extensions,
        dispatchTransactions: (trs, view) => {
            view.update(trs);
            onChange();
            if (trs.some((tr) => tr.docChanged)) {
                onDocChange();
            }
        },
    });
}
function withLogger(action, command) {
    return (...args) => {
        const { state } = args[0];
        state.facet(logger_facet_1.LoggerFacet).action({ source: 'keymap', action });
        logger_1.globalLogger.action({ mode: 'markup', source: 'keymap', action });
        return command(...args);
    };
}
//# sourceMappingURL=create.js.map
