-
Notifications
You must be signed in to change notification settings - Fork 97
Refactor: decouple CodeMirror and React #9190
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
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
3de593d to
c294f66
Compare
| // setEditorView(editorView: EditorView) { | ||
| // this.overrideTreeHighlighterUpdateForPerformanceTracking() | ||
| // } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh I just saw this! There is an issue I've created recently: #9184
Basically we called overrideTreeHighlighterUpdateForPerformanceTracking each time an edit was made wrapping the update function multiple times.
A simple fix is to keep track of the plugins already patched, or only call this once at init time (or if plugins change).
My fix would very likely conflict with this PR so I will postpone fixing it. Let me know if you prefer to fix it in your PR, or otherwise I will wait for this to merge and fix afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah I wanted to put a pin in that while I worked out the other unknowns in this PR, but I think I can bring this back or solve what it's trying to do much more simply now that we won't re-render all over the place and obliterate the EditorView.
6c81094 to
b946a6d
Compare
franknoirot
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really excited for this one.
| import type { Node } from '@rust/kcl-lib/bindings/Node' | ||
|
|
||
| import { CustomIcon } from '@src/components/CustomIcon' | ||
| import { useCodeMirror } from '@src/components/layout/areas/CodeEditor' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the diff in this PR is to get rid of this import so I could delete that file. What I've got is the start of a "microEditor" CodeMirror setup defined below, which we can package up and use as our common KCL input in a follow-up PR. Most of the annoyance here is now just that the component still re-renders like mad because off all my careless useMemos and so on, but that's how it actually is in prod.
| const editorParent = useRef<HTMLDivElement>(null) | ||
| useEffect(() => { | ||
| return () => { | ||
| kclEditorActor.send({ type: 'setKclEditorMounted', data: false }) | ||
| kclEditorActor.send({ type: 'setLastSelectionEvent', data: undefined }) | ||
| kclManager.diagnostics = [] | ||
| } | ||
| editorParent.current?.appendChild(kclManager.editorView.dom) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BYE REACT DON'T NEED YA
| // New code to just update the CodeMirror extensions directly. | ||
| kclManager.editorView.dispatch({ | ||
| effects: kclLspCompartment.reconfigure(Prec.highest(lsp)), | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left basically everything the same with the LspProvider but it can go soon. I'm pretty confident we can make it instantiate when a project is opened just from KclManager and never touch React, especially once we get a proper openProject method in there and store the opened project and executing file; those are the only things that the useEffects in this component are here for.
| } from '@kittycad/codemirror-lsp-client' | ||
| import { reportRejection } from '@src/lib/trap' | ||
| import { deferExecution } from '@src/lib/utils' | ||
| import { deferredCallback } from '@src/lib/utils' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure it's kinda noisy, but when I saw deferExecution I thought for sure this was some kind of engine execution wrapper, and it's really just a nice little deferring utility (perhaps with overlapping usefulness with our debounce function but that's for another day)
|
|
||
| /** A view plugin that requests completions from the server after a delay */ | ||
| export class KclPlugin implements PluginValue { | ||
| private viewUpdate: ViewUpdate | null = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class would hold onto viewUpdate, a very risky thing to hold onto since they're so ephemeral.
src/lang/KclManager.ts
Outdated
| set code(code: string) { | ||
| this.editorView.dispatch({ | ||
| changes: { | ||
| from: 0, | ||
| to: this.editorView.state.doc.length, | ||
| insert: code, | ||
| }, | ||
| }) | ||
| this._code.value = code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now setting the code value will dispatch, instead of bounce around.
| .writeFile(this._currentFilePath, this.code ?? '') | ||
| .writeFile(this._currentFilePath, newCode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with executeCode above, this.code is a bad pattern and not guaranteed to be up-to-date. Now we pass in new code from the ViewUpdate listener extension, which is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to @src/editor/plugins/theme/index.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I'm comfortable working with CodeMirror I loathe the boilerplate and type runaround of how I've used XState here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BYE REACT BYE
b6dc567 to
f7fe680
Compare
Towards #8885, stacked on #9236. Adding a for-now unused CodeMirror extension that registers the AST as a StateField on the EditorView. Right now we trash the EditorView constantly so that value will not be trustworthy, but it will be once we remove all our React scaffolding around CodeMirror, which is a work-in-progress in #9190. Then this will be available to become the canonical derived AST state, automatically updated whenever the code is updated by the user.
Towards #8885, stacked on #9236. Adding a for-now unused CodeMirror extension that registers the AST as a StateField on the EditorView. Right now we trash the EditorView constantly so that value will not be trustworthy, but it will be once we remove all our React scaffolding around CodeMirror, which is a work-in-progress in #9190. Then this will be available to become the canonical derived AST state, automatically updated whenever the code is updated by the user.
Towards #8885, stacked on #9236. Adding a for-now unused CodeMirror extension that registers the AST as a StateField on the EditorView. Right now we trash the EditorView constantly so that value will not be trustworthy, but it will be once we remove all our React scaffolding around CodeMirror, which is a work-in-progress in #9190. Then this will be available to become the canonical derived AST state, automatically updated whenever the code is updated by the user.
|
Taking just a bit of a detour here so that I can break out some refactor PRs and PRs that add CodeMirror extensions for other derived state. I'll return to this after a few of the PRs I've broken out from it land. |
423fe17 to
d1d4b0f
Compare
Towards #8885, broken out from #9190. Refactors the KCL LSP extension to not store any EditorView or other state. In addition, splits out concerns of highlighting engine-side entities and executing code. Users should experience no degradations from this refactor, although it is possible that this fixes some niche case bugs.
* Organize class properties on KclManager Baby step towards #8885 broken out from a larger effort in #9190. Just meant to start categorizing and commenting on the many class properties in this class, as we step towards consolidating them. * Update snapshots * Update snapshots * Revert AST setter This contained material changes that break the app currently, relying on other future changes. * Update snapshots * Update snapshots * Update snapshots * Revert changes to `code` setter These rely on other changes to come to work properly. * Update snapshots --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
ab7d796 to
df5305e
Compare
Now we gotta fix the world in this PR hold onto your butts!
And a risky one at that!
It's such a bummer that we don't receive this as a signal it's crazy
ebcd92b to
d8b7e66
Compare
WIP towards #8880, built off of #9064 which was a proof-of-concept. This still has just a bit more polish to be done but I think I've proven that this is very doable. Most of the cleanup remaining comes from needing to translate our overwrought scaffolding around CodeMirror and the EditorState into neater little effects. I think by the end of this the execution loop might be a bare CodeMirror plugin, which I am fucking thrilled about.