UNPKG

@finos/legend-code-editor

Version:

Legend shared advanced application components and building blocks

139 lines 7.67 kB
/** * 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 { editor as monacoEditorAPI, MarkerSeverity } from 'monaco-editor'; import { CODE_EDITOR_THEME, DEFAULT_DARK_THEME, GITHUB_DARK_DIMMED_THEME, GITHUB_DARK_THEME, GITHUB_LIGHT_THEME, MATERIAL_DARKER_THEME, MATERIAL_DEFAULT_THEME, ONE_DARK_PRO_DARKER_THEME, ONE_DARK_PRO_THEME, SOLARIZED_DARK_THEME, } from './CodeEditorTheme.js'; /** * Get the text value with LF line ending. * This is needed since if there are CR `\r` characters in the text input * (e.g. users of Windows doing copy/paste) * the default mode of `monaco-editor` is `TextDefined` which means if the text * contains CR character(s), it will automatically be treated as CRLF. As such, we want * an utility method to extract the text value with line ending option LF * to force omission of CR characters * See https://github.com/finos/legend-studio/issues/608 */ export const getCodeEditorValue = (editor) => editor.getModel()?.getValue(monacoEditorAPI.EndOfLinePreference.LF) ?? ''; export const getBaseCodeEditorOptions = () => ({ contextmenu: false, copyWithSyntaxHighlighting: false, // NOTE: These following font options are needed (and CSS font-size option `.monaco-editor * { font-size: ... }` as well) // in order to make the editor appear properly on multiple platform, the ligatures option is needed for Mac to display properly // otherwise the cursor position relatively to text would be off // Another potential cause for this misaligment is that the fonts are being lazy-loaded and made available after `monaco-editor` // calculated the font-width, for this, we can use `remeasureFonts`, but our case here, `fontLigatures: true` seems // to do the trick // See https://github.com/microsoft/monaco-editor/issues/392 fontSize: 14, // Enforce a fixed font-family to make cross platform display consistent (i.e. Mac defaults to use `Menlo` which is bigger than // `Consolas` on Windows, etc.) fontFamily: 'Roboto Mono', // Enable font ligature: glyphs which combine the shapes of certain sequences of characters into a new form that makes for // a more harmonious reading experience. fontLigatures: true, // Make sure hover or widget shown near boundary are not truncated by setting their position to `fixed` fixedOverflowWidgets: true, detectIndentation: false, // i.e. so we can force tab-size tabSize: 2, // The typing is currently not correct for `bracketPairColorization`, until this is fixed, we will remove the cast // See https://github.com/microsoft/monaco-editor/issues/3013 'bracketPairColorization.enabled': false, automaticLayout: true, }); export const moveCursorToPosition = (editor, position) => { if (!editor.hasTextFocus()) { editor.focus(); } // focus the editor first so that it can shows the cursor editor.revealPositionInCenter(position, 0); editor.setPosition(position); }; const INTERNAL__DUMMY_PROBLEM_MARKER_OWNER = 'dummy_problem_marker_owner'; export const setErrorMarkers = (editorModel, errors, ownerId) => { monacoEditorAPI.setModelMarkers(editorModel, ownerId ?? INTERNAL__DUMMY_PROBLEM_MARKER_OWNER, errors.map((error) => ({ startLineNumber: error.startLineNumber, startColumn: error.startColumn, endLineNumber: error.endLineNumber, endColumn: error.endColumn + 1, // add a 1 to endColumn as monaco editor range is not inclusive // NOTE: when the message is empty, no error tooltip is shown, we want to avoid this message: error.message === '' ? '(no error message)' : error.message, severity: MarkerSeverity.Error, }))); }; export const setWarningMarkers = (editorModel, warnings, ownerId) => { monacoEditorAPI.setModelMarkers(editorModel, ownerId ?? INTERNAL__DUMMY_PROBLEM_MARKER_OWNER, warnings.map((warning) => ({ startLineNumber: warning.startLineNumber, startColumn: warning.startColumn, endColumn: warning.endColumn, endLineNumber: warning.endLineNumber, message: warning.message === '' ? '(no warning message)' : warning.message, severity: MarkerSeverity.Warning, }))); }; export const clearMarkers = (ownerId) => { monacoEditorAPI.removeAllMarkers(ownerId ?? INTERNAL__DUMMY_PROBLEM_MARKER_OWNER); }; /** * This method eliminates CR '\r' character(s) in the provided text value. */ export const normalizeLineEnding = (val) => val.replace(/\r/g, ''); // We need to dynamically adjust the width of the line number gutter, otherwise as the document gets // larger, the left margin will start to shrink // See https://github.com/microsoft/monaco-editor/issues/2206 export const resetLineNumberGutterWidth = (editor) => { const currentValue = editor.getValue(); editor.updateOptions({ lineNumbersMinChars: Math.max(Math.floor(Math.log10(currentValue.split(/\r\n|\r|\n/g).length)) + 3, 5), }); }; export const configureCodeEditor = async (fontFamily, onError) => { // themes monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.DEFAULT_DARK, DEFAULT_DARK_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.SOLARIZED_DARK, SOLARIZED_DARK_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.GITHUB_DARK, GITHUB_DARK_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.GITHUB_DARK_DIMMED, GITHUB_DARK_DIMMED_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.GITHUB_LIGHT, GITHUB_LIGHT_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.MATERIAL_DEFAULT, MATERIAL_DEFAULT_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.MATERIAL_DARKER, MATERIAL_DARKER_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.ONE_DARK_PRO, ONE_DARK_PRO_THEME); monacoEditorAPI.defineTheme(CODE_EDITOR_THEME.ONE_DARK_PRO_DARKER, ONE_DARK_PRO_DARKER_THEME); /** * Since we use a custom fonts for text-editor, we want to make sure the font is loaded before any text-editor is opened * this is to ensure */ const fontLoadFailureErrorMessage = `Monospaced font '${fontFamily}' has not been loaded properly, code editor might not display properly`; await Promise.all([400, 700].map((weight) => document.fonts.load(`${weight} 1em ${fontFamily}`))) .then(() => { if (document.fonts.check(`1em ${fontFamily}`)) { monacoEditorAPI.remeasureFonts(); } else { onError(new Error(fontLoadFailureErrorMessage)); } }) .catch(() => onError(new Error(fontLoadFailureErrorMessage))); }; export var CODE_EDITOR_LANGUAGE; (function (CODE_EDITOR_LANGUAGE) { CODE_EDITOR_LANGUAGE["TEXT"] = "plaintext"; CODE_EDITOR_LANGUAGE["PURE"] = "pure"; CODE_EDITOR_LANGUAGE["JSON"] = "json"; CODE_EDITOR_LANGUAGE["JAVA"] = "java"; CODE_EDITOR_LANGUAGE["MARKDOWN"] = "markdown"; CODE_EDITOR_LANGUAGE["SQL"] = "sql"; CODE_EDITOR_LANGUAGE["XML"] = "xml"; CODE_EDITOR_LANGUAGE["YAML"] = "yaml"; CODE_EDITOR_LANGUAGE["GRAPHQL"] = "graphql"; })(CODE_EDITOR_LANGUAGE || (CODE_EDITOR_LANGUAGE = {})); //# sourceMappingURL=CodeEditorUtils.js.map