uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.69k stars 135 forks source link

Questions on Merge #508

Closed kimfucious closed 1 year ago

kimfucious commented 1 year ago

I'm trying to compare two markdown files, using CodeMirrorMerge.

In brief, I'm comparing text stored in local storage with text in React state, in the case when the browser is closed before an item is saved.

The documentation is a bit sparse, so I need a bit of help. Any helpful advice would be most appreciated.

Using the documentation here, I've managed to produce what's shown in this screenshot: image In this example the text is a single "paragraph" of around 60 words. In practice, there will be many more paragraphs with more or less words.

The "original" text is on the left, and the "modified" is on the right. I want to potentially merge changes that are in modified to the original.

Question 1: Is there any way to wrap the text? It's near impossible to compare long lines (i.e. paragraphs) on a single line.

With CodeMirror from @uiw/react-codemirror, I can wrap text with the following code:

extensions={[
    vim({ status: true }),
    markdown(),
    EditorView.lineWrapping, // <= right here
    EditorView.contentAttributes.of({ spellcheck: "true" }),
]}

The wrapping looks like this: image

I can't see a way to do this with CodeMirrorMerge.

Question 2: Is there a way to adjust the theme?

Question 3: What are those vertical white lines?

Question 4: How to you perform merges? In the screen shot below (from here), there's a little arrow, that when clicked on performs the merge. I can't seem to make that arrow show with what I've tried.

image Question 5: When a merge is actually performed, how can I get that value, so as to save it somewhere?

Here's the code for the component as it stands.

import { EditorState } from "@codemirror/state";
import { EditorView } from "codemirror";
import { Scene } from "../../../types";
import { useMemo } from "react";
import CodeMirrorMerge from "react-codemirror-merge";
import config from "../../../config/config.json";

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;

interface Props {
    originalScene: Scene | undefined;
}
// https://uiwjs.github.io/react-codemirror/#/merge/onchange
export default function MergeEditor({ originalScene }: Props) {
    const { original, modified } = useMemo(() => {
        let modified = "";
        const original = originalScene?.text;
        const draftInStorage = localStorage.getItem(config.DRAFT_SCENE_KEY);
        if (draftInStorage) {
            modified = JSON.parse(draftInStorage).text;
        }
        return { original, modified };
    }, [originalScene]);
    return (
        <CodeMirrorMerge orientation="a-b" highlightChanges>
            <div style={{ maxWidth: 300 }}>
                <Original value={original} />
            </div>
            <div style={{ maxWidth: 300 }}>
                <Modified
                    value={modified}
                    extensions={[
                        EditorView.editable.of(false),
                        EditorState.readOnly.of(true),
                    ]}
                />
            </div>
        </CodeMirrorMerge>
    );
}
jaywcjlove commented 1 year ago

@kimfucious https://codesandbox.io/embed/react-codemirror-example-codemirror-6-https-github-com-uiwjs-react-codemirror-issues-508-0l7067?fontsize=14&hidenavigation=1&theme=dark

import React, { useState } from "react";
import CodeMirrorMerge from "react-codemirror-merge";

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;
let doc = `one
two
three
four
five`;

export default function App() {
  const [value, setValue] = useState();
  const onChange = React.useCallback((val) => {
    console.log("value:", val);
    setValue(val);
  }, []);
  return (
    <div>
      <CodeMirrorMerge revertControls="a-to-b">
        <Original value={doc} onChange={onChange} />
        <Modified
          value={doc.replace(/t/g, "T") + "Six"}
          onChange={(val) => {
            console.log("value:222:", val);
          }}
        />
      </CodeMirrorMerge>
      <pre>{value}</pre>
    </div>
  );
}
kimfucious commented 1 year ago

Hi @jaywcjlove, thanks for the response.

I believe what you're showing me is how to get the change value from the merge.

If so, that answers Question 5, but the rest are still outstanding.

kimfucious commented 1 year ago

Hi @jaywcjlove,

I take it you have nothing more to add to this issue.

Is that correct?

jaywcjlove commented 1 year ago

@kimfucious Both Original and Modified have onChange. I don't know what you need to save?

You can listen for changes and then save the text you want.

kimfucious commented 1 year ago

Hi @jaywcjlove,

Thanks for the follow up.

I still have outstanding questions (1-4) in my original post.

kimfucious commented 1 year ago

Hi @jaywcjlove,

Thanks for your patience as I work through this.

I've got Questions 4 and 5 handled, with the below.

I needed to add revertControls="b-to-a" to show the little arrow.

import { EditorState } from "@codemirror/state";
import { EditorView } from "codemirror";
import { Scene } from "../../../types";
import CodeMirrorMerge from "react-codemirror-merge";

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;

interface Props {
    changedText: string;
    setChangedText: (s: string) => void;
    originalScene: Scene | undefined;
    original: string | undefined;
    modified: string | undefined;
}
// https://uiwjs.github.io/react-codemirror/#/merge/onchange
export default function MergeEditor({
    original,
    modified,
    changedText,
    setChangedText,
}: Props) {
    function handleChange(str: string) {
        setChangedText(str);
    }

    return (
        <div className="container d-flex flex-column align-items-center w-100">
            <CodeMirrorMerge
                className="w-100"
                highlightChanges
                orientation="a-b"
                revertControls="b-to-a"
            >
                <Original
                    value={original}
                    onChange={(str) => handleChange(str)}
                />
                <Modified
                    value={modified}
                    extensions={[
                        EditorView.editable.of(false),
                        EditorState.readOnly.of(true),
                    ]}
                />
            </CodeMirrorMerge>

            <div className="d-flex justify-content-between w-100">
                <small>Current Scene</small>
                <small>Unsaved Changes</small>
            </div>
            {changedText !== modified && (
                <div className="d-flex justify-content-center mt-3 w-100">
                    You can merge the unsaved changes by clicking the little
                    arrow
                </div>
            )}
        </div>
    );
}

I will raise the remaining questions under separate issues, as I believe that may be easier for you to work with.