Browse Source

feat: fix reactivity issues in graphql

Andrew Bastin 4 years ago
parent
commit
ca40cc5271
1 changed files with 112 additions and 107 deletions
  1. 112 107
      packages/hoppscotch-app/helpers/editor/codemirror.ts

+ 112 - 107
packages/hoppscotch-app/helpers/editor/codemirror.ts

@@ -4,19 +4,23 @@ import {
   EditorState,
   Compartment,
   EditorSelection,
-  TransactionSpec,
 } from "@codemirror/state"
 import { Language, LanguageSupport } from "@codemirror/language"
 import { defaultKeymap } from "@codemirror/commands"
 import { Completion, autocompletion } from "@codemirror/autocomplete"
 import { linter } from "@codemirror/lint"
 
-import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api"
+import {
+  watch,
+  ref,
+  Ref,
+  onMounted,
+  onBeforeUnmount,
+} from "@nuxtjs/composition-api"
 
 import { javascriptLanguage } from "@codemirror/lang-javascript"
 import { jsonLanguage } from "@codemirror/lang-json"
 import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql"
-import { onBeforeUnmount } from "@vue/runtime-dom"
 import { pipe } from "fp-ts/function"
 import * as O from "fp-ts/Option"
 import { isJSONContentType } from "../utils/contenttypes"
@@ -140,104 +144,100 @@ export function useCodemirror(
     line: 0,
     ch: 0,
   })
+
   const cachedValue = ref(value.value)
 
-  const state = EditorState.create({
-    doc: value.value,
-    extensions: [
-      basicSetup,
-      baseTheme,
-      baseHighlightStyle,
-      ViewPlugin.fromClass(
-        class {
-          update(update: ViewUpdate) {
-            if (update.selectionSet) {
-              const cursorPos = update.state.selection.main.head
-
-              const line = update.state.doc.lineAt(cursorPos)
-
-              cachedCursor.value = {
-                line: line.number - 1,
-                ch: cursorPos - line.from,
-              }
+  const view = ref<EditorView>()
 
-              cursor.value = {
-                line: cachedCursor.value.line,
-                ch: cachedCursor.value.ch,
+  const initView = (el: any) => {
+    view.value = new EditorView({
+      parent: el,
+      state: EditorState.create({
+        doc: value.value,
+        extensions: [
+          basicSetup,
+          baseTheme,
+          baseHighlightStyle,
+          ViewPlugin.fromClass(
+            class {
+              update(update: ViewUpdate) {
+                if (update.selectionSet) {
+                  const cursorPos = update.state.selection.main.head
+
+                  const line = update.state.doc.lineAt(cursorPos)
+
+                  cachedCursor.value = {
+                    line: line.number - 1,
+                    ch: cursorPos - line.from,
+                  }
+
+                  cursor.value = {
+                    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)
+                  value.value = cachedValue.value
+                }
               }
             }
-            if (update.docChanged) {
-              // Expensive on big files ?
-              console.log("doc change")
-              cachedValue.value = update.state.doc
-                .toJSON()
-                .join(update.state.lineBreak)
-              value.value = cachedValue.value
-            }
-          }
-        }
-      ),
-      EditorState.changeFilter.of(() => !options.extendedEditorConfig.readOnly),
-      language.of(
-        getEditorLanguage(
-          options.extendedEditorConfig.mode ?? "",
-          options.linter ?? undefined,
-          options.completer ?? undefined
-        )
-      ),
-      lineWrapping.of(
-        options.extendedEditorConfig.lineWrapping
-          ? [EditorView.lineWrapping]
-          : []
-      ),
-      keymap.of(defaultKeymap),
-    ],
-  })
-
-  const view = ref<EditorView>()
-
-  const dispatch = (t: TransactionSpec) =>
-    view.value ? view.value.dispatch(t) : state.update(t)
+          ),
+          EditorState.changeFilter.of(
+            () => !options.extendedEditorConfig.readOnly
+          ),
+          language.of(
+            getEditorLanguage(
+              options.extendedEditorConfig.mode ?? "",
+              options.linter ?? undefined,
+              options.completer ?? undefined
+            )
+          ),
+          lineWrapping.of(
+            options.extendedEditorConfig.lineWrapping
+              ? [EditorView.lineWrapping]
+              : []
+          ),
+          keymap.of(defaultKeymap),
+        ],
+      }),
+    })
+  }
 
   onMounted(() => {
-    view.value = new EditorView({
-      state,
-      parent: el.value,
-    })
+    if (el.value) {
+      if (!view.value) initView(el.value)
+    }
   })
 
-  onBeforeUnmount(() => {
-    if (view.value) view.value.destroy()
+  watch(el, () => {
+    if (el.value) {
+      if (!view.value) initView(el.value)
+    } else {
+      view.value?.destroy()
+      view.value = undefined
+    }
   })
 
-  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),
-      })
-    }
+  onBeforeUnmount(() => {
+    view.value?.destroy()
   })
 
-  watch(
-    () => options.extendedEditorConfig.lineWrapping,
-    (newMode) => {
-      dispatch({
-        effects: lineWrapping.reconfigure(
-          newMode ? [EditorView.lineWrapping] : []
-        ),
+  watch(value, (newVal) => {
+    if (cachedValue.value !== newVal) {
+      view.value?.dispatch({
+        changes: {
+          from: 0,
+          to: view.value.state.doc.length,
+          insert: newVal,
+        },
       })
     }
-  )
+  })
 
   watch(
     () => [
@@ -246,7 +246,7 @@ export function useCodemirror(
       options.completer,
     ],
     () => {
-      dispatch({
+      view.value?.dispatch({
         effects: language.reconfigure(
           getEditorLanguage(
             (options.extendedEditorConfig.mode as any) ?? "",
@@ -258,29 +258,34 @@ export function useCodemirror(
     }
   )
 
-  watch(el, (newEl) => {
-    if (view.value) {
-      view.value.destroy()
-      view.value = undefined
-    }
-
-    if (newEl) {
-      view.value = new EditorView({
-        state,
-        parent: newEl,
+  watch(
+    () => options.extendedEditorConfig.lineWrapping,
+    (newMode) => {
+      view.value?.dispatch({
+        effects: lineWrapping.reconfigure(
+          newMode ? [EditorView.lineWrapping] : []
+        ),
       })
     }
-  })
+  )
 
-  watch(value, (newVal) => {
-    if (cachedValue.value !== newVal) {
-      dispatch({
-        changes: {
-          from: 0,
-          to: state.doc.length,
-          insert: newVal,
-        },
-      })
+  watch(cursor, (newPos) => {
+    if (view.value) {
+      if (
+        cachedCursor.value.line !== newPos.line ||
+        cachedCursor.value.ch !== newPos.ch
+      ) {
+        const line = view.value.state.doc.line(newPos.line + 1)
+        const selUpdate = EditorSelection.cursor(line.from + newPos.ch - 1)
+
+        view.value?.focus()
+
+        view.value.dispatch({
+          scrollIntoView: true,
+          selection: selUpdate,
+          effects: EditorView.scrollTo.of(selUpdate),
+        })
+      }
     }
   })