You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One problem with the current asynchronous plugin model is that it can send O(number_of_plugins) updates to the front-end for every character typed.
One possibility is to aggregate them in the front-end until the next draw-cycle, but that can still be glitchy if the first update comes in right-before a redraw and the highlighted text comes after. This will still lead to a "flash of unstyled content" to use web terminology. The problem is that I prefer an occasional extra 16ms of latency over the wrong thing being drawn and then 16ms later flashing to the correct thing, it looks bad.
One way to fix this is to introduce the concept of "low-latency" plugins that always either send an update in response to an edit, or acknowledge it without doing anything. Then the core can wait for all low-latency plugins to acknowledge or 10ms to pass before sending the update to the front-end.
Then say the syntax highlighting plugin can send updates to highlight the next 100 lines and then acknowledge, and proceed with any more lines it has to highlight.
Wait for multi-plugin support
Add the concept of a "low-latency" plugin
Add the concept of an "acknowledgement". This is necessary so things like the bracket-matcher which don't always send updates don't always cause it to time out, and so that the syntax highlighter can send updates for the rest of the viewport before acknowledging.
Delay sending an update to the front-end until all "low-latency" plugins have acknowledged, 10ms passes from the user edit, or possibly also when another user edit comes in.
This could still in principle show unstyled content for an unlucky fast typist if they hit another key between the first key and the first key being styled, the second key will be sent out unstyled. But it's still much better, and that case should be rare, especially if the syntax highlighting plugin immediately gives up on any previous jobs upon receiving a new one.
Unfortunately, this is still broken-ish. without special handling you'll end up doing twice the syntax highlighting work in bracket-matching cases. You'll type an open-quote and Xi will send to the syntect plugin for re-highlighting, which will start re-highlighting the rest of the file as a string, meanwhile the bracket-matcher will add a close-quote, which will trigger another syntect job which will fix the previous job and start fixing the highlighting for however many lines it messed up before the close quote came in. I think the way Sublime and other reasonable editors do it is to synchronously process all things triggered by the user's keystroke (bracket-matching, auto-indent, snippet expansion, possibly even plugins) and after all of those have completed, then it does syntax highlighting. I'm not sure how much it will affect latency, probably some, but it will certainly affect power usage.
The only way I can think of to fix that is to create a graph of which "low-latency" plugins can affect other plugins, then topological sort it (it ought to be acyclic) and wait for plugin results with a timeout synchronously in that order. This order could just be a list in a config file done by hand because it will be a small list and easy to figure out what the best order would be. This is only viable if the round-trip latency on RPC requests is maybe less than 100 microseconds. It might also be a good idea to only send the updates to other higher-latency plugins after the low-latency plugins are done so that they don't also start jobs and then immediately throw them away when the matched bracket comes in.
And of course my mental model of Jonathan Blow won't shut up about how the overhead of the RPCs and the asynchronous model resolving will take 100-1000x longer than just doing straightforward bracket-matching and auto-indent synchronously in-process. Doing so would be faster, easier, would always display the correct content first try and would never do unnecessary work.
With this patch, edit events are not rendered to the client immediately
if there are any active plugins. Instead a render is scheduled after a
brief delay (currently 2 ms) during which window any changes received
from plugins will be batched into a single render.
Progress on xi-editor#437. Closesxi-editor#267.
With this patch, edit events are not rendered to the client immediately
if there are any active plugins. Instead a render is scheduled after a
brief delay (currently 2 ms) during which window any changes received
from plugins will be batched into a single render.
Progress on xi-editor#437. Closesxi-editor#267.
cmyr
added a commit
to cmyr/xi-editor
that referenced
this issue
Apr 21, 2018
With this patch, edit events are not rendered to the client immediately
if there are any active plugins. Instead a render is scheduled after a
brief delay (currently 2 ms) during which window any changes received
from plugins will be batched into a single render.
Progress on xi-editor#437. Closesxi-editor#267.
With this patch, edit events are not rendered to the client immediately
if there are any active plugins. Instead a render is scheduled after a
brief delay (currently 2 ms) during which window any changes received
from plugins will be batched into a single render.
Progress on #437. Closes#267.
One problem with the current asynchronous plugin model is that it can send
O(number_of_plugins)
updates to the front-end for every character typed.One possibility is to aggregate them in the front-end until the next draw-cycle, but that can still be glitchy if the first update comes in right-before a redraw and the highlighted text comes after. This will still lead to a "flash of unstyled content" to use web terminology. The problem is that I prefer an occasional extra 16ms of latency over the wrong thing being drawn and then 16ms later flashing to the correct thing, it looks bad.
One way to fix this is to introduce the concept of "low-latency" plugins that always either send an update in response to an edit, or acknowledge it without doing anything. Then the core can wait for all low-latency plugins to acknowledge or 10ms to pass before sending the update to the front-end.
Then say the syntax highlighting plugin can send updates to highlight the next 100 lines and then acknowledge, and proceed with any more lines it has to highlight.
This could still in principle show unstyled content for an unlucky fast typist if they hit another key between the first key and the first key being styled, the second key will be sent out unstyled. But it's still much better, and that case should be rare, especially if the syntax highlighting plugin immediately gives up on any previous jobs upon receiving a new one.
Unfortunately, this is still broken-ish. without special handling you'll end up doing twice the syntax highlighting work in bracket-matching cases. You'll type an open-quote and Xi will send to the syntect plugin for re-highlighting, which will start re-highlighting the rest of the file as a string, meanwhile the bracket-matcher will add a close-quote, which will trigger another syntect job which will fix the previous job and start fixing the highlighting for however many lines it messed up before the close quote came in. I think the way Sublime and other reasonable editors do it is to synchronously process all things triggered by the user's keystroke (bracket-matching, auto-indent, snippet expansion, possibly even plugins) and after all of those have completed, then it does syntax highlighting. I'm not sure how much it will affect latency, probably some, but it will certainly affect power usage.
The only way I can think of to fix that is to create a graph of which "low-latency" plugins can affect other plugins, then topological sort it (it ought to be acyclic) and wait for plugin results with a timeout synchronously in that order. This order could just be a list in a config file done by hand because it will be a small list and easy to figure out what the best order would be. This is only viable if the round-trip latency on RPC requests is maybe less than 100 microseconds. It might also be a good idea to only send the updates to other higher-latency plugins after the low-latency plugins are done so that they don't also start jobs and then immediately throw them away when the matched bracket comes in.
And of course my mental model of Jonathan Blow won't shut up about how the overhead of the RPCs and the asynchronous model resolving will take 100-1000x longer than just doing straightforward bracket-matching and auto-indent synchronously in-process. Doing so would be faster, easier, would always display the correct content first try and would never do unnecessary work.
cc participants when this was discussed on IRC: @rkusa @cmyr @raphlinus
The text was updated successfully, but these errors were encountered: