import { acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completionKeymap, nextSnippetField, prevSnippetField, snippetKeymap, } from '@codemirror/autocomplete';
import { defaultKeymap, history, historyKeymap, indentLess, indentMore, } from '@codemirror/commands';
import { bracketMatching, defaultHighlightStyle, foldKeymap, indentOnInput, syntaxHighlighting, } from '@codemirror/language';
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
import { EditorState } from '@codemirror/state';
import { crosshairCursor, drawSelection, dropCursor, EditorView, highlightSpecialChars, keymap, rectangularSelection, } from '@codemirror/view';
import { lintKeymap } from '@codemirror/lint';
import { getIconForType } from './icons';
const insertTab = (cmd) => {
    // if there is a selection we should indent the selected text, but if not insert
    // two spaces as per the cypher style guide
    if (cmd.state.selection.main.from === cmd.state.selection.main.to) {
        cmd.dispatch(cmd.state.update({
            changes: {
                from: cmd.state.selection.main.to,
                to: cmd.state.selection.main.to,
                insert: '  ',
            },
            selection: { anchor: cmd.state.selection.main.to + 2 },
        }));
    }
    else {
        indentMore(cmd);
    }
    return true;
};
export const basicNeo4jSetup = ({ moveFocusOnTab = false, }) => {
    const keymaps = [
        closeBracketsKeymap,
        defaultKeymap,
        searchKeymap,
        historyKeymap,
        foldKeymap,
        completionKeymap,
        lintKeymap,
    ].flat();
    if (!moveFocusOnTab) {
        keymaps.push({
            key: 'Tab',
            preventDefault: true,
            run: acceptCompletion,
        }, {
            key: 'Tab',
            preventDefault: true,
            run: insertTab,
        }, {
            key: 'Shift-Tab',
            preventDefault: true,
            run: indentLess,
        });
    }
    const extensions = [];
    extensions.push(highlightSpecialChars());
    extensions.push(history());
    extensions.push(drawSelection());
    extensions.push(dropCursor());
    extensions.push(EditorState.allowMultipleSelections.of(true));
    extensions.push(indentOnInput());
    extensions.push(syntaxHighlighting(defaultHighlightStyle, { fallback: true }));
    extensions.push(bracketMatching());
    extensions.push(closeBrackets());
    extensions.push(autocompletion({
        icons: false,
        interactionDelay: 5,
        addToOptions: [
            {
                render(completion, state) {
                    const isDarkTheme = state.facet(EditorView.darkTheme);
                    const icon = document.createElement('span');
                    icon.innerHTML = getIconForType(completion.type, isDarkTheme);
                    const svgElement = icon.children[0];
                    svgElement.style.display = 'inline';
                    svgElement.style.marginRight = '5px';
                    return icon;
                },
                position: 20,
            },
        ],
    }));
    extensions.push(rectangularSelection());
    extensions.push(crosshairCursor());
    extensions.push(highlightSelectionMatches());
    extensions.push(keymap.of(keymaps));
    extensions.push(snippetKeymap.of([
        {
            key: 'Tab',
            run: acceptCompletionOrGotoNextSnippet,
            shift: acceptCompletionOrGotoPrevSnippet,
        },
        { key: 'Escape', run: closeCompletionsOrClearSnippets },
    ]));
    return extensions;
};
// The logic to check if there's a completion open is surprisingly complex
// https://github.com/codemirror/autocomplete/blob/5ad2ebc861f2f61cdc943fc087a5bfb756a7d0fa/src/view.ts#L31
// For example it respects an interaction delay, so we can't just check if the completion is open
// instead we just run the acceptCompletion command which returns true if a completion was accepted
// in that case we know that we shouldn't move to the next snippet field
const acceptCompletionOrGotoNextSnippet = (view) => {
    const didCompletion = acceptCompletion(view);
    if (didCompletion) {
        return true;
    }
    return nextSnippetField(view);
};
const acceptCompletionOrGotoPrevSnippet = (view) => {
    const didCompletion = acceptCompletion(view);
    if (didCompletion) {
        return true;
    }
    return prevSnippetField(view);
};
const closeCompletionsOrClearSnippets = (view) => {
    const closedCompletions = closeCompletion(view);
    if (closedCompletions) {
        return true;
    }
    return clearSnippet(view);
};
//# sourceMappingURL=neo4jSetup.js.map