If a document is written with a new path, currently, in the event that
the write fails, the document still gets its path changed. This fixes
it so that the path is not updated unless the write succeeds.
The way that document writes are handled are by submitting them to the
async job pool, which are all executed opportunistically out of order. It
was discovered that this can lead to write inconsistencies when there
are multiple writes to the same file in quick succession.
This seeks to fix this problem by removing document writes from the
general pool of jobs and into its own specialized event. Now when a
user submits a write with one of the write commands, a request is simply
queued up in a new mpsc channel that each Document makes to handle its own
writes. This way, if multiple writes are submitted on the same document,
they are executed in order, while still allowing concurrent writes for
different documents.
Instead of repeatedly checking if it is in_bounds, calculate the
max_indent beforehand and just loop. I added a debug_assert to "prove"
that it never tries drawing out of bounds.
Better performance, and otherwise very long lines with lots of tabs
will wrap around the u16 and come back on the other side, messing up
the beginning skip_levels.
Also changes workspace diagnostic picker bindings to <space>D and
changes the debug menu keybind to <space>g, the previous diagnostic
picker keybind. This brings the diagnostic picker bindings more in
line with the jump to next/previous diagnostic bindings which are
currently on ]d and [d.
The debug assertion that document diagnostics are sorted incorrectly
panics for cases like `[161..164, 162..162]`. The merging behavior
in the following lines that relies on the assertion only needs the
input ranges to be sorted by `range.start`, so this change simplifies
the assertion to only catch violations of that assumption.
Undo/redo/earlier/later call `Document::apply_impl` which applies
transactions to the document. These transactions also need to be
applied to the view as in 0aedef0.
Here we separate the diagnostics by severity and then overlay the Vec
of spans for each severity on top of the highlights. The error
diagnostics end up overlaid on the warning diagnostics, which are
overlaid on the hints, overlaid on info, overlaid on any other severity
(default), then overlaid on the syntax highlights.
This fixes two things:
* Error diagnostics are now always visible when overlapped with other
diagnostics.
* Ghost text is eliminated.
* Ghost text was caused by duplicate diagnostics at the EOF:
overlaps within the merged `Vec<(usize, Range<usize>)>` violate
assumptions in `helix_core::syntax::Merge`.
* When we push a new range, we check it against the last range and
merge the two if they overlap. This is safe because they both
have the same severity and therefore highlight.
The actual merge is skipped for any of these when they are empty, so
this is very fast in practice. For some data, I threw together an FPS
counter which renders as fast as possible and logs the renders per
second.
With no diagnostics, I see an FPS gain from this change from 868 FPS
to 878 (+1.1%) on a release build on a Rust file. On an Erlang file
with 12 error diagnostics and 6 warnings in view (233 errors and 66
warnings total), I see a decrease in average FPS from 795 to 790
(-0.6%) on a release build.
It is easy to forget to call `Document::apply` and/or `View::apply` in
the correct order. This commit introduces a helper function which
closes over both calls.