search query input: Better handle CodeMirror extensions derived from props
Created by: fkling
Fixes #37721 (closed)
Please read this comment from the issue for more information about what causes the problem.
tl;dr: onChange
changed after onBlur
was called, which caused a group of extensions to be re-created, including the onBlur
DOM event handler, which caused it to fire as along as the editor wasn't focused (go back to the beginning).
This PR introduces a couple of changes to prevent unexpected issues with recreating CodeMirror extensions:
- At the Monaco facade level, all callbacks are "bound" via state fields. That means that extensions are not recreated (and the editor is not reconfigured) when any of the callback functions change. The downside is that extensions cannot be conditionally created depending on whether a callback was provided or not (e.g. there is always an event handler bound for
Mod+k
even ifonHandleFuzzyFinder
is not provided), but luckily CodeMirror provides ways to indicate that an event wasn't handled by the extension (e.g. returningfalse
from the keybinding handler). -
onFocus
andonBlur
event handlers are now triggered from the state update handler (as it was before) instead of DOM event handlers, to prevent them from being accidentally triggered, which was the cause for the Code Insights creation form freeze up. - The "core" CodeMirror query input also switches to using a compartment for the theme setting. With this any extension created by the component itself won't ever be re-created. All extensions derived from props are updated via transactions.
I'm also including a minor CSS fix. Without it the actual input doesn't expand to the whole width of the container and clicking inside what appears to be the input field doesn't focus to actual input.
Test plan
Go to https://sourcegraph.test:3443/insights/create/search?dashboardId=all and create a new code insight. Go to the search query input. Type something, leave the input. The page does not freeze.
App preview:
Check out the client app preview documentation to learn more.