import { computed, CSSProperties, defineComponent, nextTick, onMounted, onUnmounted, ref, shallowRef, watch, } from 'vue'; import * as monaco from 'monaco-editor'; import './index.scss'; import { bkTooltips } from 'bkui-vue'; import { Code, FilliscreenLine, UnfullScreen } from 'bkui-vue/lib/icon'; import { format } from 'sql-formatter'; import { props } from '@/component/monaco/props'; import { debounce } from 'bkui-vue/lib/shared'; export default defineComponent({ name: 'MonacoEditor', directives: { bkTooltips }, props, emits: ['update:modelValue', 'change', 'editorMounted'], setup(props, { emit, slots, expose }) { const editor = shallowRef(null); const domRef = ref(); const isFull = ref(false); const loading = ref(true); const style = computed(() => { if (isFull.value) { return { position: 'fixed', top: 0, left: 0, zIndex: 999999999, width: '100%', height: '100%', }; } return { width: typeof props.width === 'number' ? `${props.width}px` : props.width, height: typeof props.height === 'number' ? `${props.height}px` : props.height, }; }); const tooltips: Record = getTooltips(); watch(() => [props.height, props.width], () => { resize(); }); function getTooltips() { if (props?.tooltips) { return props.tooltips; } const currentLang = props?.currentLang ?? localStorage.getItem('blueking_language'); if (currentLang === 'en') { return { format: 'Format', fullScreen: 'Full Screen', exitScreen: 'Exit Full Screen', adjustFontSize: 'Adjusting the font size', }; } return { format: '格式化', fullScreen: '全屏', exitScreen: '退出全屏', adjustFontSize: '调整字号大小', }; } async function initMonaco() { if (!domRef.value) { console.error('monaco editor dom is null'); return; } const { modelValue, language, theme, options } = props; if (typeof props?.onBeforeMount === 'function') { await props?.onBeforeMount?.(monaco, domRef.value); } editor.value = monaco.editor.create(domRef.value, { value: modelValue, language, theme, wordWrap: 'on', ...options, }); loading.value = false; editor.value.onDidChangeModelContent(() => { const value = editor.value.getValue() || ''; emit('update:modelValue', value); emit('change', value); }); emit('editorMounted', editor, domRef.value); } function clearMistake() { monaco.editor.setModelMarkers( editor.value.getModel(), 'eslint', [], ); } function markMistake(range: any, type: keyof typeof monaco.MarkerSeverity, message: string) { const { startLineNumber, endLineNumber, startColumn, endColumn } = range; monaco.editor.setModelMarkers( editor.value.getModel(), 'eslint', [{ startLineNumber, endLineNumber, startColumn, endColumn, severity: monaco.MarkerSeverity[type], // type可以是Error,Warning,Info message, }], ); } function formatSql(needValue: number) { clearMistake(); try { editor.value.setValue(format(editor.value.getValue())); } catch (e) { const { message } = e; const list = message.split(' '); const line = list.indexOf('line'); const column = list.indexOf('column'); markMistake({ startLineNumber: Number(list[line + 1]), endLineNumber: Number(list[line + 1]), startColumn: Number(list[column + 1]), endColumn: Number(list[column + 1]), }, 'Error', message); } if (needValue) { return editor.value.getValue(); } } function formatContext() { if (props.language === 'sql') { formatSql(0); return; } // @ts-ignore editor.value?.trigger('anyString', 'editor.action.formatDocument'); try { editor.value?.setValue(editor.value?.getValue()); } catch (e) { console.error(e); } } const resize = debounce(200, () => { editor.value?.layout(); }); function fullScreen() { isFull.value = !isFull.value; nextTick(() => { resize(); }); } onMounted(() => { initMonaco(); }); onUnmounted(() => { editor.value?.dispose(); editor.value = null; }); watch( () => props.modelValue, (newVal) => { if (editor.value && newVal !== editor.value.getValue()) { editor.value.setValue(newVal); } }, ); watch( () => props.language, (language) => { if (language && editor) { const model = editor.value.getModel(); model && monaco.editor.setModelLanguage(model, language); } }, ); watch( () => props.theme, (theme) => { if (theme && editor) { monaco.editor.setTheme(theme); } }, ); expose({ isFull, style, editor, domRef, loading, clearMistake, formatContext, fullScreen, resize, }); return () => { function toolsRender() { if (!props.isShowToolbox) { return null; } if (typeof slots?.tools === 'function') { return slots?.tools(editor); } if (!props.isShowTooltips) { return (
{isFull.value ? : }
); } // {...(props.isShowTooltips ? { 'v-bkTooltips': { content: tooltips.format } } : {})} return (
{isFull.value ? : }
); } return (
{loading.value ? slots.loading?.() ?? '' : ''} {props.isShowHeader ? (
{slots?.title?.() ?? props?.title}
{toolsRender()}
) : ''}
); }; }, });