We got some help from @apcragg, who made the build script for our N-API bindings support Linux and Windows. Also @maxim-lian helped by updating our repo to correctly use Cargo workspaces. Also saw a bunch of people building the project and exploring. There's not much to see yet, but we're happy that people are interested.
Someone posted this repo to Hacker News last week, which drew a bunch of attention to the project. Overall this is obviously great, but I sort of regret reading the comments. People can be so mean on HN and it's really a drag to feel like you're the target of vitriol and derision. I'm just over here trying to build stuff. But I guess you gotta just have a thick skin and keep coding.
Thanks to everyone who jumped in with an interest in contributing! The engagement was really helpful and prompted me to post the beginnings of a contributing guide and some initial help-wanted issues. Looking forward to engaging with someone who wants to dive in on one of those problems.
We have selections and cursors rendering on a branch, and hope to merge it this week. The results are promising, and we're only exceeding our 8 ms frame budget when we reach thousands of selections in a document with thousands of edits. We think we can do better with some optimizations.
We plan to merge an initial PR that lays the groundwork this week. This will include the ability to model and render selections, but we need to get a basic key bindings and commands system in place before this will mean much in the UI. We'll post some more detailed benchmarks once we get this basic implementation integrated and have a chance to look at the profile for any basic optimizations.
A conversation with @joefitzgerald at Pivotal in Denver led to a big shift in how we plan to interoperate between JavaScript and Rust. Originally, we planned to embed a shared library written in Rust into the Electron render process and use Node's N-API to interoperate. Somewhere along the line, we realized that to maintain a global edit history for all files that wasn't tied to a project, we would need to unify all of the file system interaction in a single process to avoid race conditions between multiple Electron windows. This process gradually grew in our thinking to take on other responsibilities, such as connecting to other processes to facilitate real time collaboration. Eventually, we decided that we would need to route all I/O through this central process.
Joe asked a simple and insightful question. If we're planning to route all I/O through an external process, then what's the point of the Node APIs available in Electron? They're all designed around I/O, but we won't be doing any. This made it click for me that we should actually move all of the application logic completely into the external Rust process and treat the UI as an extremely thin layer that interacts with the app via an async channel. We'll use something akin to the Flux architecture, where the UI can submit actions to the server on the channel and receive JSON payloads representing state to render. Yes, I realize that this makes us even more similar to Xi architecturally.
This will make the UI code 100% ordinary HTML and JavaScript with no assumption of any special APIs, which really supports our goal of running on the web. For the desktop experience, we can use any solution that gives us a modern, standards-compliant web view and run the core of the application as a server process. The easiest solution on the desktop would be Electron, but we could even use an embedded WebKit view on the Mac to save on bundle size if we wanted to absorb that complexity (it's not clear it's worth it though). On the web, we'll need the server process to run inside the browser, because this whole design assumes an ultra-low-latency connection between the front end and the back end. In this scenario, we can compile some subset of the server process that runs on the desktop to WebAssembly and run it in a worker thread. This web "back end" can then establish a peer-to-peer connection with another Xray process running in the cloud or on another user's computer. This will provide a 100% compatible experience between the browser and the desktop and enable collaboration between users in either environment.
Here's a somewhat complicated picture of our current thinking. Note the centrality of the "Xray Core Process". All the logic and extensibility lives there, and the view becomes much simpler.
We'll be starting on these changes this week. The first step is to completely eliminate Electron and wrap xray_core
in a server process, which we're thinking about calling xray_server
. The front end will be xray_client
and compile down to a simple HTML file. When you open it in the browser, it will connect to a local port based on the query parameter in the URL.
Once we accomplish that, we'll need to figure out an alternate variant of the server, maybe called xray_server_wasm
, which runs a "server" in one or more worker threads for a low-latency experience on the web. Compiling pure Rust to WebAssembly hopefully won't be a big deal, but we are a bit worried about including TreeSitter, whose runtime and grammars are written in C. We think we can figure it out though.
In light of these big structural changes, we'll probably be holding off on merging any PRs this week until the dust has settled. Thanks for your patience.
I've mentioned elsewhere in this repo the conversation I had with Raph Levien a few weeks ago about collaborating with Xi. In light of the fact that we're moving even closer to Xi architecturally, I can already anticipate the criticism that what we're doing here is redundant and we should just contribute to Xi. Why bother with this?
First of all, I'm definitely not opposed to some sort of partnership with Xi. I have tremendous respect for the technical work they've done and really like Raph personally. That said, it's complicated. We have our own ideas for where we want to take this project and what it means to GitHub. At the moment, the only way I see to guarantee we can achieve those ideas is to have enough creative control to iterate and follow our own path. Xi has been around for a while now, and it would be rude and presumptuous to roll in and start telling them how they should run their project. If we want to be active participants in our own destiny without telling other people what to do, it seems like we need to take our own path, at least for now.
We would like to learn as much as we can from the Xi team, and we'd be happy if we could provide value to them as well. It seems like sharing ideas would be a necessary prerequisite to sharing code. If the work we're doing proves valuable enough for the Xi team to want to invite us in as partners, then that would be great, but we're really still experimenting here with how best to achieve our particular goals. It's not clear that we have the same priorities as the Xi team, and it's not obvious that our priorities are sufficiently compatible for us share a codebase. And that's okay. There's room for more than one editor in the world.
If we do end up having enough social and technical alignment to share code, then that would obviously be great for us, because we'd be working with some incredibly smart people. I want to be open minded, but I also want the freedom to create based on our own ideas without telling anyone else what to do. So it's complicated. It's not crystal clear what the right path is, but we're doing our best to make the best decisions with the experience and wisdom we've managed to acquire to this point.