import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { useEffect, useState, useRef, useCallback, forwardRef } from 'react';
import { observer } from 'mobx-react-lite';
import { editor as monacoEditorAPI, languages as monacoLanguagesAPI, KeyCode, KeyMod, } from 'monaco-editor';
import { ContextMenu, PanelContent, MenuContent, MenuContentItem, PanelLoadingIndicator, CaretDownIcon, ControlledDropdownMenu, MenuContentItemIcon, CheckIcon, MenuContentItemLabel, Dialog, ModalFooter, Modal, ModalHeader, ModalBody, ModalTitle, ModalFooterButton, } from '@finos/legend-art';
import { DEFAULT_TAB_SIZE, useApplicationStore, useApplicationNavigationContext, } from '@finos/legend-application';
import { getBaseCodeEditorOptions, resetLineNumberGutterWidth, getCodeEditorValue, normalizeLineEnding, setWarningMarkers, clearMarkers, setErrorMarkers, moveCursorToPosition, getCodeEditorThemeForAppTheme, CODE_EDITOR_LANGUAGE, getInlineSnippetSuggestions, getParserKeywordSuggestions, getParserElementSnippetSuggestions, getSectionParserNameFromLineText, } from '@finos/legend-code-editor';
import { disposeCodeEditor } from '@finos/legend-lego/code-editor';
import { CORE_DND_TYPE, } from '../../../stores/editor/utils/DnDUtils.js';
import { useDrop } from 'react-dnd';
import { flowResult } from 'mobx';
import { useEditorStore } from '../EditorStoreProvider.js';
import { LogEvent, assertErrorThrown, assertTrue, hasWhiteSpace, isNonNullable, } from '@finos/legend-shared';
import { ELEMENT_PATH_DELIMITER, PARSER_SECTION_MARKER, PURE_CONNECTION_NAME, PURE_ELEMENT_NAME, PURE_PARSER, isValidFullPath, } from '@finos/legend-graph';
import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../__lib__/LegendStudioDocumentation.js';
import { BLANK_CLASS_SNIPPET, CLASS_WITH_CONSTRAINT_SNIPPET, CLASS_WITH_INHERITANCE_SNIPPET, CLASS_WITH_PROPERTY_SNIPPET, DATA_WITH_EXTERNAL_FORMAT_SNIPPET, DATA_WITH_MODEL_STORE_SNIPPET, createDataElementSnippetWithEmbeddedDataSuggestionSnippet, SIMPLE_PROFILE_SNIPPET, SIMPLE_ENUMERATION_SNIPPET, SIMPLE_ASSOCIATION_SNIPPET, SIMPLE_MEASURE_SNIPPET, BLANK_FUNCTION_SNIPPET, SIMPLE_FUNCTION_SNIPPET, SIMPLE_RUNTIME_SNIPPET, JSON_MODEL_CONNECTION_SNIPPET, XML_MODEL_CONNECTION_SNIPPET, MODEL_CHAIN_CONNECTION_SNIPPET, RELATIONAL_DATABASE_CONNECTION_SNIPPET, BLANK_RELATIONAL_DATABASE_SNIPPET, SIMPLE_GENERATION_SPECIFICATION_SNIPPET, BLANK_SERVICE_SNIPPET, SERVICE_WITH_SINGLE_EXECUTION_SNIPPET, SERVICE_WITH_MULTI_EXECUTION_SNIPPET, BLANK_MAPPING_SNIPPET, MAPPING_WITH_M2M_CLASS_MAPPING_SNIPPET, MAPPING_WITH_ENUMERATION_MAPPING_SNIPPET, MAPPING_WITH_RELATIONAL_CLASS_MAPPING_SNIPPET, POST_PROCESSOR_RELATIONAL_DATABASE_CONNECTION_SNIPPET, createConnectionSnippetWithPostProcessorSuggestionSnippet, } from '../../../__lib__/LegendStudioCodeSnippet.js';
import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../__lib__/LegendStudioApplicationNavigationContext.js';
import { LEGEND_STUDIO_SETTING_KEY } from '../../../__lib__/LegendStudioSetting.js';
import { GRAMMAR_MODE_EDITOR_ACTION, GraphEditGrammarModeState, } from '../../../stores/editor/GraphEditGrammarModeState.js';
import { LEGEND_STUDIO_APP_EVENT } from '../../../__lib__/LegendStudioEvent.js';
import { FileSystem_FileViewer } from './ArtifactGenerationViewer.js';
export const GrammarTextEditorHeaderTabContextMenu = observer(forwardRef(function GrammarTextEditorHeaderTabContextMenu(props, ref) {
    const editorStore = useEditorStore();
    const applicationStore = useApplicationStore();
    const leaveTextMode = applicationStore.guardUnhandledError(() => flowResult(editorStore.toggleTextMode()));
    return (_jsx(MenuContent, { ref: ref, children: _jsx(MenuContentItem, { onClick: leaveTextMode, children: "Leave Text Mode" }) }));
}));
const getParserDocumetation = (editorStore, parserKeyword) => {
    switch (parserKeyword) {
        case PURE_PARSER.PURE: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_PURE);
        }
        case PURE_PARSER.MAPPING: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_MAPPING);
        }
        case PURE_PARSER.CONNECTION: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_CONNECTION);
        }
        case PURE_PARSER.RUNTIME: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_RUNTIME);
        }
        case PURE_PARSER.SERVICE: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_SERVICE);
        }
        case PURE_PARSER.RELATIONAL: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_RELATIONAL);
        }
        case PURE_PARSER.FILE_GENERATION_SPECIFICATION: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_FILE_GENERATION);
        }
        case PURE_PARSER.GENERATION_SPECIFICATION: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_GENERATION_SPECIFICATION);
        }
        case PURE_PARSER.DATA: {
            return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_DATA);
        }
        default: {
            const parserDocumentationGetters = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraPureGrammarParserDocumentationGetters?.() ?? []);
            for (const docGetter of parserDocumentationGetters) {
                const doc = docGetter(editorStore, parserKeyword);
                if (doc) {
                    return doc;
                }
            }
        }
    }
    return undefined;
};
const getParserElementDocumentation = (editorStore, parserKeyword, elementKeyword) => {
    switch (parserKeyword) {
        case PURE_PARSER.PURE: {
            if (elementKeyword === PURE_ELEMENT_NAME.CLASS) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_CLASS);
            }
            else if (elementKeyword === PURE_ELEMENT_NAME.PROFILE) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_PROFILE);
            }
            else if (elementKeyword === PURE_ELEMENT_NAME.ENUMERATION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_ENUMERATION);
            }
            else if (elementKeyword === PURE_ELEMENT_NAME.MEASURE) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_MEASURE);
            }
            else if (elementKeyword === PURE_ELEMENT_NAME.ASSOCIATION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_ASSOCIATION);
            }
            else if (elementKeyword === PURE_ELEMENT_NAME.FUNCTION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_FUNCTION);
            }
            return undefined;
        }
        case PURE_PARSER.MAPPING: {
            if (elementKeyword === PURE_ELEMENT_NAME.MAPPING) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_MAPPING);
            }
            return undefined;
        }
        case PURE_PARSER.CONNECTION: {
            if (elementKeyword === PURE_CONNECTION_NAME.JSON_MODEL_CONNECTION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_CONNECTION_JSON_MODEL_CONNECTION);
            }
            else if (elementKeyword === PURE_CONNECTION_NAME.XML_MODEL_CONNECTION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_CONNECTION_XML_MODEL_CONNECTION);
            }
            else if (elementKeyword === PURE_CONNECTION_NAME.MODEL_CHAIN_CONNECTION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_CONNECTION_MODEL_CHAIN_CONNECTION);
            }
            else if (elementKeyword === PURE_CONNECTION_NAME.RELATIONAL_DATABASE_CONNECTION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_CONNECTION_RELATIONAL_DATABASE_CONNECTION);
            }
            // TODO: introduce extension mechanism
            return undefined;
        }
        case PURE_PARSER.RUNTIME: {
            if (elementKeyword === PURE_ELEMENT_NAME.RUNTIME) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_RUNTIME);
            }
            return undefined;
        }
        case PURE_PARSER.SERVICE: {
            if (elementKeyword === PURE_ELEMENT_NAME.SERVICE) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_SERVICE);
            }
            return undefined;
        }
        case PURE_PARSER.RELATIONAL: {
            if (elementKeyword === PURE_ELEMENT_NAME.DATABASE) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_DATABASE);
            }
            return undefined;
        }
        case PURE_PARSER.FILE_GENERATION_SPECIFICATION: {
            if (elementKeyword === PURE_ELEMENT_NAME.FILE_GENERATION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_FILE_GENERATION_SPECIFICATION);
            }
            return undefined;
        }
        case PURE_PARSER.GENERATION_SPECIFICATION: {
            if (elementKeyword === PURE_ELEMENT_NAME.GENERATION_SPECIFICATION) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.CONCEPT_ELEMENT_GENERATION_SPECIFICATION);
            }
            return undefined;
        }
        case PURE_PARSER.DATA: {
            if (elementKeyword === PURE_ELEMENT_NAME.DATA_ELEMENT) {
                return editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_DATA);
            }
            return undefined;
        }
        default: {
            const parserElementDocumentationGetters = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraPureGrammarParserElementDocumentationGetters?.() ?? []);
            for (const docGetter of parserElementDocumentationGetters) {
                const doc = docGetter(editorStore, parserKeyword, elementKeyword);
                if (doc) {
                    return doc;
                }
            }
        }
    }
    return undefined;
};
const collectParserKeywordSuggestions = (editorStore) => {
    const parserKeywordSuggestions = editorStore.pluginManager
        .getApplicationPlugins()
        .flatMap((plugin) => plugin.getExtraPureGrammarParserKeywordSuggestionGetters?.() ?? [])
        .flatMap((suggestionGetter) => suggestionGetter(editorStore));
    return [
        {
            text: PURE_PARSER.PURE,
            description: `(core Pure)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_PURE),
            insertText: PURE_PARSER.PURE,
        },
        {
            text: PURE_PARSER.MAPPING,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_MAPPING),
            insertText: PURE_PARSER.MAPPING,
        },
        {
            text: PURE_PARSER.CONNECTION,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_CONNECTION),
            insertText: PURE_PARSER.CONNECTION,
        },
        {
            text: PURE_PARSER.RUNTIME,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_RUNTIME),
            insertText: PURE_PARSER.RUNTIME,
        },
        {
            text: PURE_PARSER.RELATIONAL,
            description: `(external store)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_RELATIONAL),
            insertText: PURE_PARSER.RELATIONAL,
        },
        {
            text: PURE_PARSER.SERVICE,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_SERVICE),
            insertText: PURE_PARSER.SERVICE,
        },
        {
            text: PURE_PARSER.GENERATION_SPECIFICATION,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_GENERATION_SPECIFICATION),
            insertText: PURE_PARSER.GENERATION_SPECIFICATION,
        },
        {
            text: PURE_PARSER.FILE_GENERATION_SPECIFICATION,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_FILE_GENERATION),
            insertText: PURE_PARSER.FILE_GENERATION_SPECIFICATION,
        },
        {
            text: PURE_PARSER.DATA,
            description: `(dsl)`,
            documentation: editorStore.applicationStore.documentationService.getDocEntry(LEGEND_STUDIO_DOCUMENTATION_KEY.GRAMMAR_PARSER_DATA),
            insertText: PURE_PARSER.DATA,
        },
        ...parserKeywordSuggestions,
    ];
};
const collectParserElementSnippetSuggestions = (editorStore, parserKeyword) => {
    switch (parserKeyword) {
        case PURE_PARSER.PURE: {
            return [
                // class
                {
                    text: PURE_ELEMENT_NAME.CLASS,
                    description: '(blank)',
                    insertText: BLANK_CLASS_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.CLASS,
                    description: 'with property',
                    insertText: CLASS_WITH_PROPERTY_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.CLASS,
                    description: 'with inheritance',
                    insertText: CLASS_WITH_INHERITANCE_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.CLASS,
                    description: 'with constraint',
                    insertText: CLASS_WITH_CONSTRAINT_SNIPPET,
                },
                // profile
                {
                    text: PURE_ELEMENT_NAME.PROFILE,
                    insertText: SIMPLE_PROFILE_SNIPPET,
                },
                // enumeration
                {
                    text: PURE_ELEMENT_NAME.ENUMERATION,
                    insertText: SIMPLE_ENUMERATION_SNIPPET,
                },
                // association
                {
                    text: PURE_ELEMENT_NAME.ASSOCIATION,
                    insertText: SIMPLE_ASSOCIATION_SNIPPET,
                },
                // measure
                {
                    text: PURE_ELEMENT_NAME.MEASURE,
                    insertText: SIMPLE_MEASURE_SNIPPET,
                },
                // function
                {
                    text: PURE_ELEMENT_NAME.FUNCTION,
                    description: '(blank)',
                    insertText: BLANK_FUNCTION_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.FUNCTION,
                    insertText: SIMPLE_FUNCTION_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.MAPPING: {
            return [
                {
                    text: PURE_ELEMENT_NAME.MAPPING,
                    description: '(blank)',
                    insertText: BLANK_MAPPING_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.MAPPING,
                    description: 'with model-to-model mapping',
                    insertText: MAPPING_WITH_M2M_CLASS_MAPPING_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.MAPPING,
                    description: 'with relational mapping',
                    insertText: MAPPING_WITH_RELATIONAL_CLASS_MAPPING_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.MAPPING,
                    description: 'with enumeration mapping',
                    insertText: MAPPING_WITH_ENUMERATION_MAPPING_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.CONNECTION: {
            const embeddedPostProcessorSnippetSuggestions = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraPostProcessorSnippetSuggestions?.() ?? []);
            const connectionSnippetSuggestions = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraNewConnectionSnippetSuggestions?.() ?? []);
            return [
                {
                    text: PURE_CONNECTION_NAME.JSON_MODEL_CONNECTION,
                    description: 'JSON model connection',
                    insertText: JSON_MODEL_CONNECTION_SNIPPET,
                },
                {
                    text: PURE_CONNECTION_NAME.XML_MODEL_CONNECTION,
                    description: 'XML model connection',
                    insertText: XML_MODEL_CONNECTION_SNIPPET,
                },
                {
                    text: PURE_CONNECTION_NAME.MODEL_CHAIN_CONNECTION,
                    description: 'model chain connection',
                    insertText: MODEL_CHAIN_CONNECTION_SNIPPET,
                },
                {
                    text: PURE_CONNECTION_NAME.RELATIONAL_DATABASE_CONNECTION,
                    description: 'relational database connection',
                    insertText: RELATIONAL_DATABASE_CONNECTION_SNIPPET,
                },
                {
                    text: PURE_CONNECTION_NAME.RELATIONAL_DATABASE_CONNECTION,
                    description: 'relational database connection with post-processor',
                    insertText: POST_PROCESSOR_RELATIONAL_DATABASE_CONNECTION_SNIPPET,
                },
                ...connectionSnippetSuggestions.map((suggestion) => ({
                    text: suggestion.text,
                    description: suggestion.description,
                    insertText: suggestion.insertText,
                })),
                ...embeddedPostProcessorSnippetSuggestions.map((suggestion) => ({
                    text: PURE_CONNECTION_NAME.RELATIONAL_DATABASE_CONNECTION,
                    description: suggestion.description,
                    insertText: createConnectionSnippetWithPostProcessorSuggestionSnippet(suggestion.text),
                })),
            ];
        }
        case PURE_PARSER.RUNTIME: {
            return [
                {
                    text: PURE_ELEMENT_NAME.RUNTIME,
                    insertText: SIMPLE_RUNTIME_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.SERVICE: {
            return [
                {
                    text: PURE_ELEMENT_NAME.SERVICE,
                    description: '(blank)',
                    insertText: BLANK_SERVICE_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.SERVICE,
                    description: 'with single execution',
                    insertText: SERVICE_WITH_SINGLE_EXECUTION_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.SERVICE,
                    description: 'with multi execution',
                    insertText: SERVICE_WITH_MULTI_EXECUTION_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.RELATIONAL: {
            return [
                {
                    text: PURE_ELEMENT_NAME.DATABASE,
                    description: '(blank)',
                    insertText: BLANK_RELATIONAL_DATABASE_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.FILE_GENERATION_SPECIFICATION: {
            return [
            // TODO?: add extension mechanism for suggestion for different file generations
            ];
        }
        case PURE_PARSER.GENERATION_SPECIFICATION: {
            return [
                {
                    text: PURE_ELEMENT_NAME.GENERATION_SPECIFICATION,
                    description: '(blank)',
                    insertText: SIMPLE_GENERATION_SPECIFICATION_SNIPPET,
                },
            ];
        }
        case PURE_PARSER.DATA: {
            const embeddedDateSnippetSuggestions = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraEmbeddedDataSnippetSuggestions?.() ?? []);
            return [
                {
                    text: PURE_ELEMENT_NAME.DATA_ELEMENT,
                    description: 'with external format',
                    insertText: DATA_WITH_EXTERNAL_FORMAT_SNIPPET,
                },
                {
                    text: PURE_ELEMENT_NAME.DATA_ELEMENT,
                    description: 'using model store',
                    insertText: DATA_WITH_MODEL_STORE_SNIPPET,
                },
                ...embeddedDateSnippetSuggestions.map((suggestion) => ({
                    text: PURE_ELEMENT_NAME.DATA_ELEMENT,
                    description: suggestion.description,
                    insertText: createDataElementSnippetWithEmbeddedDataSuggestionSnippet(suggestion.text),
                })),
            ];
        }
        default: {
            const parserElementSnippetSuggestionsGetters = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraPureGrammarParserElementSnippetSuggestionsGetters?.() ??
                []);
            for (const snippetSuggestionsGetter of parserElementSnippetSuggestionsGetters) {
                const snippetSuggestions = snippetSuggestionsGetter(editorStore, parserKeyword);
                if (snippetSuggestions) {
                    return snippetSuggestions;
                }
            }
        }
    }
    return [];
};
const resolveElementPathFromCurrentPosition = (_editor, grammarModeState) => {
    let elementPath = '';
    try {
        const model = _editor.getModel();
        let position = _editor.getPosition();
        let maxWords = 0;
        if (model) {
            while (position && maxWords < 30) {
                const currentWord = model.getWordAtPosition(position);
                const lineNumber = position.lineNumber;
                position = null;
                maxWords += 1;
                if (currentWord) {
                    const wordStartPost = {
                        lineNumber: lineNumber,
                        column: currentWord.startColumn,
                    };
                    const startPost = model.modifyPosition(wordStartPost, -2);
                    elementPath = currentWord.word + elementPath;
                    const pathDelimiterRange = {
                        startLineNumber: startPost.lineNumber,
                        startColumn: startPost.column,
                        endLineNumber: wordStartPost.lineNumber,
                        endColumn: wordStartPost.column,
                    };
                    const packageRange = model.getValueInRange(model.validateRange(pathDelimiterRange));
                    if (packageRange === ELEMENT_PATH_DELIMITER) {
                        elementPath = packageRange + elementPath;
                        position = model.modifyPosition(startPost, -1);
                    }
                }
            }
        }
        assertTrue(isValidFullPath(elementPath), `Unable to go to element definition. Not valid element path: ${elementPath}`);
        return elementPath;
    }
    catch (error) {
        assertErrorThrown(error);
        grammarModeState.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.TEXT_MODE_ACTION_KEYBOARD_SHORTCUT_GO_TO_DEFINITION__ERROR), error);
    }
    return undefined;
};
const goToElement = (_editor, grammarModeState) => {
    grammarModeState.editorStore.applicationStore.logService.info(LogEvent.create(LEGEND_STUDIO_APP_EVENT.TEXT_MODE_ACTION_KEYBOARD_SHORTCUT_GO_TO_DEFINITION__LAUNCH));
    const elementPath = resolveElementPathFromCurrentPosition(_editor, grammarModeState);
    if (elementPath) {
        flowResult(grammarModeState.goToElement(elementPath)).catch(grammarModeState.editorStore.applicationStore.alertUnhandledError);
    }
};
const FileSystem_FileModal = observer((props) => {
    const { graphEditGrammarModeState, generatedFile } = props;
    const applicationStore = graphEditGrammarModeState.editorStore.applicationStore;
    const closeModal = () => graphEditGrammarModeState.setGeneratedFile(undefined);
    return (_jsx(Dialog, { open: true, classes: {
            root: 'editor-modal__root-container',
            container: 'editor-modal__container',
            paper: 'editor-modal__content',
        }, onClose: closeModal, children: _jsxs(Modal, { darkMode: !applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled, className: "editor-modal", children: [_jsx(ModalHeader, { children: _jsx(ModalTitle, { title: "Generated Artifact" }) }), _jsx(ModalBody, { children: _jsx(FileSystem_FileViewer, { generatedArtifact: generatedFile, visitGenerator: undefined, generator: undefined }) }), _jsx(ModalFooter, { children: _jsx(ModalFooterButton, { onClick: closeModal, text: "Close", type: "secondary" }) })] }) }));
});
export const GrammarTextEditor = observer(() => {
    const [editor, setEditor] = useState();
    const editorStore = useEditorStore();
    const applicationStore = useApplicationStore();
    const grammarModeState = editorStore.getGraphEditorMode(GraphEditGrammarModeState);
    const grammarTextEditorState = grammarModeState.grammarTextEditorState;
    const error = editorStore.graphState.error;
    const warnings = editorStore.graphState.warnings;
    const [elementsFolded, setFoldingElements] = useState(false);
    const forcedCursorPosition = grammarTextEditorState.forcedCursorPosition;
    const wordWrapOtion = grammarTextEditorState.wordWrapOtion;
    const value = normalizeLineEnding(grammarTextEditorState.graphGrammarText);
    const ref = useRef(null);
    const hoverProviderDisposer = useRef(undefined);
    const suggestionProviderDisposer = useRef(undefined);
    const leaveTextMode = applicationStore.guardUnhandledError(() => flowResult(editorStore.toggleTextMode()));
    const globalCompile = applicationStore.guardUnhandledError(() => flowResult(grammarModeState.globalCompile()));
    const toggleWordWrap = () => {
        grammarTextEditorState.setWrapText(!grammarTextEditorState.wrapText);
        editorStore.applicationStore.settingService.persistValue(LEGEND_STUDIO_SETTING_KEY.EDITOR_WRAP_TEXT, grammarTextEditorState.wrapText);
    };
    useEffect(() => {
        if (!editor && ref.current) {
            const element = ref.current;
            const _editor = monacoEditorAPI.create(element, {
                ...getBaseCodeEditorOptions(),
                language: CODE_EDITOR_LANGUAGE.PURE,
                // Pick the theme matching the current app theme so the editor doesn't
                // flash dark before the global theme sync (in configureCodeEditorComponent)
                // applies. Theme changes after mount are picked up via that global sync.
                theme: getCodeEditorThemeForAppTheme(editorStore.applicationStore.layoutService
                    .TEMPORARY__isLightColorThemeEnabled),
                renderValidationDecorations: 'on',
                wordWrap: grammarTextEditorState.wordWrapOtion,
                readOnly: editorStore.editorMode.disableEditing,
            });
            _editor.onDidChangeModelContent(() => {
                grammarTextEditorState.setGraphGrammarText(getCodeEditorValue(_editor));
                clearMarkers();
                // NOTE: we can technically can reset the current element label regex string here
                // but if we do that on first load, the cursor will not jump to the current element
                // also, it's better to place that logic in an effect that watches for the regex string.
                // this is done by watching `forcedCursorPosition` in the useEffect
            });
            _editor.focus(); // focus on the editor initially
            _editor.getModel()?.updateOptions({ tabSize: DEFAULT_TAB_SIZE });
            _editor.addAction({
                id: GRAMMAR_MODE_EDITOR_ACTION.GO_TO_ELEMENT_DEFINITION,
                label: 'Go To Element',
                keybindings: [KeyMod.CtrlCmd | KeyCode.KeyB],
                run: (ed) => {
                    goToElement(ed, grammarModeState);
                },
            });
            setEditor(_editor);
        }
    }, [
        editorStore,
        applicationStore,
        editor,
        grammarTextEditorState,
        grammarModeState,
    ]);
    // Drag and Drop
    const extraElementDragTypes = editorStore.pluginManager
        .getApplicationPlugins()
        .flatMap((plugin) => plugin.getExtraPureGrammarTextEditorDragElementTypes?.() ?? []);
    const handleDrop = useCallback((item) => {
        if (editor) {
            editor.trigger('keyboard', 'type', {
                text: item.data.packageableElement.path,
            });
        }
    }, [editor]);
    const [, dropConnector] = useDrop(() => ({
        accept: [
            ...extraElementDragTypes,
            CORE_DND_TYPE.PROJECT_EXPLORER_PACKAGE,
            CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
            CORE_DND_TYPE.PROJECT_EXPLORER_ASSOCIATION,
            CORE_DND_TYPE.PROJECT_EXPLORER_MEASURE,
            CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
            CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE,
            CORE_DND_TYPE.PROJECT_EXPLORER_FUNCTION,
            CORE_DND_TYPE.PROJECT_EXPLORER_FLAT_DATA,
            CORE_DND_TYPE.PROJECT_EXPLORER_DATABASE,
            CORE_DND_TYPE.PROJECT_EXPLORER_MAPPING,
            CORE_DND_TYPE.PROJECT_EXPLORER_SERVICE,
            CORE_DND_TYPE.PROJECT_EXPLORER_CONNECTION,
            CORE_DND_TYPE.PROJECT_EXPLORER_RUNTIME,
            CORE_DND_TYPE.PROJECT_EXPLORER_FILE_GENERATION,
            CORE_DND_TYPE.PROJECT_EXPLORER_GENERATION_TREE,
            CORE_DND_TYPE.PROJECT_EXPLORER_DATA,
        ],
        drop: (item) => handleDrop(item),
    }), [extraElementDragTypes, handleDrop]);
    dropConnector(ref);
    if (editor) {
        // Set the value of the editor
        const currentValue = getCodeEditorValue(editor);
        if (currentValue !== value) {
            editor.setValue(value);
        }
        resetLineNumberGutterWidth(editor);
        const editorModel = editor.getModel();
        if (editorModel) {
            // hover
            hoverProviderDisposer.current?.dispose();
            hoverProviderDisposer.current = monacoLanguagesAPI.registerHoverProvider(CODE_EDITOR_LANGUAGE.PURE, {
                provideHover: (model, position) => {
                    const currentWord = model.getWordAtPosition(position);
                    if (!currentWord) {
                        return { contents: [] };
                    }
                    // show documention for parser section
                    const lineTextIncludingWordRange = {
                        startLineNumber: position.lineNumber,
                        startColumn: 1,
                        endLineNumber: position.lineNumber,
                        endColumn: currentWord.endColumn,
                    };
                    const lineTextIncludingWord = model.getValueInRange(lineTextIncludingWordRange);
                    // NOTE: we don't need to trim here since the leading whitespace in front of
                    // the section header is considered invalid syntax in the grammar
                    if (!hasWhiteSpace(lineTextIncludingWord) &&
                        lineTextIncludingWord.startsWith(PARSER_SECTION_MARKER)) {
                        const parserKeyword = lineTextIncludingWord.substring(PARSER_SECTION_MARKER.length);
                        const doc = getParserDocumetation(editorStore, parserKeyword);
                        if (doc) {
                            return {
                                range: lineTextIncludingWordRange,
                                contents: [
                                    doc.markdownText
                                        ? {
                                            value: doc.markdownText.value,
                                        }
                                        : undefined,
                                    doc.url
                                        ? {
                                            value: `[See documentation](${doc.url})`,
                                        }
                                        : undefined,
                                ].filter(isNonNullable),
                            };
                        }
                    }
                    // show documentation for parser element
                    const textUntilPosition = model.getValueInRange({
                        startLineNumber: 1,
                        startColumn: 1,
                        endLineNumber: position.lineNumber,
                        endColumn: position.column,
                    });
                    const allParserSectionHeaders = 
                    // NOTE: since `###Pure` is implicitly considered as the first section, we prepend it to the text
                    `${PARSER_SECTION_MARKER}${PURE_PARSER.PURE}\n${textUntilPosition}`
                        .split('\n')
                        .filter((line) => line.startsWith(PARSER_SECTION_MARKER));
                    const currentSectionParserKeyword = getSectionParserNameFromLineText(allParserSectionHeaders[allParserSectionHeaders.length - 1] ??
                        '');
                    if (currentSectionParserKeyword) {
                        const doc = getParserElementDocumentation(editorStore, currentSectionParserKeyword, currentWord.word);
                        if (doc) {
                            return {
                                range: {
                                    startLineNumber: position.lineNumber,
                                    startColumn: currentWord.startColumn,
                                    endLineNumber: position.lineNumber,
                                    endColumn: currentWord.endColumn,
                                },
                                contents: [
                                    doc.markdownText
                                        ? {
                                            value: doc.markdownText.value,
                                        }
                                        : undefined,
                                    doc.url
                                        ? {
                                            value: `[See documentation](${doc.url})`,
                                        }
                                        : undefined,
                                ].filter(isNonNullable),
                            };
                        }
                    }
                    return { contents: [] };
                },
            });
            // suggestion
            suggestionProviderDisposer.current?.dispose();
            suggestionProviderDisposer.current =
                monacoLanguagesAPI.registerCompletionItemProvider(CODE_EDITOR_LANGUAGE.PURE, {
                    // NOTE: we need to specify this to show suggestions for section
                    // because by default, only alphanumeric characters trigger completion item provider
                    // See https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.CompletionContext.html#triggerCharacter
                    // See https://github.com/microsoft/monaco-editor/issues/2530#issuecomment-861757198
                    triggerCharacters: ['#'],
                    provideCompletionItems: (model, position) => {
                        let suggestions = [];
                        // suggestions for parser keyword
                        suggestions = suggestions.concat(getParserKeywordSuggestions(position, model, collectParserKeywordSuggestions(editorStore)));
                        // suggestions for parser element snippets
                        suggestions = suggestions.concat(getParserElementSnippetSuggestions(position, model, (parserName) => collectParserElementSnippetSuggestions(editorStore, parserName)));
                        // inline code snippet suggestions
                        suggestions = suggestions.concat(getInlineSnippetSuggestions(position, model));
                        return { suggestions };
                    },
                });
        }
    }
    function toggleAutoFoldingElements() {
        const autoFoldingElements = editorStore.pluginManager
            .getApplicationPlugins()
            .flatMap((plugin) => plugin.getExtraGrammarTextEditorAutoFoldingElementCreatorKeywords?.() ??
            []);
        const foldingClass = editor?.getContribution('editor.contrib.folding');
        if (editor && foldingClass) {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            foldingClass.getFoldingModel().then((foldingModel) => {
                const model = editor.getModel();
                const toggleFoldingLines = [];
                model?.getLinesContent().forEach((line, j) => {
                    autoFoldingElements.forEach((elementName) => {
                        if (line.match(new RegExp(`^${elementName}`))) {
                            toggleFoldingLines.push(j + 2);
                        }
                    });
                });
                const toFold = !elementsFolded;
                toggleFoldingLines.forEach((foldingLineRegion, i) => {
                    if (foldingModel.getAllRegionsAtLine(foldingLineRegion)[0]) {
                        if (foldingModel._regions.isCollapsed(foldingModel.getAllRegionsAtLine(foldingLineRegion)[0]
                            .regionIndex) !== toFold) {
                            foldingModel.toggleCollapseState(foldingModel.getAllRegionsAtLine(foldingLineRegion));
                        }
                    }
                });
                setFoldingElements(toFold);
            });
        }
    }
    // below use effects watch over `forcedCursorPosition`, `wordWrapOtion`, `error`, `warnings` and reset them to the editor as needed
    useEffect(() => {
        if (editor && forcedCursorPosition) {
            moveCursorToPosition(editor, forcedCursorPosition);
        }
    }, [editor, forcedCursorPosition]);
    useEffect(() => {
        if (editor) {
            editor.updateOptions({
                wordWrap: wordWrapOtion,
            });
        }
    }, [editor, wordWrapOtion]);
    useEffect(() => {
        const editorModel = editor?.getModel();
        if (editorModel && (error?.sourceInformation || warnings.length)) {
            if (error?.sourceInformation) {
                setErrorMarkers(editorModel, [
                    {
                        message: error.message,
                        startLineNumber: error.sourceInformation.startLine,
                        startColumn: error.sourceInformation.startColumn,
                        endLineNumber: error.sourceInformation.endLine,
                        endColumn: error.sourceInformation.endColumn,
                    },
                ]);
            }
            if (warnings.length) {
                setWarningMarkers(editorModel, warnings
                    .map((warning) => {
                    if (!warning.sourceInformation) {
                        return undefined;
                    }
                    return {
                        message: warning.message,
                        startLineNumber: warning.sourceInformation.startLine,
                        startColumn: warning.sourceInformation.startColumn,
                        endLineNumber: warning.sourceInformation.endLine,
                        endColumn: warning.sourceInformation.endColumn,
                    };
                })
                    .filter(isNonNullable));
            }
        }
    }, [editor, error, warnings]);
    // first load with grammar. auto fold element sections
    useEffect(() => {
        if (editor) {
            const model = editor.getModel();
            const autoFoldingElements = editorStore.pluginManager
                .getApplicationPlugins()
                .flatMap((plugin) => plugin.getExtraGrammarTextEditorAutoFoldingElementCreatorKeywords?.() ??
                []);
            const foldingClass = editor.getContribution('editor.contrib.folding');
            if (foldingClass && model) {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                foldingClass.getFoldingModel().then((foldingModel) => {
                    if (foldingModel) {
                        const elementLinesToBeFolded = [];
                        model.getLinesContent().forEach((line, idx) => {
                            autoFoldingElements.forEach((elementName) => {
                                if (line.match(new RegExp(`^${elementName}`))) {
                                    elementLinesToBeFolded.push(idx + 2);
                                }
                            });
                        });
                        elementLinesToBeFolded.forEach((lineToBeFolded) => {
                            const regionToFold = foldingModel.getAllRegionsAtLine(lineToBeFolded);
                            foldingModel.toggleCollapseState(regionToFold);
                        });
                        setFoldingElements(true);
                    }
                });
            }
        }
    }, [editor, editorStore.pluginManager]);
    // NOTE: dispose the editor to prevent potential memory-leak
    useEffect(() => () => {
        if (editor) {
            disposeCodeEditor(editor);
        }
        // Dispose the providers properly to avoid ending up with duplicated suggestions
        hoverProviderDisposer.current?.dispose();
        suggestionProviderDisposer.current?.dispose();
    }, [editor]);
    useApplicationNavigationContext(LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.TEXT_MODE_EDITOR);
    return (_jsxs("div", { className: "panel editor-group", children: [_jsxs("div", { className: "panel__header editor-group__header", children: [_jsx("div", { className: "editor-group__header__tabs", children: _jsx(ContextMenu, { className: "editor-group__text-mode__tab editor-group__text-mode__tab--active", content: _jsx(GrammarTextEditorHeaderTabContextMenu, {}), children: _jsx("div", { className: "editor-group__text-mode__tab__label", children: grammarModeState.headerLabel }) }) }), _jsxs("div", { className: "editor-group__header__actions", children: [_jsx("div", { className: "editor-group__text-mode__action", children: _jsx("button", { title: "Compile (F9)", onClick: globalCompile, className: "editor-group__text-mode-btn btn--dark", children: "Compile" }) }), _jsx("div", { className: "editor-group__text-mode__action", children: _jsx("button", { title: "Click to exit text mode and go back to form mode (F8)", onClick: leaveTextMode, className: "editor-group__text-mode-btn btn--dark", children: "Exit Text Mode" }) }), _jsx("div", { className: "query-builder__header__actions", children: _jsxs(ControlledDropdownMenu, { className: "query-builder__header__advanced-dropdown", title: "Show Advanced Menu...", content: _jsxs(MenuContent, { children: [_jsxs(MenuContentItem, { onClick: toggleWordWrap, children: [_jsx(MenuContentItemIcon, { children: grammarTextEditorState.wrapText ? _jsx(CheckIcon, {}) : null }), _jsx(MenuContentItemLabel, { children: "Wrap Overflowing Words" })] }), _jsxs(MenuContentItem, { onClick: toggleAutoFoldingElements, children: [_jsx(MenuContentItemIcon, { children: elementsFolded ? _jsx(CheckIcon, {}) : null }), _jsx(MenuContentItemLabel, { children: "Auto Fold Elements" })] })] }), menuProps: {
                                        anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
                                        transformOrigin: { vertical: 'top', horizontal: 'right' },
                                        elevation: 7,
                                    }, children: [_jsx("div", { className: "query-builder__header__advanced-dropdown__label", children: "Advanced" }), _jsx(CaretDownIcon, { className: "query-builder__header__advanced-dropdown__icon" })] }) })] })] }), _jsxs(PanelContent, { className: "editor-group__content", children: [_jsx(PanelLoadingIndicator, { isLoading: editorStore.graphState.isRunningGlobalCompile }), _jsx("div", { className: "code-editor__container", children: _jsx("div", { className: "code-editor__body", ref: ref }) })] }), grammarModeState.generatedFile && (_jsx(FileSystem_FileModal, { generatedFile: grammarModeState.generatedFile, graphEditGrammarModeState: grammarModeState }))] }));
});
//# sourceMappingURL=GrammarTextEditor.js.map