Instead of marker-added and marker-removed events which are emitted
when markers are created/invalidated/revalidated/destroyed, we now
just have marker-created events that are triggered *only* when markers
are created for the first time. The marker itself emits a 'destroyed'
event when it is destroyed. The marker already notifies observers when
its validation status changes, so that's covered.
The previous API revolved around methods on TextBuffer for querying
and manipulating markers based on their id. Now marker creation
methods return marker objects. These are still retrievable by id so
they can be dealt with across serialization boundaries in the future,
but you deal with them directly as objects.
This required changing text-buffer to support having a
path but not underlying file that exists yet.
Now calling RootView.open() with a non-existed path will
open a dirty empty editor to the path and the file will be
created on first save.
This makes it easy to only assign variables for the information you
need in the iterator. Before, we always forced you to take a match and
a range as the first two arguments even if you weren't using them.
We might have two edit sessions pointing to the same buffer, for
example if we have a split pane… So when we deserialize a buffer, we
always need to check that we don't already have an instance of that
buffer on the project. If we do, then we've already deserialized it
once so we don't need to worry about the saved text.
We still have a problem when deserializing previously unsaved buffers,
because we can't use the path to identify them.
Typically it's fine to test serialization behaviorally. If we can
deserialize the serialized state correctly, then we're generally
happy. We don't need explicit tests on the serialized state… but I
added a couple assertions to ensure we don't write text when we don't
need to. It would have been more correct to just modify the saved
file and verify we load the new state, but it's not worth the hassle.
This reflects the way buffers should always be created in practice. It
registers buffers on project, which will be important when testing
that we always get the same buffer when deserializing a buffer for a
path we've already opened.
Previously the line ending length was hard-coded to one which
would cause TextBuffer.scanInRange() to return incorrect results
since one character per line wasn't being accounted for.
Closes#428