Homepage    |    GitHub    |    API    |    FAQ

CodeMirror resetting cursor in text insert/update

I'm trying to write a plugin to highlight text in the CodeMirror editor. I have borrowed the base code from another plugin and have the plugin working, apart from ONE thing. Every time I update a line in the editor, it resets the cursor to the start of the editor. It doesn't matter if the inserted text is before or after the location of the cursor, or even on a different line.

I have read all the CodeMirror forums and this is a known problem which the admin of CodeMirror refuses to fix in the core, saying that it can be worked around, but I cannot find any examples of what that workaround is.

Would those with knowledge of CodeMirror please give me a steer if you have an answer.

I have provided a stripped down version of the module without the bulk of the plugin code here -

module.exports = {

    default: function(context: any) {

        const plugin = function(CodeMirror) {

            CodeMirror.defineOption('highlighter', false, function(cm, value, prev) {

                if (!value) return;

                cm.on('inputRead', async function (cm1, change) {

                    var line = cm.getCursor().line;

                    var activeLine = change.from.line;

                    var lineTxt = cm.getLine(change.from.line);

                    const start = {line: change.from.line, ch: 0};

                    const finish = {line: change.from.line, ch: 10};

                    var pos = { // create a new object to avoid mutation of the original selection

                        line: change.from.line,

                        ch: 35 // set the character position to the end of the line

                    }

                    cm.replaceRange("TEXT TO INSERT", start, finish, pos);

                    // I've also tried setting the cursor here to a new position here

                    cm.focus();

                    cm.setCursor(pos);

                });

            });

        };

        return {

            plugin: plugin,

            codeMirrorOptions: {

                'highlighter': true,

            }

        }

    }

}

I think there is maybe more going on in this example that causes the isssue? Joplin uses replaceRange internally without running into this bug. Maybe you can provide a bit more context to what you're doing and link to the CodeMirror forum where the issue is mentioned?

Thanks for the reply. It is discussed here -

What about not moving the cursor if setValue does not change the content? · Issue #3734 · codemirror/CodeMirror · GitHub

It is also mentioned in other threads as I believe that inserting data causes a change event to occur, which in turn causes the editor to reset and then put the cursor at 0,0.

All that I'm doing is replacing text using replaceRange. It doesn't seem to matter if I am replacing text before or after the current cursor position, or even on a different line.

I think what happening, is that the moment a change is made a 'change event' is triggered and the editor treats it like a page reload.

When calling replaceRange, I have tried passing a value through the 'origin' parameter, but everything I've tried has not worked.

I think I'm missing something obvious, but cannot work it out.

Thanks, I'll try to reproduce the error on my own computer.

But I wonder, given the nature of you plugin, maybe you can do it another way? For example, do you actually need to edit a line? Codemirror has support for marking sections with a css class for styling as well as support for replacing chunks of text with a widget.

The Joplin plugin system also has a change event which you could likely leverage instead of the CodeMirror change event.

Thanks for taking the time to look at this.

Yes, I may be approaching this the wrong way, I appreciate that.

The plugin wraps an inline style around text using <SPAN> and so part of the text in the CodeMirror editor need to be replaced. It is at this point that I believe it triggers a 'change event'. What I don't understand is that the plugin is based on another published plugin where text is entered into the editor.

To save you time, would it be worth be sending you the plugin so that you can see the problem?

Yes, that would be great.