Skip to content
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

Editor invalidation, optimizations, and more #433

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

MinusGix
Copy link
Member

@MinusGix MinusGix commented May 1, 2024

This does a variety of optimizations.
Commits:

  • Rather than (roughly) HashMap<Font Size, HashMap<Line, TextLayout>>, we store it as (roughly) HashMap<Font Size, [TextLayout]>.
    • Also introduces smarter invalidation of text layouts, using InvalLines, rather than the recreating the text layouts after every edit
    • This makes a lot of other changes simpler, too.
  • LLVM seems pretty poor at optimizing Rope. This results in many cases where the same value is computed repeatedly, and so I've started adding more utility functions. I've also cached the last_line of the Rope on the RopeTextVal/RopeTextRef, as this gives some boost due to how often we compute it.
    • I'd like to cache this on the Rope itself, but it'd require a good investment of time to wrap my head around all the implementation details of Rope. (which is also why some other opts aren't done)
  • Due to the new layout cache as an array, calculating the last visual line becomes significantly cheaper, as it is easy to only calculate the vline part that is actually in view.
  • This and the next commit make large text in register for pasting faster.
  • Fix the cache, there was a bug with how I invalidated
  • Apparently I swapped the order of the 'forward' / 'backward' search which made it slower than needed, but these are removed later
  • Removes the HashMap<Font Size, _> as it complicates a bunch of code having multiple locations for the layouts to come from.
    • This does mean less caching for features like code lens in Lapce (or whatever it was renamed to) where some text is made very small, but I think we are fast enough at creating text layouts for that to fine.
    • This gives a very nice performance boost in some areas, removing the majority of lag large files have
  • Completely remove font size provider. This wasn't needed anymore, really, since Lines doesn't need to know the font size. This simplifies the code.
  • Next three commits are simply altering some functions to avoid the possibility of allocating a string during operations that we might use often. These aren't significant, though.
  • Another two opts because LLVM is being mean
  • Simplifies the calculation of the initial vline like how last vline was made cheaper, making calculating the visual line practically free (especially compared to the cost of creating text layouts)
  • Fix invalidation logic again, and fix it across multiple editors
  • Make the standard InvalCount not need the rope as the majority of locations do not benefit from it, and it would make simply invalidating some lines harder. Still has the version with Rope separate as InvalCountR
  • Remove cache_rev from Document (and the impl supplied, TextDocument), as well as from Visual Lines, as we no longer need an entire file cache id due to line-specific invalidation. (All the lines can still be cleared by calling a specific function on Lines, possibly should be exposed from Editor if it isn't already)
  • Make the Layouts cache a generic LineRenderCache which can be used in Lapce for various data associated with lines that needs to be invalidated

There's still a few bugs I need to determine, and may try other alterations.

MinusGix added 21 commits June 20, 2024 22:49
Last vline could grow very expensive (10ms) on large (200k lines) files, because it was forced to look up every (font_size, line) in the hashmap.
(Possibly it was more expensive than 10ms previously, because it had a second-level hashmap rather than an array!)
Now it is quite cheap as the new layout cache makes it simple to only do that iteration on the lines actually in view.

It does have the issue that it isn't respecting different font sizes for each line but that's fixable.
Register could have large text in its fields which we would then clone everytime we performed an action relating to it.
This was originally only thought to be used for code lens in Lapce, which would shrink the font size of lines, but I don't believe that's implemented.
As well, it should be fast enough to just rerender those text layouts. This makes many operations much faster, no longer having to deal with a hashmap or the trait object indirection every loop iter.
This significantly simplifies & optimizes the calculation of the initial visual line, now being mostly only sensitive to how many lines are on screen than the size of the file.
As well it lets us get rid of a bunch of side code that isn't needed.
Uses a listener rather than invalidating only the editor doing the edit, for the obvious reason so as to invalidate all editors.
(Though I would've liked to avoid using Listener)

Also fixes & simplifies the invalidation calculation, adding tests to ensure correctness.
Also does some minor changes to Document
This is useful for Lapce where we have styles/code-actions/etc associated with lines which can be partially invalidated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant