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

I want to get the cursor position. #603

Open
ilysusu opened this issue Nov 9, 2023 · 7 comments
Open

I want to get the cursor position. #603

ilysusu opened this issue Nov 9, 2023 · 7 comments

Comments

@ilysusu
Copy link

ilysusu commented Nov 9, 2023

我需要获取光标在编辑器中的位置,做一个文本插入的功能,需要怎么做

@ilysusu
Copy link
Author

ilysusu commented Nov 9, 2023

I need to get the position of the cursor in the editor to implement a text insertion function. What should I do?

@ilysusu ilysusu changed the title 我想要获取光标位置 I want to get the cursor position. Nov 9, 2023
@jaywcjlove
Copy link
Member

在 CodeMirror v6 中,要向光标位置插入字符串,你可以使用 EditorView.dispatch 方法来发送一个 StateEffect,以修改编辑器的状态。具体步骤如下:

  1. 创建一个 StateEffect,用于表示要插入的字符串。例如,假设你要插入的字符串是 insertText

    import { StateEffect } from "@codemirror/state";
    
    const insertText = StateEffect.appendText("insertText");
  2. 使用 ref 获取 codemirror 的 view 对象

  3. 使用 EditorView.dispatch,将该 StateEffect 分发给编辑器视图:

    view.dispatch({
      effects: insertText,
    });

@ilysusu

@ilysusu
Copy link
Author

ilysusu commented Nov 10, 2023

import React, {forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState} from 'react';
import CodeMirror from "@uiw/react-codemirror";
import { StateEffect } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";
import { EditorView } from "@codemirror/view"

const AutoCodeMirror = forwardRef(({exprVal, setExprVal}, ref) => {
const currentNode = useContext(NodesContext)
const [options, setOptions] = useState([])

const codeMirrorRef = useRef(null);

useImperativeHandle(ref, () => {
codeMirrorRef.current
})

// 将 codeMirrorRef 暴露给父组件
useImperativeHandle(ref, () => ({
getCodeMirrorInstance: () => codeMirrorRef.current,
}));
useEffect(() => {
function initOptions() {
const currNodeId = parseInt(currentNode.data.nodeId.substring(1), 10);
const newOptions = [];
for (let i = currNodeId; i >= 1; i--) {
const nodeId = N${i.toString().padStart(4, '0')};
newOptions.push({ label: nodeId, type: "variable" });
}
console.log(newOptions, 'newOptions')
setOptions(newOptions)

}
initOptions()

}, [currentNode]);

const onChange = useCallback((val, viewUpdate) => {
// console.log("val:", val);
setExprVal(val);
// 当前光标位置插入数据
const insertText = StateEffect.appendText("insertText");
const view = codeMirrorRef.current.view;
console.log(view,' view')
view.dispatch({
effects: insertText,
});
}, [setExprVal]);

const myCompletions = (context) => {
let word = context.matchBefore(/\w*/)
if (word.from === word.to && !context.explicit) return null
return {
from: word.from,
// 建议内容
options: options
};
};

return (
<>
<CodeMirror
ref={codeMirrorRef}
style={{border: "1px solid #eee"}}
value={exprVal}
height="250px"
extensions={[
javascript({ jsx: true }),
javascript().language.data.of({autocomplete: myCompletions}),
EditorView.lineWrapping
]}
onChange={onChange}
/>

</>

);
})

export default AutoCodeMirror;

这是我的代码,出现报错 update listener: TypeError: StateEffect.appendText is not a function

@jaywcjlove
Copy link
Member

如果有错误,清使用下面工具工具之一提供重现的示例

另外我可能给了个错误的示例,我这里有个 编辑器的实现有类似的插入代码

https://github.com/uiwjs/react-markdown-editor/blob/c237b69acdad69c2d1804537ecb797bcdcdc14c9/core/src/commands/bold.tsx#L18-L26

    view.dispatch(
      view.state.changeByRange((range) => ({
        changes: [
          { from: range.from, insert: '**' },
          { from: range.to, insert: '**' },
        ],
        range: EditorSelection.range(range.from + 2, range.to + 2),
      })),
    );

@ilysusu 你可以参考我封装的 react-markdown-editor 组件代码

@jaywcjlove
Copy link
Member

@ilysusu 示例: https://codesandbox.io/embed/https-github-com-uiwjs-react-codemirror-issues-603-wr6ph9?fontsize=14&hidenavigation=1&theme=dark

import React, { useRef, useState } from "react";
import CodeMirror from "@uiw/react-codemirror";
import { StateEffect } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";
import { EditorSelection } from "@codemirror/state";

export default function App() {
  const codeMirrorRef = useRef(null);
  const [val, setVal] = useState("console.log('hello world!');");
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log("value:", value);
  }, []);

  // 从光标位置插入文本
  const handleInsertVal = () => {
    const view = codeMirrorRef.current.view;

    view.dispatch(
      view.state.changeByRange((range) => ({
        changes: [
          { from: range.from, insert: "**" },
          { from: range.to, insert: "**" }
        ],
        range: EditorSelection.range(range.from + 2, range.to + 2)
      }))
    );
  };

  const onRefChange = () => {
    codeMirrorRef.current.view.dispatch({
      changes: { from: 0, to: 12, insert: "InsertText" }
    });
  };

  return (
    <div>
      <button onClick={handleInsertVal}> insertValue </button>
      <button onClick={onRefChange}>Ref Change Value</button>
      <CodeMirror
        value={val}
        ref={codeMirrorRef}
        height="200px"
        theme="dark"
        extensions={[javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}

@fsuk
Copy link

fsuk commented Nov 15, 2023

In answer to the issue title (for others looking for an answer to "How to get cursor position"

const cursorPosition = editorRef.current?.view?.state?.selection.main.head

NOTE: Use editorRef.current?.view?.state NOT just editorRef.current?.state as the latter seems to always return 0

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