feat: fix reactivity issues in graphql

This commit is contained in:
Andrew Bastin
2021-11-12 17:54:34 +05:30
parent 103ef8ee0d
commit ca40cc5271

View File

@@ -4,19 +4,23 @@ import {
EditorState, EditorState,
Compartment, Compartment,
EditorSelection, EditorSelection,
TransactionSpec,
} from "@codemirror/state" } from "@codemirror/state"
import { Language, LanguageSupport } from "@codemirror/language" import { Language, LanguageSupport } from "@codemirror/language"
import { defaultKeymap } from "@codemirror/commands" import { defaultKeymap } from "@codemirror/commands"
import { Completion, autocompletion } from "@codemirror/autocomplete" import { Completion, autocompletion } from "@codemirror/autocomplete"
import { linter } from "@codemirror/lint" 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 { javascriptLanguage } from "@codemirror/lang-javascript"
import { jsonLanguage } from "@codemirror/lang-json" import { jsonLanguage } from "@codemirror/lang-json"
import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql" import { GQLLanguage } from "@hoppscotch/codemirror-lang-graphql"
import { onBeforeUnmount } from "@vue/runtime-dom"
import { pipe } from "fp-ts/function" import { pipe } from "fp-ts/function"
import * as O from "fp-ts/Option" import * as O from "fp-ts/Option"
import { isJSONContentType } from "../utils/contenttypes" import { isJSONContentType } from "../utils/contenttypes"
@@ -140,105 +144,101 @@ export function useCodemirror(
line: 0, line: 0,
ch: 0, ch: 0,
}) })
const cachedValue = ref(value.value) 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,
}
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
}
}
}
),
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 view = ref<EditorView>()
const dispatch = (t: TransactionSpec) => const initView = (el: any) => {
view.value ? view.value.dispatch(t) : state.update(t) 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
}
}
}
),
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(() => { onMounted(() => {
view.value = new EditorView({ if (el.value) {
state, if (!view.value) initView(el.value)
parent: el.value, }
}) })
watch(el, () => {
if (el.value) {
if (!view.value) initView(el.value)
} else {
view.value?.destroy()
view.value = undefined
}
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (view.value) view.value.destroy() view.value?.destroy()
}) })
watch(cursor, (newPos) => { watch(value, (newVal) => {
if ( if (cachedValue.value !== newVal) {
cachedCursor.value.line !== newPos.line || view.value?.dispatch({
cachedCursor.value.ch !== newPos.ch changes: {
) { from: 0,
const line = state.doc.line(newPos.line + 1) to: view.value.state.doc.length,
const selUpdate = EditorSelection.cursor(line.from + newPos.ch - 1) insert: newVal,
},
view.value?.focus()
dispatch({
scrollIntoView: true,
selection: selUpdate,
effects: EditorView.scrollTo.of(selUpdate),
}) })
} }
}) })
watch(
() => options.extendedEditorConfig.lineWrapping,
(newMode) => {
dispatch({
effects: lineWrapping.reconfigure(
newMode ? [EditorView.lineWrapping] : []
),
})
}
)
watch( watch(
() => [ () => [
options.extendedEditorConfig.mode, options.extendedEditorConfig.mode,
@@ -246,7 +246,7 @@ export function useCodemirror(
options.completer, options.completer,
], ],
() => { () => {
dispatch({ view.value?.dispatch({
effects: language.reconfigure( effects: language.reconfigure(
getEditorLanguage( getEditorLanguage(
(options.extendedEditorConfig.mode as any) ?? "", (options.extendedEditorConfig.mode as any) ?? "",
@@ -258,29 +258,34 @@ export function useCodemirror(
} }
) )
watch(el, (newEl) => { watch(
() => options.extendedEditorConfig.lineWrapping,
(newMode) => {
view.value?.dispatch({
effects: lineWrapping.reconfigure(
newMode ? [EditorView.lineWrapping] : []
),
})
}
)
watch(cursor, (newPos) => {
if (view.value) { if (view.value) {
view.value.destroy() if (
view.value = undefined 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)
if (newEl) { view.value?.focus()
view.value = new EditorView({
state,
parent: newEl,
})
}
})
watch(value, (newVal) => { view.value.dispatch({
if (cachedValue.value !== newVal) { scrollIntoView: true,
dispatch({ selection: selUpdate,
changes: { effects: EditorView.scrollTo.of(selUpdate),
from: 0, })
to: state.doc.length, }
insert: newVal,
},
})
} }
}) })