codemirror / codemirror5

In-browser code editor (version 5, legacy)
http://codemirror.net/5/
MIT License
26.84k stars 4.97k forks source link

Cursor cannot be placed after whitespace at end of wrapped line when using 'contenteditable'. #6274

Open bmurr opened 4 years ago

bmurr commented 4 years ago

Issue

When using mode contenteditable, you cannot place a cursor at the end of a wrapped line if it ends in whitespace.

In browser textarea, browser contenteditable and CodeMirror textarea, when you click the white space at the end of a line, the cursor appears on the same line, after the whitespace. In CodeMirror contenteditable, it appears on the next line.

This issue is also apparent when using the "End" key to jump to the end of the line, as the cursor will be drawn on the next line down.

It can also be apparent when using "Up" and "Down" keys, as the cursor will appear to jump from the start of a line to a later point in the line, below the last character of the previous line. This looks very wrong.

Unfortunately my use case for CodeMirror requires contenteditable and I cannot use textarea.

Demo

Here is a demo, showing examples with CodeMirror using contenteditable and textarea, as well as examples using browser versions.

https://jsbin.com/maharafaca/1/edit?js,output

Possibly related issues:

5415

4840

4841

CodeMirror: 5.53.2 Browsers: Chrome 81 on Mac, Firefox 72 Mac

marijnh commented 4 years ago

The editor uses the browser's native cursor in contentEditable mode. As your demo shows, Chrome will always show a cursor at a wrap point on the next line. Firefox does have support for something like this, but it works differently than what CodeMirror does by default—it'll require an additional arrow key press to move across to the next line.

It might be possible that this can be fixed in Firefox. I think with Chrome, that is unlikely to be possible.

bmurr commented 4 years ago

I'm confused -- surely my demo shows that Chrome does not show a cursor on the next line, but on the same line? If CodeMirror uses the browser's native cursor, why is the behaviour different to the browser contenteditable div?

marijnh commented 4 years ago

That might be a Linux/macOS difference—Chrome linux doesn't allow me to place the cursor after the whitespace on the wrap point at all.

CodeMirror handles cursor motion itself, and then updates the DOM selection to match it. Its internal model does distinguish between these cases, as do browser's selection models, apparently, but the JavaScript DOM selection interface is very simplistic, and doesn't provide a direct way to control this. It's possible that there's a kludge that could make this work, though. I haven't looked into it yet.

bmurr commented 4 years ago

I don't think it's an OS difference -- I have tried the same thing on Ubuntu 20.04 with both Chrome and Firefox and I see the same behaviour, so I'm not sure why you are unable to place the cursor after the whitespace, unless it's down to whatever flavor of Linux you are running.

Just to make sure we are talking about the same thing, here is a screencast of the issue (Chrome, Ubuntu):

out

If that is not the behaviour you are seeing locally (for all 4 textual areas), that is also strange.

marijnh commented 4 years ago

Oh, right, it seems I can place the cursor there with the mouse, just not with the arrow keys. That's good news, I guess, since it means Chrome is capable of drawing such cursors, and we just need to find a way to create them with a script.

bmurr commented 4 years ago

Well, it's good news that there may be a potential fix!

For anyone experiencing the same issue - as a workaround for my case, I capture the mousedown event and any keydown events which could cause this effect (Home, End, Cmd-Right, Up, Down, etc) and tell CodeMirror to ignore them by setting a truthy codemirrorIgnore property on the event.

Unfortunately this means that some CodeMirror features I was using like the matchBrackets plugin and multiple cursors no longer work, but it's more important for me that the navigation keys work as they do when handled by the browser. I'm not sure what other potential consequences this might have.

@marijnh It doesn't seem possible to tell CodeMirror to ignore an event from a key that is bound in the extraKeys option? I think it would be a nicer solution to ignore a key in there, as it would be in a position to take advantage of all the cross-platform compatibility things that CodeMirror does.