Skip to content

Commit

Permalink
update: refactor linter to use codemirror guidance regarding stete up…
Browse files Browse the repository at this point in the history
…dates
  • Loading branch information
VsevolodX committed Sep 7, 2023
1 parent 75177d0 commit f53a922
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
21 changes: 14 additions & 7 deletions src/other/codemirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { fortran } from "@codemirror/legacy-modes/mode/fortran";
import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2";
import { shell } from "@codemirror/legacy-modes/mode/shell";
import { linter, lintGutter } from "@codemirror/lint";
import { ViewUpdate } from "@codemirror/view";
// eslint-disable-next-line import/no-extraneous-dependencies
import { ConsistencyChecks } from "@exabyte-io/code.js/src/types";
import CodeMirrorBase, { BasicSetupOptions } from "@uiw/react-codemirror";
import React from "react";

import { linterGenerator } from "./utils/exaxyz_linter";
import { ChecksAnnotation, checksStateField, exaxyzLinter } from "./utils/exaxyz_linter";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const LANGUAGES_MAP: Record<string, any> = {
python: [python()],
Expand Down Expand Up @@ -55,13 +57,11 @@ class CodeMirror extends React.Component<CodeMirrorProps, CodeMirrorState> {
handleContentChange(newContent: string, viewUpdate: { origin: string }) {
const { isLoaded, isEditing } = this.state;
const { updateContent, updateOnFirstLoad = true } = this.props;
// kludge for the way state management is handled in web-app

if (!isLoaded && !updateOnFirstLoad && viewUpdate.origin === "setValue") {
this.setState({ isLoaded: true });
return;
}
// update content only if component is focused
// Otherwise content is being marked as edited when selecting a flavor in workflow designer!
if (isEditing && updateContent) updateContent(newContent);
}

Expand All @@ -70,15 +70,14 @@ class CodeMirror extends React.Component<CodeMirrorProps, CodeMirrorState> {
const baseExtensions = LANGUAGES_MAP[language] || LANGUAGES_MAP.fortran;

if (language === "exaxyz") {
const { checks } = this.props;
return [...baseExtensions, linter(linterGenerator(checks))];
return [...baseExtensions, checksStateField, linter(exaxyzLinter)];
}

return baseExtensions;
}

render() {
const { content = "", options = {}, language, completions } = this.props;
const { content = "", options = {}, language, completions, checks } = this.props;
const completionExtension = autocompletion({ override: [completions] });

const { theme, onFocus, onBlur } = this.props;
Expand All @@ -89,6 +88,14 @@ class CodeMirror extends React.Component<CodeMirrorProps, CodeMirrorState> {
onChange={(editor: string, viewUpdate: { origin: string }) => {
this.handleContentChange(editor, viewUpdate);
}}
onUpdate={(viewUpdate: ViewUpdate) => {
if (checks && checks.keys.length > 0) {
console.log("viewUpdate", viewUpdate);
viewUpdate.view.dispatch({
annotations: [ChecksAnnotation.of({ checks })],
});
}
}}
onFocus={() => {
if (onFocus) onFocus();
this.setState({ isEditing: true });
Expand Down
46 changes: 33 additions & 13 deletions src/other/codemirror/utils/exaxyz_linter.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
import { Diagnostic } from "@codemirror/lint";
import { Annotation, StateField } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
// eslint-disable-next-line import/no-extraneous-dependencies
import { ConsistencyChecks } from "@exabyte-io/code.js/src/types";
import _ from "underscore";

const linterGenerator = (checks: ConsistencyChecks | undefined) => {
return (view: EditorView): Diagnostic[] => {
const { doc } = view.state;
if (!checks || !doc) return [];
export const ChecksAnnotation = Annotation.define<{ checks: ConsistencyChecks }>();

const warnings = checks.messages.map((check) => {
export const checksStateField = StateField.define({
create() {
return [];
}, // Initializes with an empty array
// @ts-ignore
update(value, tr) {
if (tr.annotation(ChecksAnnotation)) {
// @ts-ignore
return tr.annotation(ChecksAnnotation).checks;
}
return value;
},
});
const exaxyzLinter = (view: EditorView): Diagnostic[] => {
const checks: ConsistencyChecks | undefined = view.state.field(checksStateField) as
| ConsistencyChecks
| undefined;

if (!checks) return [];
if (Object.keys(checks).length === 0) return [];

return checks.messages
.map((check) => {
const keyFragments = check.key.split(".");
const atomIdStr = _.last(keyFragments);
if (!atomIdStr) return null;

const atomId = parseInt(atomIdStr, 10);
const lineNumber = atomId + 1; // codemirror counts from 1
const lineNumber = atomId + 1;
return {
message: check.message,
severity: check.severity,
from: doc.line(lineNumber).from,
to: doc.line(lineNumber).to,
from: view.state.doc.line(lineNumber).from,
to: view.state.doc.line(lineNumber).to,
};
});

return warnings.filter(Boolean) as Diagnostic[];
};
})
.filter(Boolean) as Diagnostic[];
};

export { linterGenerator };
export { exaxyzLinter };

0 comments on commit f53a922

Please sign in to comment.