Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line number is not updated #221

Closed
JMLX42 opened this issue Nov 9, 2021 · 10 comments
Closed

Line number is not updated #221

JMLX42 opened this issue Nov 9, 2021 · 10 comments

Comments

@JMLX42
Copy link

JMLX42 commented Nov 9, 2021

Hello,

I'm trying to use the lineNumbers extension to add an offset to each line number.
It works fine when the component is created/rendered for the first time.

But then if the lineNumberOffset prop is changed, the CodeMirror editor is not updated.
Any idea how to fix this?

import { CatalaCell, setCodeValue } from "../file/fileSlice";
import { connect, ConnectedProps } from "react-redux";
import { RootState } from "../../app/store";
import CodeMirror from '@uiw/react-codemirror';
import { lineNumbers } from "@codemirror/gutter";
import { EditorView } from "@codemirror/view";
import { useAppDispatch } from "../../app/hooks";

const mapState = (state: RootState) => ({
  fileContent: state.file.content,
});

const mapDispatch = {
};

const connector = connect(mapState, mapDispatch);

type PropsFromRedux = ConnectedProps<typeof connector>;

type Props = PropsFromRedux & {
  cellIndex: number;
  lineNumberOffset: number;
}

const CodeEditor = (props: Props) => {
  const dispatch = useAppDispatch();
  const cell: CatalaCell = props.fileContent![props.cellIndex];

  let theme = EditorView.theme({
    "&.cm-editor": {
      padding: "10px 0 10px 0",
      fontSize: ".9em",
      fontFamily: "Roboto Mono, sans-serif",
    },
    ".cm-lineNumbers .cm-gutterElement": {
      minWidth: "45px",
      paddingRight: "0px",
      fontSize: "15px",
      lineHeight: "24px",
      marginRight: "18px",
      fontFamily: "Roboto Mono, sans-serif",
    },
    /* Disable CodeMirror's active line highlighting. */
    "& .cm-activeLineGutter, & .cm-activeLine": {
      backgroundColor: "transparent !important",
    },
    /* Disable CodeMirror's focused editor outline. */
    "&.cm-editor.cm-focused": {
      outline: "none",
    },
  }, {dark: true});

  const extensions = [
    theme,
    lineNumbers({
      formatNumber: (n, s) => {
        return (n + props.lineNumberOffset).toString();
      }
    }),
  ];

  return (
    <div style={{ marginTop: 10, marginBottom: 10 }}>
      <CodeMirror
        basicSetup={false}
        value={cell?.code?.code}
        onChange={(value, viewUpdate) => {
          dispatch(setCodeValue([props.cellIndex, value]));
        }}
        extensions={extensions}
        theme="dark"
      />
    </div>
  );
}
  
export default connector(CodeEditor);
@JMLX42
Copy link
Author

JMLX42 commented Nov 10, 2021

I just asked on the CodeMirror forum: https://discuss.codemirror.net/t/codemirror-6-offset-line-numbers/2675/4

@jaywcjlove
Copy link
Member

@JMLX42
Copy link
Author

JMLX42 commented Nov 11, 2021

@jaywcjlove here you go:

https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-k0uyu?file=/src/App.js

Update: just fixed the codesandbox link

@JMLX42
Copy link
Author

JMLX42 commented Nov 11, 2021

@jaywcjlove I have tried reconfiguring the extension but it doesn't help:

function CodeEditor(props) {
  const gutter = new Compartment();
  const lines = lineNumbers({
    formatNumber: (n, s) => {
      return (n + props.lineNumberOffset).toString();
    }
  });
  const extensions = [gutter.of(lines)];
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current.view) {
      console.log("reconfigure");
      ref.current.view.dispatch({
        effects: gutter.reconfigure(lines)
      });
    }
  });

  return (
    <CodeMirror
      ref={ref}
      value="some_code();"
      height="200px"
      extensions={extensions}
    />
  );
}

Sadly, the editor is not refreshed (and the line number are not updated) until it is focused the 1st time. Then if new lines are added, focusing the editor doesn’t update the lines anymore. But adding content to the editor updates the line numbers.

Is there a way to force an editor update after reconfiguring an extension without focusing it/typing anything in it?

@JMLX42
Copy link
Author

JMLX42 commented Nov 11, 2021

@jaywcjlove it might actually be a CodeMirror bug: https://discuss.codemirror.net/t/codemirror-6-offset-line-numbers/2675/10

@JMLX42
Copy link
Author

JMLX42 commented Nov 12, 2021

It was a bug and it is now fixed in @codemirror/gutter version 0.19.5. The following code now works as expected:

import { CatalaCell, setCodeValue } from "../file/fileSlice";
import { connect, ConnectedProps } from "react-redux";
import { RootState } from "../../app/store";
import { lineNumbers } from "@codemirror/gutter";
import { useAppDispatch } from "../../app/hooks";
import CodeMirror from "@uiw/react-codemirror";
import { EditorState } from "@codemirror/state";

const mapState = (state: RootState) => ({
  fileContent: state.file.content,
});

const mapDispatch = {
};

const connector = connect(mapState, mapDispatch);

type PropsFromRedux = ConnectedProps<typeof connector>;

type Props = PropsFromRedux & {
  cellIndex: number;
  lineNumberOffset: number;
}

const CodeEditor = (props: Props) => {
  const dispatch = useAppDispatch();
  const cell: CatalaCell = props.fileContent![props.cellIndex];

  const extensions = [
    lineNumbers({ formatNumber: (n: number, s: EditorState) =>
      (n + props.lineNumberOffset).toString()
    }),
  ];

  return (
    <div style={{ marginTop: 10, marginBottom: 10 }}>
      <CodeMirror
        value={cell?.code?.code}
        onChange={(value, viewUpdate) => {
          dispatch(setCodeValue([props.cellIndex, value]));
        }}
        extensions={extensions}
        theme="dark"
      />
    </div>
  );
}
  
export default connector(CodeEditor);

And here is the updated CodeSandbox:

https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-2s82t?file=/src/App.js

@JMLX42 JMLX42 closed this as completed Nov 12, 2021
@jaywcjlove
Copy link
Member

https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-2s82t?file=/src/App.js

import CodeMirror from "@uiw/react-codemirror";
import { lineNumbers } from "@codemirror/gutter";
import React from "react";

export function TextEditor(props) {
  const [value, setValue] = React.useState(props.defaultValue);

  const onChange = (e) => {
    setValue(e.target.value);
    props.onChange(e);
  };

  return (
    <textarea
      style={{ width: 400, height: 200 }}
      onChange={onChange}
      value={value}
    ></textarea>
  );
}

function CodeEditor(props) {
  const extensions = [
    lineNumbers({
      formatNumber: (n, s) => {
        return (n + props.lineNumberOffset).toString();
      }
    })
  ];

  return (
    <CodeMirror value="some_code();" height="200px" extensions={extensions} />
  );
}

export default function App() {
  const defaultText = "some text\nadd lines to test";
  const countLines = (s) => s.match(/\n/gm)?.length ?? 0;
  const [lineNumberOffset, setLineNumberOffset] = React.useState(
    countLines(defaultText) + 1
  );

  const onChange = (e) => {
    setLineNumberOffset(countLines(e.target.value) + 1);
  };

  return (
    <div>
      <TextEditor onChange={onChange} defaultValue={defaultText} />
      <div>Line number offset = {lineNumberOffset}</div>
      <CodeEditor lineNumberOffset={lineNumberOffset} />
    </div>
  );
}

@jaywcjlove
Copy link
Member

#316 (comment)

@xiefengnian
Copy link

https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-2s82t?file=/src/App.js

import CodeMirror from "@uiw/react-codemirror";
import { lineNumbers } from "@codemirror/gutter";
import React from "react";

export function TextEditor(props) {
  const [value, setValue] = React.useState(props.defaultValue);

  const onChange = (e) => {
    setValue(e.target.value);
    props.onChange(e);
  };

  return (
    <textarea
      style={{ width: 400, height: 200 }}
      onChange={onChange}
      value={value}
    ></textarea>
  );
}

function CodeEditor(props) {
  const extensions = [
    lineNumbers({
      formatNumber: (n, s) => {
        return (n + props.lineNumberOffset).toString();
      }
    })
  ];

  return (
    <CodeMirror value="some_code();" height="200px" extensions={extensions} />
  );
}

export default function App() {
  const defaultText = "some text\nadd lines to test";
  const countLines = (s) => s.match(/\n/gm)?.length ?? 0;
  const [lineNumberOffset, setLineNumberOffset] = React.useState(
    countLines(defaultText) + 1
  );

  const onChange = (e) => {
    setLineNumberOffset(countLines(e.target.value) + 1);
  };

  return (
    <div>
      <TextEditor onChange={onChange} defaultValue={defaultText} />
      <div>Line number offset = {lineNumberOffset}</div>
      <CodeEditor lineNumberOffset={lineNumberOffset} />
    </div>
  );
}

its not wroking in latest @uiw/react-codemirror (4.21.20).

image

how can i set the linenum offet of react-codemiirror?

@xiefengnian
Copy link

https://codesandbox.io/s/react-codemirror-example-codemirror-6-forked-2s82t?file=/src/App.js

import CodeMirror from "@uiw/react-codemirror";
import { lineNumbers } from "@codemirror/gutter";
import React from "react";

export function TextEditor(props) {
  const [value, setValue] = React.useState(props.defaultValue);

  const onChange = (e) => {
    setValue(e.target.value);
    props.onChange(e);
  };

  return (
    <textarea
      style={{ width: 400, height: 200 }}
      onChange={onChange}
      value={value}
    ></textarea>
  );
}

function CodeEditor(props) {
  const extensions = [
    lineNumbers({
      formatNumber: (n, s) => {
        return (n + props.lineNumberOffset).toString();
      }
    })
  ];

  return (
    <CodeMirror value="some_code();" height="200px" extensions={extensions} />
  );
}

export default function App() {
  const defaultText = "some text\nadd lines to test";
  const countLines = (s) => s.match(/\n/gm)?.length ?? 0;
  const [lineNumberOffset, setLineNumberOffset] = React.useState(
    countLines(defaultText) + 1
  );

  const onChange = (e) => {
    setLineNumberOffset(countLines(e.target.value) + 1);
  };

  return (
    <div>
      <TextEditor onChange={onChange} defaultValue={defaultText} />
      <div>Line number offset = {lineNumberOffset}</div>
      <CodeEditor lineNumberOffset={lineNumberOffset} />
    </div>
  );
}

its not wroking in latest @uiw/react-codemirror (4.21.20).

image

how can i set the linenum offet of react-codemiirror?

For those who need it:

import { lineNumbers } from "@codemirror/gutter"; // remove this
import { lineNumbers } from "@codemirror/view"; // use this

make it work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants