瀏覽代碼

feat: cm 6 json mode + readonly + cursor update

Andrew Bastin 4 年之前
父節點
當前提交
7c65da4cf3

+ 1 - 1
packages/hoppscotch-app/components/lenses/renderers/JSONLensRenderer.vue

@@ -145,7 +145,7 @@
 
 <script setup lang="ts">
 import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api"
-import { useCodemirror } from "~/helpers/editor/codemirror"
+import { useNewCodemirror as useCodemirror } from "~/helpers/editor/codemirror"
 import { copyToClipboard } from "~/helpers/utils/clipboard"
 import "codemirror/mode/javascript/javascript"
 import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"

+ 58 - 6
packages/hoppscotch-app/helpers/editor/codemirror.ts

@@ -27,12 +27,20 @@ import "codemirror/addon/selection/active-line"
 
 import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api"
 
-import { EditorState, Compartment, StateField } from "@codemirror/state"
+import {
+  EditorState,
+  Compartment,
+  StateField,
+  EditorSelection,
+  TransactionSpec,
+} from "@codemirror/state"
 import { EditorView, keymap, ViewPlugin, ViewUpdate } from "@codemirror/view"
 import { defaultKeymap } from "@codemirror/commands"
 import { basicSetup } from "@codemirror/basic-setup"
 import { javascript } from "@codemirror/lang-javascript"
+import { json } from "@codemirror/lang-json"
 import { onBeforeUnmount } from "@vue/runtime-dom"
+import { isJSONContentType } from "../utils/contenttypes"
 import { Completer } from "./completion"
 import { LinterDefinition } from "./linting/linter"
 
@@ -222,7 +230,9 @@ export function useCodemirror(
 }
 
 const getEditorLanguage = (mode: string) => {
-  if (mode === "application/javascript") {
+  if (isJSONContentType(mode)) {
+    return json()
+  } else if (mode === "application/javascript") {
     return javascript()
   } else {
     return StateField.define({
@@ -241,6 +251,10 @@ export function useNewCodemirror(
 ): { cursor: Ref<{ line: number; ch: number }> } {
   const language = new Compartment()
 
+  const cachedCursor = ref({
+    line: 0,
+    ch: 0,
+  })
   const cursor = ref({
     line: 0,
     ch: 0,
@@ -259,14 +273,19 @@ export function useNewCodemirror(
 
               const line = update.state.doc.lineAt(cursorPos)
 
+              cachedCursor.value = {
+                line: line.number - 1,
+                ch: cursorPos - line.from,
+              }
+
               cursor.value = {
-                line: line.number,
-                ch: cursorPos - line.from + 1,
+                line: cachedCursor.value.line,
+                ch: cachedCursor.value.ch,
               }
             }
-
             if (update.docChanged) {
               // Expensive on big files ?
+              console.log("doc change")
               cachedValue.value = update.state.doc
                 .toJSON()
                 .join(update.state.lineBreak)
@@ -275,6 +294,7 @@ export function useNewCodemirror(
           }
         }
       ),
+      EditorState.changeFilter.of(() => !options.extendedEditorConfig.readOnly),
       language.of(
         getEditorLanguage((options.extendedEditorConfig.mode as any) ?? "")
       ),
@@ -284,6 +304,9 @@ export function useNewCodemirror(
 
   const view = ref<EditorView>()
 
+  const dispatch = (t: TransactionSpec) =>
+    view.value ? view.value.dispatch(t) : state.update(t)
+
   onMounted(() => {
     view.value = new EditorView({
       state,
@@ -295,6 +318,35 @@ export function useNewCodemirror(
     if (view.value) view.value.destroy()
   })
 
+  watch(cursor, (newPos) => {
+    if (
+      cachedCursor.value.line !== newPos.line ||
+      cachedCursor.value.ch !== newPos.ch
+    ) {
+      const line = state.doc.line(newPos.line + 1)
+      const selUpdate = EditorSelection.cursor(line.from + newPos.ch - 1)
+
+      view.value?.focus()
+
+      dispatch({
+        scrollIntoView: true,
+        selection: selUpdate,
+        effects: EditorView.scrollTo.of(selUpdate),
+      })
+    }
+  })
+
+  watch(
+    () => options.extendedEditorConfig.mode,
+    (newMode) => {
+      dispatch({
+        effects: language.reconfigure(
+          getEditorLanguage((newMode as any) ?? "")
+        ),
+      })
+    }
+  )
+
   watch(el, (newEl) => {
     if (view.value) {
       view.value.destroy()
@@ -311,7 +363,7 @@ export function useNewCodemirror(
 
   watch(value, (newVal) => {
     if (cachedValue.value !== newVal) {
-      state.update({
+      dispatch({
         changes: {
           from: 0,
           to: state.doc.length,

+ 1 - 0
packages/hoppscotch-app/package.json

@@ -38,6 +38,7 @@
     "@codemirror/commands": "^0.19.5",
     "@codemirror/gutter": "^0.19.4",
     "@codemirror/lang-javascript": "^0.19.2",
+    "@codemirror/lang-json": "^0.19.1",
     "@codemirror/language": "^0.19.3",
     "@codemirror/state": "^0.19.3",
     "@codemirror/text": "^0.19.5",

+ 19 - 3
pnpm-lock.yaml

@@ -24,6 +24,7 @@ importers:
       '@codemirror/commands': ^0.19.5
       '@codemirror/gutter': ^0.19.4
       '@codemirror/lang-javascript': ^0.19.2
+      '@codemirror/lang-json': ^0.19.1
       '@codemirror/language': ^0.19.3
       '@codemirror/state': ^0.19.3
       '@codemirror/text': ^0.19.5
@@ -137,6 +138,7 @@ importers:
       '@codemirror/commands': 0.19.5
       '@codemirror/gutter': 0.19.4
       '@codemirror/lang-javascript': 0.19.2
+      '@codemirror/lang-json': 0.19.1
       '@codemirror/language': 0.19.3
       '@codemirror/state': 0.19.3
       '@codemirror/text': 0.19.5
@@ -1817,6 +1819,14 @@ packages:
       '@lezer/javascript': 0.15.0
     dev: false
 
+  /@codemirror/lang-json/0.19.1:
+    resolution: {integrity: sha512-66K5TT9HO0ODtpjY+3Ub6t3r0OB1d27P+Kl5oygk4tDavHUBpsyHTJRFw/CdeRM2VwjbpBfctGm/cTrSthFDZg==}
+    dependencies:
+      '@codemirror/highlight': 0.19.6
+      '@codemirror/language': 0.19.3
+      '@lezer/json': 0.15.0
+    dev: false
+
   /@codemirror/language/0.19.3:
     resolution: {integrity: sha512-6vjkRYHRJg/z9wdAk75nU2fQwCJBsh2HpkIjKXIHfzISSgLt5qSDxVhPd8Uu8PD5WMmFFP8tX7I9kdIt873o0A==}
     dependencies:
@@ -3690,6 +3700,12 @@ packages:
       '@lezer/lr': 0.15.4
     dev: false
 
+  /@lezer/json/0.15.0:
+    resolution: {integrity: sha512-OsMjjBkTkeQ15iMCu5U1OiBubRC4V9Wm03zdIlUgNZ20aUPx5DWDRqUc5wG41JXVSj7Lxmo+idlFCfBBdxB8sw==}
+    dependencies:
+      '@lezer/lr': 0.15.4
+    dev: false
+
   /@lezer/lr/0.15.4:
     resolution: {integrity: sha512-vwgG80sihEGJn6wJp6VijXrnzVai/KPva/OzYKaWvIx0IiXKjoMQ8UAwcgpSBwfS4Fbz3IKOX/cCNXU3r1FvpQ==}
     dependencies:
@@ -3896,8 +3912,8 @@ packages:
       ufo: 0.7.9
     dev: false
 
-  /@nuxt/kit-edge/3.0.0-27267163.9b8d44d:
-    resolution: {integrity: sha512-Skw7Es5w+tCDX0K0oB/aX6OzyZ8zEFq3aUasv5rGjQlztAv/BtvBHEK1kprP2nR7xiXKMpyUphMOy3qFtHamfg==}
+  /@nuxt/kit-edge/3.0.0-27267816.6bd7186:
+    resolution: {integrity: sha512-OCinQR1TBeZmgU61of/YM55JvY+3emO6D4BwfTNYe8KwqIpynYcrZJxlxAYRYZKzqfZhtqLnD1B8DJ1f2b6thQ==}
     engines: {node: ^14.16.0 || ^16.11.0 || ^17.0.0}
     dependencies:
       consola: 2.15.3
@@ -14020,7 +14036,7 @@ packages:
   /nuxt-windicss/2.0.11:
     resolution: {integrity: sha512-/vAEmKLq1Iomuj4lz751dsoXdlGVAoiEGSh3JVxuZJMkqc/yrHTQrNhtMaOQzx5heuVsQ+E2bIF+Q/tfxicOFQ==}
     dependencies:
-      '@nuxt/kit': /@nuxt/kit-edge/3.0.0-27267163.9b8d44d
+      '@nuxt/kit': /@nuxt/kit-edge/3.0.0-27267816.6bd7186
       defu: 5.0.0
       h3: 0.3.3
       listhen: 0.2.5