瀏覽代碼

feat: replace code editor

Ahmad Kholid 3 年之前
父節點
當前提交
f49e246050

+ 4 - 2
package.json

@@ -21,6 +21,10 @@
     "*.{js,ts,vue}": "eslint --fix"
   },
   "dependencies": {
+    "@codemirror/basic-setup": "^0.19.1",
+    "@codemirror/lang-javascript": "^0.19.3",
+    "@codemirror/lang-json": "^0.19.1",
+    "@codemirror/theme-one-dark": "^0.19.1",
     "@medv/finder": "^2.1.0",
     "@vuex-orm/core": "^0.36.4",
     "dayjs": "^1.10.7",
@@ -30,13 +34,11 @@
     "nanoid": "3.1.28",
     "object-path-immutable": "^4.1.2",
     "papaparse": "^5.3.1",
-    "prismjs": "^1.25.0",
     "tiny-emitter": "^2.1.0",
     "tippy.js": "^6.3.1",
     "v-remixicon": "^0.1.1",
     "vue": "3.2.19",
     "vue-i18n": "^9.2.0-beta.20",
-    "vue-prism-editor": "^2.0.0-alpha.2",
     "vue-router": "^4.0.11",
     "vuedraggable": "^4.1.0",
     "vuex": "^4.0.2",

+ 0 - 13
src/assets/css/prism-editor.css

@@ -1,13 +0,0 @@
-.my-editor,
-.prism-editor-wrapper {
-  color: #ccc;
-  font-family: JetBrains Mono, Fira code, Fira Mono, Consolas, Menlo, Courier,
-    monospace;
-  font-size: 14px;
-  line-height: 1.5;
-  padding: 5px;
-  @apply bg-gray-900 rounded-lg;
-}
-.prism-editor__textarea:focus {
-  outline: none;
-}

+ 3 - 0
src/assets/css/tailwind.css

@@ -33,6 +33,9 @@ select:focus,
   overflow: hidden;
   text-overflow: ellipsis;
 }
+pre {
+  font-size: 15px;
+}
 .scroll::-webkit-scrollbar {
   width: 7px;
   height: 9px;

+ 5 - 6
src/components/newtab/logs/LogsDataViewer.vue

@@ -26,21 +26,20 @@
       </ui-list>
     </ui-popover>
   </div>
-  <prism-editor
+  <shared-codemirror
     :model-value="jsonData"
-    :highlight="highlighter('json')"
     :class="editorClass"
+    lang="json"
     readonly
-    class="my-editor p-4 bg-gray-900 rounded-lg mt-4"
-  ></prism-editor>
+    class="mt-4"
+  />
 </template>
 <script setup>
 import { ref } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { PrismEditor } from 'vue-prism-editor';
-import { highlighter } from '@/lib/prism';
 import { dataExportTypes } from '@/utils/shared';
 import dataExporter, { generateJSON } from '@/utils/data-exporter';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   log: {

+ 101 - 0
src/components/newtab/shared/SharedCodemirror.vue

@@ -0,0 +1,101 @@
+<template>
+  <div
+    ref="containerEl"
+    :class="{ 'hide-gutters': !lineNumbers }"
+    class="codemirror relative"
+  ></div>
+</template>
+<script setup>
+import { onMounted, ref, onBeforeUnmount, watch } from 'vue';
+import { json } from '@codemirror/lang-json';
+import { indentWithTab } from '@codemirror/commands';
+import { oneDark } from '@codemirror/theme-one-dark';
+import { EditorView, keymap } from '@codemirror/view';
+import { javascript } from '@codemirror/lang-javascript';
+import { EditorState, basicSetup } from '@codemirror/basic-setup';
+
+const props = defineProps({
+  lang: {
+    type: String,
+    default: 'javascript',
+  },
+  modelValue: {
+    type: String,
+    default: '',
+  },
+  readonly: {
+    type: Boolean,
+    default: false,
+  },
+  lineNumbers: {
+    type: Boolean,
+    default: true,
+  },
+});
+const emit = defineEmits(['change', 'update:modelValue']);
+
+let view = null;
+const containerEl = ref(null);
+
+const updateListener = EditorView.updateListener.of((event) => {
+  if (event.docChanged) {
+    event.state.sliceDoc(0, 20);
+
+    const newValue = event.state.doc.toString();
+
+    emit('change', newValue);
+    emit('update:modelValue', newValue);
+  }
+});
+
+const state = EditorState.create({
+  doc: props.modelValue,
+  extensions: [
+    oneDark,
+    basicSetup,
+    updateListener,
+    EditorState.tabSize.of(2),
+    keymap.of([indentWithTab]),
+    EditorState.readOnly.of(props.readonly),
+    props.lang === 'javascript' ? javascript() : json(),
+  ],
+});
+
+watch(
+  () => props.modelValue,
+  (value) => {
+    if (value === view.state.doc.toString()) return;
+
+    view.dispatch({
+      changes: { from: 0, to: view.state.doc.length, insert: value },
+    });
+  }
+);
+
+onMounted(() => {
+  view = new EditorView({
+    state,
+    parent: containerEl.value,
+  });
+});
+onBeforeUnmount(() => {
+  view?.destroy();
+});
+</script>
+<style>
+.codemirror.hide-gutters .cm-gutters {
+  display: none !important;
+}
+
+.cm-editor {
+  height: 100%;
+  font-size: 15px;
+}
+
+.cm-editor .cm-gutters,
+.cm-editor .cm-content,
+.cm-tooltip.cm-tooltip-autocomplete > ul {
+  font-family: JetBrains Mono, Fira code, Fira Mono, Consolas, Menlo, Courier,
+    monospace !important;
+}
+</style>

+ 3 - 5
src/components/newtab/workflow/WorkflowGlobalData.vue

@@ -11,20 +11,18 @@
     <p class="float-right clear-both" title="Characters limit">
       {{ globalData.length }}/{{ maxLength.toLocaleString() }}
     </p>
-    <prism-editor
+    <shared-codemirror
       v-model="globalData"
-      :highlight="highlighter('json')"
-      class="h-full scroll mt-2"
       style="height: calc(100vh - 10rem)"
+      lang="json"
     />
   </div>
 </template>
 <script setup>
 import { ref, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { PrismEditor } from 'vue-prism-editor';
-import { highlighter } from '@/lib/prism';
 import { debounce } from '@/utils/helper';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   workflow: {

+ 8 - 18
src/components/newtab/workflow/edit/EditExecuteWorkflow.vue

@@ -15,13 +15,11 @@
       </option>
     </ui-select>
     <p>{{ t('common.globalData') }}</p>
-    <prism-editor
+    <pre
       v-if="!state.showGlobalData"
-      :model-value="data.globalData"
-      :highlight="highlighter('json')"
-      readonly
-      class="p-4 max-h-80"
+      class="rounded-lg text-gray-200 p-4 max-h-80 bg-gray-900 overflow-auto"
       @click="state.showGlobalData = true"
+      v-text="data.globalData"
     />
     <ui-modal
       v-model="state.showGlobalData"
@@ -29,12 +27,12 @@
       content-class="max-w-xl"
     >
       <p>{{ t('workflow.blocks.execute-workflow.overwriteNote') }}</p>
-      <prism-editor
-        :model-value="state.globalData"
-        :highlight="highlighter('json')"
+      <shared-codemirror
+        :model-value="data.globalData"
+        lang="json"
         class="w-full scroll"
         style="height: calc(100vh - 10rem)"
-        @input="updateGlobalData"
+        @change="updateData({ globalData: $event })"
       />
     </ui-modal>
   </div>
@@ -43,9 +41,8 @@
 import { computed, shallowReactive } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { useRoute } from 'vue-router';
-import { PrismEditor } from 'vue-prism-editor';
-import { highlighter } from '@/lib/prism';
 import Workflow from '@/models/workflow';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   data: {
@@ -64,7 +61,6 @@ const route = useRoute();
 
 const state = shallowReactive({
   showGlobalData: false,
-  globalData: `${props.data.globalData}`,
 });
 
 const workflows = computed(() =>
@@ -80,10 +76,4 @@ const workflows = computed(() =>
 function updateData(value) {
   emit('update:data', { ...props.data, ...value });
 }
-function updateGlobalData(event) {
-  const { value } = event.target;
-
-  state.globalData = value;
-  updateData({ globalData: value });
-}
 </script>

+ 6 - 11
src/components/newtab/workflow/edit/EditJavascriptCode.vue

@@ -15,13 +15,11 @@
       :title="t('workflow.blocks.javascript-code.timeout.title')"
       @change="updateData({ timeout: +$event })"
     />
-    <prism-editor
+    <pre
       v-if="!state.showCodeModal"
-      :model-value="data.code"
-      :highlight="highlighter('javascript')"
-      readonly
-      class="p-4 max-h-80"
+      class="rounded-lg overflow-auto text-gray-200 p-4 max-h-80 bg-gray-900"
       @click="state.showCodeModal = true"
+      v-text="data.code"
     />
     <ui-modal v-model="state.showCodeModal" content-class="max-w-3xl">
       <template #header>
@@ -40,11 +38,9 @@
         style="height: calc(100vh - 9rem)"
       >
         <ui-tab-panel value="code" class="h-full">
-          <prism-editor
+          <shared-codemirror
             v-model="state.code"
-            :highlight="highlighter('javascript')"
-            line-numbers
-            class="py-4 overflow-auto"
+            class="overflow-auto"
             style="height: 87%"
           />
           <p class="mt-1">
@@ -96,8 +92,7 @@
 <script setup>
 import { watch, reactive } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { PrismEditor } from 'vue-prism-editor';
-import { highlighter } from '@/lib/prism';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   data: {

+ 16 - 29
src/components/newtab/workflow/edit/EditLoopData.vue

@@ -82,7 +82,7 @@
           {{ t('workflow.blocks.loop-data.buttons.import') }}
         </ui-button>
         <ui-button
-          v-tooltip="t('commons.options')"
+          v-tooltip="t('common.options')"
           :class="{ 'text-primary': state.showOptions }"
           icon
           class="ml-2"
@@ -91,24 +91,15 @@
           <v-remixicon name="riSettings3Line" />
         </ui-button>
         <p class="flex-1 text-overflow mx-4">{{ file.name }}</p>
-        <template v-if="data.loopData.length > maxStrLength">
-          <p class="mr-2">
-            {{ t('workflow.blocks.loop-data.modal.fileTooLarge') }}
-          </p>
-          <ui-button @click="updateData({ loopData: '[]' })">
-            {{ t('workflow.blocks.loop-data.buttons.clear') }}
-          </ui-button>
-        </template>
-        <p v-else>{{ t('workflow.blocks.loop-data.modal.maxFile') }}</p>
+        <p>{{ t('workflow.blocks.loop-data.modal.maxFile') }}</p>
       </div>
       <div style="height: calc(100vh - 11rem)">
-        <prism-editor
+        <shared-codemirror
           v-show="!state.showOptions"
-          v-model="state.tempLoopData"
-          :highlight="highlighter('json')"
-          :readonly="data.loopData.length > maxStrLength"
-          class="py-4"
-          @input="updateData({ loopData: $event.target.value })"
+          :model-value="data.loopData"
+          lang="json"
+          class="h-full"
+          @change="updateLoopData"
         />
         <div v-show="state.showOptions">
           <p class="font-semibold mb-2">CSV</p>
@@ -124,11 +115,10 @@
 /* eslint-disable no-alert */
 import { onMounted, shallowReactive } from 'vue';
 import { nanoid } from 'nanoid';
-import { PrismEditor } from 'vue-prism-editor';
 import { useI18n } from 'vue-i18n';
 import Papa from 'papaparse';
-import { highlighter } from '@/lib/prism';
 import { openFilePicker } from '@/utils/helper';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   blockId: {
@@ -144,16 +134,10 @@ const emit = defineEmits(['update:data']);
 
 const { t } = useI18n();
 
-const maxStrLength = 5e4;
 const maxFileSize = 1024 * 1024;
 const loopTypes = ['data-columns', 'numbers', 'custom-data'];
-const tempLoopData =
-  props.data.loopData.length > maxStrLength
-    ? props.data.loopData.slice(0, maxStrLength)
-    : props.data.loopData;
 
 const state = shallowReactive({
-  tempLoopData,
   showOptions: false,
   showDataModal: false,
   workflowLoopData: {},
@@ -170,6 +154,13 @@ const file = shallowReactive({
 function updateData(value) {
   emit('update:data', { ...props.data, ...value });
 }
+function updateLoopData(value) {
+  if (value.length > maxFileSize) {
+    alert(t('message.maxSizeExceeded'));
+  }
+
+  updateData({ loopData: value.slice(0, maxFileSize) });
+}
 function updateLoopID(id) {
   let loopId = id.replace(/\s/g, '');
 
@@ -205,12 +196,8 @@ function importFile() {
         }
 
         if (Array.isArray(loopData)) {
-          const loopDataStr = JSON.stringify(loopData);
+          const loopDataStr = JSON.stringify(loopData, null, 2);
 
-          state.tempLoopData =
-            loopDataStr.length > maxStrLength
-              ? loopDataStr.slice(0, maxStrLength)
-              : loopDataStr;
           updateData({ loopData: loopDataStr });
         }
       };

+ 19 - 23
src/components/newtab/workflow/edit/EditWebhook.vue

@@ -38,9 +38,9 @@
       @change="updateData({ timeout: +$event })"
     />
     <ui-tabs v-model="activeTab" fill class="mb-4">
-      <ui-tab value="headers">{{
-        t('workflow.blocks.webhook.tabs.headers')
-      }}</ui-tab>
+      <ui-tab value="headers">
+        {{ t('workflow.blocks.webhook.tabs.headers') }}
+      </ui-tab>
       <ui-tab value="body">{{ t('workflow.blocks.webhook.tabs.body') }}</ui-tab>
     </ui-tabs>
     <ui-tab-panels :model-value="activeTab">
@@ -74,13 +74,18 @@
         </ui-button>
       </ui-tab-panel>
       <ui-tab-panel value="body">
-        <prism-editor
+        <pre
           v-if="!showContentModalRef"
-          :highlight="highlighter('json')"
-          :model-value="data.body"
-          class="p-4 max-h-80 mb-2"
-          readonly
+          class="
+            rounded-lg
+            text-gray-200
+            p-4
+            max-h-80
+            bg-gray-900
+            overflow-auto
+          "
           @click="showContentModalRef = true"
+          v-text="data.body"
         />
       </ui-tab-panel>
     </ui-tab-panels>
@@ -89,12 +94,11 @@
       content-class="max-w-3xl"
       :title="t('workflow.blocks.webhook.tabs.body')"
     >
-      <prism-editor
-        v-model="contentRef"
-        :highlight="highlighter('json')"
-        class="py-4"
-        line-numbers
-        style="height: calc(100vh - 18rem)"
+      <shared-codemirror
+        :model-value="data.body"
+        lang="json"
+        style="height: calc(100vh - 10rem)"
+        @change="updateData({ body: $event })"
       />
       <div class="mt-3">
         <a
@@ -112,9 +116,8 @@
 <script setup>
 import { ref, watch } from 'vue';
 import { useI18n } from 'vue-i18n';
-import { PrismEditor } from 'vue-prism-editor';
-import { highlighter } from '@/lib/prism';
 import { contentTypes } from '@/utils/shared';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 
 const props = defineProps({
   data: {
@@ -127,22 +130,15 @@ const emit = defineEmits(['update:data']);
 const { t } = useI18n();
 
 const activeTab = ref('headers');
-const contentRef = ref(props.data.body);
 const headerRef = ref(props.data.headers);
 const showContentModalRef = ref(false);
 
 function updateData(value) {
   emit('update:data', { ...props.data, ...value });
 }
-
-watch(contentRef, (value) => {
-  updateData({ body: value });
-});
-
 function removeHeader(index) {
   headerRef.value.splice(index, 1);
 }
-
 function addHeader() {
   headerRef.value.push({ name: '', value: '' });
 }

+ 5 - 5
src/content/element-selector/AppBlocks.vue

@@ -26,26 +26,26 @@
       :hide-base="true"
       @update:data="updateParams"
     />
-    <prism-editor
+    <shared-codemirror
       v-if="state.blockResult"
       v-model="state.blockResult"
+      :line-numbers="false"
       readonly
-      :highlight="highlighter('json')"
-      class="h-full scroll mt-2"
+      lang="json"
+      class="h-full mt-2"
     />
   </div>
 </template>
 <script setup>
 import { shallowReactive } from 'vue';
-import { PrismEditor } from 'vue-prism-editor';
 import { tasks } from '@/utils/shared';
-import { highlighter } from '@/lib/prism';
 import handleForms from '../blocks-handler/handler-forms';
 import handleGetText from '../blocks-handler/handler-get-text';
 import handleEventClick from '../blocks-handler/handler-event-click';
 import handelTriggerEvent from '../blocks-handler/handler-trigger-event';
 import handleElementScroll from '../blocks-handler/handler-element-scroll';
 import EditForms from '@/components/newtab/workflow/edit/EditForms.vue';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 import EditTriggerEvent from '@/components/newtab/workflow/edit/EditTriggerEvent.vue';
 import EditScrollElement from '@/components/newtab/workflow/edit/EditScrollElement.vue';
 

+ 0 - 13
src/lib/prism.js

@@ -1,13 +0,0 @@
-import { highlight, languages } from 'prismjs/components/prism-core';
-import 'vue-prism-editor/dist/prismeditor.min.css';
-import 'prismjs/components/prism-clike';
-import 'prismjs/components/prism-javascript';
-import 'prismjs/components/prism-json';
-import 'prismjs/themes/prism-tomorrow.css';
-import '@/assets/css/prism-editor.css';
-
-export function highlighter(language) {
-  return function (code) {
-    return highlight(code, languages[language]);
-  };
-}

+ 5 - 6
src/newtab/pages/collections/[id].vue

@@ -218,12 +218,12 @@
     <p class="float-right clear-both" title="Characters limit">
       {{ collection.globalData.length }}/{{ (1e4).toLocaleString() }}
     </p>
-    <prism-editor
+    <shared-codemirror
       :model-value="collection.globalData"
-      :highlight="highlighter('json')"
-      class="h-full scroll mt-2"
+      lang="json"
+      class="mt-2"
       style="height: calc(100vh - 10rem)"
-      @update:modelValue="updateGlobalData"
+      @change="updateGlobalData"
     />
   </ui-modal>
 </template>
@@ -232,16 +232,15 @@ import { computed, shallowReactive, onMounted, watch } from 'vue';
 import { nanoid } from 'nanoid';
 import { useStore } from 'vuex';
 import { useRoute, useRouter } from 'vue-router';
-import { PrismEditor } from 'vue-prism-editor';
 import { useI18n } from 'vue-i18n';
 import Draggable from 'vuedraggable';
-import { highlighter } from '@/lib/prism';
 import { useDialog } from '@/composable/dialog';
 import { sendMessage } from '@/utils/message';
 import Log from '@/models/log';
 import Workflow from '@/models/workflow';
 import Collection from '@/models/collection';
 import SharedLogsTable from '@/components/newtab/shared/SharedLogsTable.vue';
+import SharedCodemirror from '@/components/newtab/shared/SharedCodemirror.vue';
 import SharedWorkflowState from '@/components/newtab/shared/SharedWorkflowState.vue';
 
 const { t } = useI18n();

+ 1 - 1
src/utils/shared.js

@@ -461,7 +461,7 @@ export const tasks = {
       contentType: 'json',
       timeout: 10000,
       headers: [{ name: '', value: '' }],
-      body: '{\n "key": "{{ dataColumns@0.key }}" \n}',
+      body: '{}',
     },
   },
   'loop-data': {

+ 278 - 10
yarn.lock

@@ -884,6 +884,243 @@
     "@babel/helper-validator-identifier" "^7.14.9"
     to-fast-properties "^2.0.0"
 
+"@codemirror/autocomplete@^0.19.0":
+  version "0.19.9"
+  resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-0.19.9.tgz#28b6600ad617bdc8dfeb0102a1df8cc61883d87c"
+  integrity sha512-Ph1LWHtFFqNUIqEVrws6I263ihe5TH+TRBPwxQ78j7st7Q67FDAmgKX6mNbUPh02dxfqQrc9qxlo5JIqKeiVdg==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/state" "^0.19.4"
+    "@codemirror/text" "^0.19.2"
+    "@codemirror/tooltip" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/common" "^0.15.0"
+
+"@codemirror/basic-setup@^0.19.1":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/basic-setup/-/basic-setup-0.19.1.tgz#17b27d02f15c628eb62a85d01e3e1b1958933eb4"
+  integrity sha512-gLjD7YgZU/we6BzS/ecCmD3viw83dsgv5ZUaSydYbYx9X4w4w9RqYnckcJ+0GDyHfNr5Jtfv2Z5ZtFQnBj0UDA==
+  dependencies:
+    "@codemirror/autocomplete" "^0.19.0"
+    "@codemirror/closebrackets" "^0.19.0"
+    "@codemirror/commands" "^0.19.0"
+    "@codemirror/comment" "^0.19.0"
+    "@codemirror/fold" "^0.19.0"
+    "@codemirror/gutter" "^0.19.0"
+    "@codemirror/highlight" "^0.19.0"
+    "@codemirror/history" "^0.19.0"
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/lint" "^0.19.0"
+    "@codemirror/matchbrackets" "^0.19.0"
+    "@codemirror/rectangular-selection" "^0.19.0"
+    "@codemirror/search" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.31"
+
+"@codemirror/closebrackets@^0.19.0":
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/closebrackets/-/closebrackets-0.19.0.tgz#69fdcee85779d638a00a42becd9f53a33a26d77f"
+  integrity sha512-dFWX5OEVYWRNtGaifSbwIAlymnRRjxWMiMbffbAjF7p0zfGHDbdGkiT56q3Xud63h5/tQdSo5dK1iyNTzHz5vg==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/text" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/commands@^0.19.0":
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-0.19.6.tgz#1568cf2c45a05864c1a4229575c5ac367ebbad9f"
+  integrity sha512-Mjc3ZfTifOn0h5499xI3MfCVIZvO2I0ochgzxfRtPOFwfXX/k7HTgnK0/KzuGDINyxUVeDaFCkf53TyyWjdxMQ==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/matchbrackets" "^0.19.0"
+    "@codemirror/state" "^0.19.2"
+    "@codemirror/text" "^0.19.0"
+    "@codemirror/view" "^0.19.22"
+    "@lezer/common" "^0.15.0"
+
+"@codemirror/comment@^0.19.0":
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/comment/-/comment-0.19.0.tgz#4f23497924e9346898c2e0123011acc535a0bea6"
+  integrity sha512-3hqAd0548fxqOBm4khFMcXVIivX8p0bSlbAuZJ6PNoUn/0wXhxkxowPp0FmFzU2+y37Z+ZQF5cRB5EREWPRIiQ==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/text" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/fold@^0.19.0":
+  version "0.19.2"
+  resolved "https://registry.yarnpkg.com/@codemirror/fold/-/fold-0.19.2.tgz#9d4e0c0f9f3bb2fcded7d82bea14ce39310e8e2a"
+  integrity sha512-FLi6RBhHPBnSbKZEu1S98z+VYSP5678cMdYVqhR58OWWTkEiLRVPeCTj8FhRKNL9B8Gx+lBQhGq3uwr3KtSs8w==
+  dependencies:
+    "@codemirror/gutter" "^0.19.0"
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.22"
+
+"@codemirror/gutter@^0.19.0", "@codemirror/gutter@^0.19.4":
+  version "0.19.9"
+  resolved "https://registry.yarnpkg.com/@codemirror/gutter/-/gutter-0.19.9.tgz#bbb69f4d49570d9c1b3f3df5d134980c516cd42b"
+  integrity sha512-PFrtmilahin1g6uL27aG5tM/rqR9DZzZYZsIrCXA5Uc2OFTFqx4owuhoU9hqfYxHp5ovfvBwQ+txFzqS4vog6Q==
+  dependencies:
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.23"
+
+"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6":
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.6.tgz#7f2e066f83f5649e8e0748a3abe0aaeaf64b8ac2"
+  integrity sha512-+eibu6on9quY8uN3xJ/n3rH+YIDLlpX7YulVmFvqAIz/ukRQ5tWaBmB7fMixHmnmRIRBRZgB8rNtonuMwZSAHQ==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/common" "^0.15.0"
+    style-mod "^4.0.0"
+
+"@codemirror/history@^0.19.0":
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/@codemirror/history/-/history-0.19.0.tgz#cc8095c927c9566f7b69fa404074edde4c54d39c"
+  integrity sha512-E0H+lncH66IMDhaND9jgkjE7s0dhYfjCPmS+Ig2Yes9I8+UIEecIdObj8c8HPCFGctGg3fxXqRAw2mdHl2Wouw==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/lang-javascript@^0.19.3":
+  version "0.19.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-0.19.3.tgz#281b3447d8b65d98311ebf25893ef5c30a11418b"
+  integrity sha512-2NE5z98Nz9Rv4OS5UtgehCSnyQjac+P85+evzy1D/4wllp/EPaHIEEtSP1daBvrLy49SdI/9vES3ZJu6rSv4/w==
+  dependencies:
+    "@codemirror/autocomplete" "^0.19.0"
+    "@codemirror/highlight" "^0.19.6"
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/lint" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/javascript" "^0.15.1"
+
+"@codemirror/lang-json@^0.19.1":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-0.19.1.tgz#616588d1422529965243c10af6c44ad0b9134fb0"
+  integrity sha512-66K5TT9HO0ODtpjY+3Ub6t3r0OB1d27P+Kl5oygk4tDavHUBpsyHTJRFw/CdeRM2VwjbpBfctGm/cTrSthFDZg==
+  dependencies:
+    "@codemirror/highlight" "^0.19.0"
+    "@codemirror/language" "^0.19.0"
+    "@lezer/json" "^0.15.0"
+
+"@codemirror/language@^0.19.0":
+  version "0.19.7"
+  resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-0.19.7.tgz#9eef8e827692d93a701b18db9d46a42be34ecca6"
+  integrity sha512-pNNUtYWMIMG0lUSKyUXJr8U0rFiCKsKFXbA2Oj17PC+S1FY99hV0z1vcntW67ekAIZw9DMEUQnLsKBuIbAUX7Q==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/text" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/common" "^0.15.5"
+    "@lezer/lr" "^0.15.0"
+
+"@codemirror/lint@^0.19.0":
+  version "0.19.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-0.19.3.tgz#84101d0967fea8df114a8f0f79965c22ccd3b3cc"
+  integrity sha512-+c39s05ybD2NjghxkPFsUbH/qBL0cdzKmtHbzUm0RVspeL2OiP7uHYJ6J5+Qr9RjMIPWzcqSauRqxfmCrctUfg==
+  dependencies:
+    "@codemirror/gutter" "^0.19.4"
+    "@codemirror/panel" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.1"
+    "@codemirror/state" "^0.19.4"
+    "@codemirror/tooltip" "^0.19.5"
+    "@codemirror/view" "^0.19.0"
+    crelt "^1.0.5"
+
+"@codemirror/matchbrackets@^0.19.0":
+  version "0.19.3"
+  resolved "https://registry.yarnpkg.com/@codemirror/matchbrackets/-/matchbrackets-0.19.3.tgz#1f430ada6fa21af2205280ff344ef57bb95dd3cb"
+  integrity sha512-ljkrBxaLgh8jesroUiBa57pdEwqJamxkukXrJpL9LdyFZVJaF+9TldhztRaMsMZO1XnCSSHQ9sg32iuHo7Sc2g==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/common" "^0.15.0"
+
+"@codemirror/panel@^0.19.0":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/panel/-/panel-0.19.1.tgz#bf77d27b962cf16357139e50864d0eb69d634441"
+  integrity sha512-sYeOCMA3KRYxZYJYn5PNlt9yNsjy3zTNTrbYSfVgjgL9QomIVgOJWPO5hZ2sTN8lufO6lw0vTBsIPL9MSidmBg==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/rangeset@^0.19.0", "@codemirror/rangeset@^0.19.1", "@codemirror/rangeset@^0.19.5":
+  version "0.19.5"
+  resolved "https://registry.yarnpkg.com/@codemirror/rangeset/-/rangeset-0.19.5.tgz#82dd2583324f5d5ffacf58922170bc5f3010e076"
+  integrity sha512-L3b+RIwIRKOJ3pJLOtpkxCUjGnxZKFyPb0CjYWKnVLuzEIaEExWWK7sp6rsejxOy8RjYzfCHlFhYB4UdQN7brw==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+
+"@codemirror/rectangular-selection@^0.19.0":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/rectangular-selection/-/rectangular-selection-0.19.1.tgz#5a88ece4fb68ce5682539497db8a64fc015aae63"
+  integrity sha512-9ElnqOg3mpZIWe0prPRd1SZ48Q9QB3bR8Aocq8UtjboJSUG8ABhRrbuTZMW/rMqpBPSjVpCe9xkCCkEQMYQVmw==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/text" "^0.19.4"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/search@^0.19.0":
+  version "0.19.5"
+  resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-0.19.5.tgz#cae88292a6b4a6d6e6a8b6218fe62355cf7f6055"
+  integrity sha512-9kbtCBpMDlzcj7AptMRBx9BZpC5wz+/tG8nIe4vdpOszP08ZY2AcxN5nlhCoUSZu+pd0b6fYiwjLXOf000rRpw==
+  dependencies:
+    "@codemirror/panel" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.3"
+    "@codemirror/text" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+    crelt "^1.0.5"
+
+"@codemirror/state@^0.19.0", "@codemirror/state@^0.19.2", "@codemirror/state@^0.19.3", "@codemirror/state@^0.19.4":
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-0.19.6.tgz#d631f041d39ce41b7891b099fca26cb1fdb9763e"
+  integrity sha512-sqIQZE9VqwQj7D4c2oz9mfLhlT1ElAzGB5lO1lE33BPyrdNy1cJyCIOecT4cn4VeJOFrnjOeu+IftZ3zqdFETw==
+  dependencies:
+    "@codemirror/text" "^0.19.0"
+
+"@codemirror/text@^0.19.0", "@codemirror/text@^0.19.2", "@codemirror/text@^0.19.4":
+  version "0.19.5"
+  resolved "https://registry.yarnpkg.com/@codemirror/text/-/text-0.19.5.tgz#75033af2476214e79eae22b81ada618815441c18"
+  integrity sha512-Syu5Xc7tZzeUAM/y4fETkT0zgGr48rDG+w4U38bPwSIUr+L9S/7w2wDE1WGNzjaZPz12F6gb1gxWiSTg9ocLow==
+
+"@codemirror/theme-one-dark@^0.19.1":
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/@codemirror/theme-one-dark/-/theme-one-dark-0.19.1.tgz#648b9cbe37186a2b7bd2a83fb483dc7aa18ce218"
+  integrity sha512-8gc4c2k2o/EhyHoWkghCxp5vyDT96JaFGtRy35PHwIom0LZdx7aU4AbDUnITvwiFB+0+i54VO+WQjBqgTyJvqg==
+  dependencies:
+    "@codemirror/highlight" "^0.19.0"
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/tooltip@^0.19.0", "@codemirror/tooltip@^0.19.5":
+  version "0.19.10"
+  resolved "https://registry.yarnpkg.com/@codemirror/tooltip/-/tooltip-0.19.10.tgz#c9ce5f8844ef28ab24d4a5adab0fc7ed85c44b4a"
+  integrity sha512-xqIhCHr+IYoamdNLvBnU/oDh92zPnsbT1zLaFtKTFi9GI9SxOfBhWY3jfMENlK0j1C9rk8+AvwpXblPGvY/O6w==
+  dependencies:
+    "@codemirror/state" "^0.19.0"
+    "@codemirror/view" "^0.19.0"
+
+"@codemirror/view@^0.19.0", "@codemirror/view@^0.19.22", "@codemirror/view@^0.19.23", "@codemirror/view@^0.19.31":
+  version "0.19.37"
+  resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-0.19.37.tgz#36fe17c774525c775af57e7dde2867b3b7cb400f"
+  integrity sha512-SLuLx9p0O1ZHXLehvl5MwSvUrQRcsNGemzTgJ0zRajmc3BBsNigI1PXxdo7tvBhO5DcAzRRBXoke9DZFUR6Qqg==
+  dependencies:
+    "@codemirror/rangeset" "^0.19.5"
+    "@codemirror/state" "^0.19.3"
+    "@codemirror/text" "^0.19.0"
+    style-mod "^4.0.0"
+    w3c-keyname "^2.2.4"
+
 "@discoveryjs/json-ext@^0.5.0":
   version "0.5.5"
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
@@ -991,6 +1228,32 @@
     json5 "^2.2.0"
     loader-utils "^2.0.0"
 
+"@lezer/common@^0.15.0", "@lezer/common@^0.15.5":
+  version "0.15.11"
+  resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.11.tgz#965b5067036305f12e8a3efc344076850be1d3a8"
+  integrity sha512-vv0nSdIaVCRcJ8rPuDdsrNVfBOYe/4Szr/LhF929XyDmBndLDuWiCCHooGlGlJfzELyO608AyDhVsuX/ZG36NA==
+
+"@lezer/javascript@^0.15.1":
+  version "0.15.2"
+  resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-0.15.2.tgz#50b70a02561b047947e050e0619b1aea7131dc5f"
+  integrity sha512-ytWvdJ1NAc0pfrNipGQs8otJVfjVibpIiFKH0fl99rKSA6cVlyQN/XTj/dEAQCfBfCBPAFdc30cuUe5CGZ0odA==
+  dependencies:
+    "@lezer/lr" "^0.15.0"
+
+"@lezer/json@^0.15.0":
+  version "0.15.0"
+  resolved "https://registry.yarnpkg.com/@lezer/json/-/json-0.15.0.tgz#b96c1161eb8514e05f4eaaec95c68376e76e539f"
+  integrity sha512-OsMjjBkTkeQ15iMCu5U1OiBubRC4V9Wm03zdIlUgNZ20aUPx5DWDRqUc5wG41JXVSj7Lxmo+idlFCfBBdxB8sw==
+  dependencies:
+    "@lezer/lr" "^0.15.0"
+
+"@lezer/lr@^0.15.0":
+  version "0.15.5"
+  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.5.tgz#4bce44169c441d9dda7be398f5202ea65c5f1138"
+  integrity sha512-DEcLyhdmBxD1foQe7RegLrSlfS/XaTMGLkO5evkzHWAQKh/JnFWp7j7iNB7s2EpxzRrBCh0U+W7JDCeFhv2mng==
+  dependencies:
+    "@lezer/common" "^0.15.0"
+
 "@medv/finder@^2.1.0":
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/@medv/finder/-/finder-2.1.0.tgz#5c53cdaac3b87057b9e5579ca1282b2397624016"
@@ -2295,6 +2558,11 @@ crc32-stream@^4.0.2:
     crc-32 "^1.2.0"
     readable-stream "^3.4.0"
 
+crelt@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
+  integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==
+
 cross-spawn@^6.0.0:
   version "6.0.5"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@@ -5448,11 +5716,6 @@ printj@~1.1.0:
   resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
   integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
 
-prismjs@^1.25.0:
-  version "1.25.0"
-  resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.25.0.tgz#6f822df1bdad965734b310b315a23315cf999756"
-  integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==
-
 process-nextick-args@~2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -6411,6 +6674,11 @@ style-loader@3.3.0:
   resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.0.tgz#d66ea95fc50b22f8b79b69a9e414760fcf58d8d8"
   integrity sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ==
 
+style-mod@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.0.tgz#97e7c2d68b592975f2ca7a63d0dd6fcacfe35a01"
+  integrity sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==
+
 supports-color@^5.3.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -6835,11 +7103,6 @@ vue-loader@16.8.1:
     hash-sum "^2.0.0"
     loader-utils "^2.0.0"
 
-vue-prism-editor@^2.0.0-alpha.2:
-  version "2.0.0-alpha.2"
-  resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz#aa53a88efaaed628027cbb282c2b1d37fc7c5c69"
-  integrity sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==
-
 vue-router@^4.0.11:
   version "4.0.11"
   resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.11.tgz#cd649a0941c635281763a20965b599643ddc68ed"
@@ -6872,6 +7135,11 @@ vuex@^4.0.2:
   dependencies:
     "@vue/devtools-api" "^6.0.0-beta.11"
 
+w3c-keyname@^2.2.4:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b"
+  integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==
+
 watchpack@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce"