Closed olivierdagenais closed 3 months ago
codemirror.js
, lines 571-573 reads:
// The DOM events that CodeMirror handles can be overridden by
// registering a (non-DOM) handler on the editor for the event name,
// and preventDefault-ing the event in that handler.
It's possible we're dealing with a call to moveToLineBoundary where the includeWrap
parameter is misconfigured.
Bitbucket 8.9.9 ships with CodeMirror 5.60.0. Using the following test.html
content, I was able to fix the editor by using the extraKeys
option that replaces the Home & End keys with more appropriate commands:
<html>
<head>
<script src="lib/codemirror.js"></script>
<link rel="stylesheet" href="lib/codemirror.css">
<script src="mode/javascript/javascript.js"></script>
</head>
<body>
<textarea id="code">
@codemirror and @lezer packages can be imported directly by name. Other imports should be URLs. You'll usually want your script to create an editor in document.body. Press Ctrl-Space to run the current code, and see the result (boxed in an <iframe>) in the “Ouput” tab. When errors occur or things are logged to the console, you can find them in the “Log” tab.
</textarea>
<script>
const codeMirror = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
lineWrapping: true,
mode: "htmlmixed"
});
codeMirror.setOption("extraKeys", {
"End": "goLineRight",
"Home": "goLineLeftSmart"
});
</script>
</body>
</html>
Next up is figuring out how to set these options in Bitbucket's CodeMirror instance.
In theory, this works:
const codeMirrorWrappedDiv: CodeMirrorWrappedDiv | null =
bitbucketBody.querySelector("div.CodeMirror.CodeMirror-wrap");
if (codeMirrorWrappedDiv) {
const editor = codeMirrorWrappedDiv.CodeMirror;
if (editor) {
var extraKeys = editor.getOption("extraKeys");
if (!extraKeys || typeof extraKeys === "string") {
extraKeys = {};
editor.setOption("extraKeys", extraKeys);
}
extraKeys.Home = "goLineLeftSmart";
extraKeys.End = "goLineRight";
}
}
...however, the current location of that code (page load) is no good because most of the time the CodeMirror-based editors are created dynamically, in response to activating a button.
The elements retrieved from the following selectors would be worth monitoring for the presence of div.CodeMirror.CodeMirror-wrap
:
div.comment-editor-wrapper
div.atlaskit-portal-container
div.comment-content
Additionally, a monitor could be added to div.activities
to watch for new elements matching the selector div.activity-item.commented-activity
.
Still missing: comments added to files/lines.
Perhaps, as a start, we attach an observer to div.tabs-pane.active-pane
(because its contents changes drastically/entirely based on which tab is active) and see what the performance is like before trying to target a list of elements to observe. That still wouldn't cover the editor for the pull request description, since it lives under div.atlaskit-portal-container
.
The observer technique worked for the Bitbucket code search enhancement, but when I tried it on the Bitbucket tab to enhance CodeMirror, it was firing on every letter typed, since that counts as a descendant mutation.
New idea: can we trap Home/End and then only enhance the nearest CodeMirror (if we find any!) before passing on the event? That way, we only spend time "enhancing" whenever those keys are used, which is far less than the time spent typing.
OK, this seems to work but not on the first press of Home or End:
async function handleKeydown2(this: Window, e: KeyboardEvent) {
const document: Document = window.document;
if (bitbucketBody && (e.key == "Home" || e.key == "End")) {
const divs = bitbucketBody.querySelectorAll<CodeMirrorWrappedDiv>(
"div.CodeMirror.CodeMirror-wrap"
);
for (let i = 0; i < divs.length; i++) {
const div = divs[i];
const editor = div.CodeMirror;
if (editor) {
var extraKeys = editor.getOption("extraKeys");
if (!extraKeys || typeof extraKeys === "string") {
extraKeys = {};
editor.setOption("extraKeys", extraKeys);
}
extraKeys.Home = "goLineLeftSmart";
extraKeys.End = "goLineRight";
}
}
}
}
...this event was only registered if we detected the pull request tabs div.
Also, the version of CodeMirror used by Bitbucket might have a defect; the goLineRight
makes the cursor go after the last space on the current virtual line, which means it ends up on the first column of the next line, yet behaves as if it was on the last column of the current line. UPDATE: this odd behaviour is the result of using inputStyle: "contenteditable"
(as opposed to textarea
) and is a known defect with version 5: codemirror/codemirror5#6274
Have you explored setting extraKeys
on the global CodeMirror.defaults
? Does that not work because Bitbucket sets its own extraKeys
on instances and the defaults do not kick in?
Have you explored setting
extraKeys
on the globalCodeMirror.defaults
?
Thanks for the suggestion! Sometimes the easy thing is the best way, however in this scenario it doesn't seem to work:
CodeMirror
object.I then created the simplest Tampermonkey script possible:
// ==UserScript==
// @name Bitbucket CodeMirror
// @namespace http://tampermonkey.net/
// @version 2024-03-02
// @description try to take over the world!
// @author You
// @match http://localhost:7990/bitbucket/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
CodeMirror.defaults.extraKeys = {
Home: "goLineLeftSmart",
End: "goLineRight",
};
})();
...but, once an editor was created, I could see it wasn't working, likely because they had provided their own content for extraKeys
and thus whatever is defined in CodeMirror.defaults
isn't used. Here's what the CodeMirror instance had:
extraKeys: Object {
Enter: "newlineAndIndentContinueMarkdownList",
Tab: false,
"Shift-Tab": false
}
```
For a long line which is soft-wrapped across a few lines, hitting HOME or END goes to the line's absolute beginning or end, rather than that of the current soft-wrapped (virtual) line (which all the other editors in the world do).
Last observed in version 8.9.9, logged with Atlassian on 2020/11/10 as BSERV-12651: Home key has unexpected behavior in comment editor