From 52765568379d6c2620275ad5715cd3d9ca1c867b Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 1 Sep 2021 16:41:14 +0530 Subject: [PATCH] feat: codemirror linting system --- components/smart/CodeMirror.vue | 24 +++++++++++++++++------- helpers/editor/codemirror.ts | 19 +++++++++++++++++-- helpers/editor/linting/linter.ts | 7 +++++++ helpers/editor/utils.ts | 23 +++++++++++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 helpers/editor/linting/linter.ts create mode 100644 helpers/editor/utils.ts diff --git a/components/smart/CodeMirror.vue b/components/smart/CodeMirror.vue index 6068778c8..3cf602030 100644 --- a/components/smart/CodeMirror.vue +++ b/components/smart/CodeMirror.vue @@ -7,13 +7,20 @@ import "codemirror/mode/javascript/javascript" import { ref, watch } from "@nuxtjs/composition-api" import { useCodemirror } from "~/helpers/editor/codemirror" +import { LinterDefinition } from "~/helpers/editor/linting/linter" -const props = defineProps<{ - value: string - mode: string - placeholder: string - wrap: boolean -}>() +const props = withDefaults( + defineProps<{ + value: string + mode: string + placeholder: string + wrap: boolean + linter: LinterDefinition | null + }>(), + { + linter: null as any, + } +) const emit = defineEmits<{ (e: "input", value: string): void @@ -30,7 +37,10 @@ watch(value, (val) => emit("input", val)) const editor = ref(null) useCodemirror(editor, value, { - mode: props.mode, + extendedEditorConfig: { + mode: props.mode, + }, + linter: props.linter, }) diff --git a/helpers/editor/codemirror.ts b/helpers/editor/codemirror.ts index 9a282979f..49969267f 100644 --- a/helpers/editor/codemirror.ts +++ b/helpers/editor/codemirror.ts @@ -3,6 +3,7 @@ import CodeMirror from "codemirror" import "codemirror/theme/juejin.css" import "codemirror/lib/codemirror.css" +import "codemirror/addon/lint/lint.css" import "codemirror/addon/fold/foldgutter.css" import "codemirror/addon/fold/foldgutter" @@ -10,11 +11,18 @@ import "codemirror/addon/fold/brace-fold" import "codemirror/addon/fold/comment-fold" import "codemirror/addon/fold/indent-fold" import "codemirror/addon/display/autorefresh" +import "codemirror/addon/lint/lint" import { watch, onMounted, ref, Ref } from "@nuxtjs/composition-api" +import { LinterDefinition } from "./linting/linter" const DEFAULT_THEME = "juejin" +type CodeMirrorOptions = { + extendedEditorConfig: CodeMirror.EditorConfiguration + linter: LinterDefinition | null +} + const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { theme: DEFAULT_THEME, autoRefresh: true, @@ -35,15 +43,22 @@ const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = { export function useCodemirror( el: Ref, value: Ref, - options: CodeMirror.EditorConfiguration + options: CodeMirrorOptions ) { const cm = ref(null) // Boot-up CodeMirror, set the value and listeners onMounted(() => { - cm.value = CodeMirror(el.value!, { ...DEFAULT_EDITOR_CONFIG, ...options }) + cm.value = CodeMirror(el.value!, { + ...DEFAULT_EDITOR_CONFIG, + ...options.extendedEditorConfig, + }) cm.value.setValue(value.value) + if (options.linter) { + cm.value.setOption("lint", options.linter) + } + cm.value.on("change", (instance) => { // External update propagation (via watchers) should be ignored if (instance.getValue() !== value.value) { diff --git a/helpers/editor/linting/linter.ts b/helpers/editor/linting/linter.ts new file mode 100644 index 000000000..704270cbe --- /dev/null +++ b/helpers/editor/linting/linter.ts @@ -0,0 +1,7 @@ +export type LinterResult = { + message: string + severity: "warning" | "error" + from: { line: number; ch: number } + to: { line: number; ch: number } +} +export type LinterDefinition = (text: string) => Promise diff --git a/helpers/editor/utils.ts b/helpers/editor/utils.ts new file mode 100644 index 000000000..18b311765 --- /dev/null +++ b/helpers/editor/utils.ts @@ -0,0 +1,23 @@ +export function convertIndexToLineCh( + text: string, + i: number +): { line: number; ch: number } { + const lines = text.split("/n") + + let line = 0 + let counter = 0 + + while (line < lines.length) { + if (i > lines[line].length + counter) { + counter += lines[line].length + 1 + line++ + } else { + return { + line: line + 1, + ch: i - counter + 1, + } + } + } + + throw new Error("Invalid input") +}