At the start, my goal was to learn how Vulkan and GPU programming/rendering worked in general; over time, this slowly morphed into trying to write a streaming-based text editor. Even though it currently lacks too many (indeed, any) features required to be useable, I thought it might be interesting enough to share in its present state.
The things that are most exciting about it (in my opinion) are:
Files are never loaded into memory; edits are instead tracked in an IntMap keyed on byte positions in the base file, which is used to generate a Stream (Of Char) IO () on demand.
With a streaming-based approach, line traversal requires knowing the positions of newline ('\n') characters in the base file, and typically you want to scan these into an array on load – this is surprisingly fast, but can still be a noticeable delay on very large files.
Here, this is done asynchronously, and functions only block when they attempt to force a value in a part of the array that has not been initialized yet. This means that startup (and even editing near the start of the file!) is instant even on extremely large (> 1 GB) files, as long as you have at least 2 CPU cores.
Seems like an interesting concept, do you know of other visual editors that adopt this approach?
I looked around (not thoroughly by any means!), but didn’t see anything that used quite the same approach. I did recently hear about some commercial software called UltraEdit that can handle large files, but I think it’s closed source and I haven’t tried it.
Also, how do you handle the possibility of very long lines?
Great question! I currently don’t, which means very long lines will cause line operations to block until the end of the file is reached in the initial scan. I did think about this, and my solution will likely be to just treat files as having a virtual newline character on every 32 KB boundary, if the block does not contain '\n'. This ends up being an extremely simple change code-wise, though I want to test it to see how it performs.
I do also want to eventually separate visual line traversal from actual line traversal, but this is a little more involved since information about where lines wrapped visually needs to flow back from the renderer.
I wonder what made you pick vulkan-api and wrapping VMA over vulkan and its stuff.
This is also a great question! I really didn’t have any good reason here. When I began, I reasoned I’d pick the library that was a 1:1 binding so I could follow traditional Vulkan tutorials more closely. At the point where I started finding manual memory management annoying, I was already fairly committed and figured I could just generate the VMA bindings I needed.
I’m definitely aware vulkan already has bindings to VMA (in fact, I used them as a reference!) and was probably the better choice to start with. That said, I certainly don’t regret the decision – I learned quite a bit doing it, and the FFI was very pleasant to work with once I got off the ground.