A technical deep dive into the new Vectra
We've just shipped the public beta of Vectra 2.0. It is the biggest release since we first launched, and the first version that runs on both macOS and Windows.
To get there, we rewrote the app from the ground up. This post is about the decisions we made along the way.
Where we started
The original app was written in Swift and AppKit. It was fast, but every feature had to be built twice to reach a second platform, and the extension API ran in a separate Node process that talked to the app over a pipe.
Why the rewrite
We wanted three things: one codebase, an extension runtime that lives inside the app, and no regressions in speed. That last point ruled out most of the obvious choices.
Picking a stack
We settled on a Rust core with a thin native shell per platform. The UI renders through a small retained-mode layer we wrote ourselves.
pub fn rank(query: &str, items: &[Item]) -> Vec<Match> {
let mut out: Vec<Match> = items
.par_iter()
.filter_map(|it| score(query, &it.title).map(|s| Match { id: it.id, score: s }))
.collect();
out.sort_unstable_by(|a, b| b.score.cmp(&a.score));
out.truncate(50);
out
}New file indexer
The indexer now watches the file system incrementally instead of rescanning. On a laptop with half a million files, a cold index takes 11 seconds and an update is effectively free.
Platform conventions
Shortcuts, window behaviour and focus rules follow each platform. On Windows, the command bar opens with Alt+Space; on macOS it keeps the shortcut you already use.
What's next
The public beta is open to everyone today. We will publish a second post on the extension runtime next month.