Skip to content

Commit e833cf1

Browse files
committed
feat: use monaco
1 parent 977011f commit e833cf1

18 files changed

+33643
-16
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,11 @@
4949
},
5050
"peerDependencies": {
5151
"vue": "^3.2.13"
52+
},
53+
"dependencies": {
54+
"monaco-editor": "^0.33.0",
55+
"monaco-editor-textmate": "^3.0.0",
56+
"monaco-textmate": "^3.0.1",
57+
"onigasm": "^2.2.5"
5258
}
5359
}

pnpm-lock.yaml

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/editor/Editor.vue

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
11
<script setup lang="ts">
22
import FileSelector from './FileSelector.vue'
3-
import CodeMirror from '../codemirror/CodeMirror.vue'
3+
import Monaco from '../monaco/Monaco.vue'
44
import Message from '../Message.vue'
5-
import { debounce } from '../utils'
65
import { computed, inject } from 'vue'
76
import { Store } from '../store'
87
98
const store = inject('store') as Store
109
11-
const onChange = debounce((code: string) => {
10+
const onChange = (code: string) => {
1211
store.state.activeFile.code = code
13-
}, 250)
12+
}
1413
15-
const activeMode = computed(() => {
14+
const language = computed(() => {
1615
const { filename } = store.state.activeFile
17-
return filename.endsWith('.vue') || filename.endsWith('.html')
18-
? 'htmlmixed'
19-
: filename.endsWith('.css')
20-
? 'css'
21-
: 'javascript'
16+
if (filename.endsWith('.vue')) {
17+
return 'vue'
18+
}
19+
if (filename.endsWith('.html')) {
20+
return 'html'
21+
}
22+
if (filename.endsWith('.css')) {
23+
return 'css'
24+
}
25+
if (filename.endsWith('.ts')) {
26+
return 'typescript'
27+
}
28+
return 'javascript'
2229
})
2330
</script>
2431

2532
<template>
2633
<FileSelector />
2734
<div class="editor-container">
28-
<CodeMirror
29-
@change="onChange"
35+
<Monaco
3036
:value="store.state.activeFile.code"
31-
:mode="activeMode"
37+
:language="language"
38+
@save="onChange"
3239
/>
3340
<Message :err="store.state.errors[0]" />
3441
</div>

src/monaco/Monaco.vue

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<script lang="ts">
2+
import { setupMonacoEnv } from './utils';
3+
setupMonacoEnv();
4+
</script>
5+
<script lang="ts" setup>
6+
import { onMounted, onBeforeUnmount, ref, shallowRef, nextTick, watchEffect } from 'vue';
7+
import { loadGrammars } from './grammars';
8+
import * as monaco from 'monaco-editor';
9+
import { setupThemePromise } from './utils';
10+
11+
interface Props {
12+
value?: string
13+
language?: string;
14+
readonly?: boolean
15+
}
16+
17+
const props = withDefaults(defineProps<Props>(), {
18+
value: '',
19+
readonly: false
20+
})
21+
22+
const emits = defineEmits<{
23+
(e: 'change', value: string): void,
24+
(e: 'save', value: string): void
25+
}>()
26+
27+
const containerRef = ref<HTMLDivElement | null>();
28+
const ready = ref(false);
29+
const editor = shallowRef<monaco.editor.IStandaloneCodeEditor | undefined>(undefined);
30+
31+
onMounted(async () => {
32+
const theme = await setupThemePromise;
33+
ready.value = true;
34+
await nextTick();
35+
36+
if (!containerRef.value) {
37+
throw new Error("Cannot find containerRef");
38+
}
39+
40+
const editorInstance = monaco.editor.create(containerRef.value, {
41+
theme,
42+
value: props.value,
43+
language: props.language,
44+
readOnly: props.readonly,
45+
automaticLayout: true,
46+
scrollBeyondLastLine: false,
47+
minimap: {
48+
enabled: false,
49+
},
50+
inlineSuggest: {
51+
enabled: false,
52+
},
53+
});
54+
editor.value = editorInstance
55+
56+
await loadGrammars(editorInstance);
57+
58+
editorInstance.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
59+
emits('save', editorInstance.getValue());
60+
});
61+
62+
editorInstance.onDidChangeModelContent(() => {
63+
emits('change', editorInstance.getValue());
64+
});
65+
});
66+
67+
watchEffect(() => {
68+
if (editor.value && editor.value.getValue() !== props.value) {
69+
editor.value.setValue(props.value);
70+
}
71+
})
72+
73+
onBeforeUnmount(() => {
74+
editor.value?.dispose();
75+
});
76+
</script>
77+
<template>
78+
<div class="editor" ref="containerRef"></div>
79+
</template>
80+
<style>
81+
.editor {
82+
position: relative;
83+
height: 100%;
84+
width: 100%;
85+
overflow: hidden;
86+
}
87+
</style>

0 commit comments

Comments
 (0)