Each recipe is a task, start to finish. For what each part is, see the Technical reference; for why, see Understanding the architecture.

A change is done when the code is written, its tests cover the paths that fail as well as the one that works, its cost is measured where a budget applies, and the documentation says so — in English and in French.

Add a setting

  1. Add the field to Settings in crates/kve-config/src/settings.rs, with a doc comment that says what it is for.
  2. Give it its value in resources/settings/defaults.toml, with a comment above it: that file is what a user reads. Without a value, the tests fail.
  3. Give it a fixed value in resources/settings/for-tests.toml; a test holds the two files to the same keys.
  4. Write it out in Settings::annotated — one setting(&mut out, "name", …) line in the order of the file.
  5. Explain it in both catalogues, settings.<name> in crates/kve-config/locales/en-US.yml and fr-FR.yml. A test refuses a setting with no explanation.
  6. Read it where it is used. In kve-ui, a view that is not the window asks the window through an accessor rather than holding a copy.
  7. Say so in the README’s example settings and on the user page that describes the feature. The settings reference page is generated; make site writes it.

Add a command

  1. Declare its action with the others at the top of crates/kve-ui/src/window.rs.
  2. Add it to the registry in crates/kve-config/src/command.rs: an id (file.my_command), a scope, label_key: "command.file.my_command", a default binding or None, and a group if it belongs in a submenu.
  3. Name it in both catalogues under command.<id>.
  4. Map the id to the action in crates/kve-ui/src/menu.rs, and, when it has a key, in bindings() in window.rs.
  5. Handle it: a method on EditorWindow, wired with .on_action(cx.listener(Self::my_command)) in the window’s render.
  6. Test the method, and the key with cx.simulate_keystrokes(…) when it has one. The shortcut reference page is generated from the registry.

Add a string the user sees

  1. Add a key to en-US.yml and the same key to fr-FR.yml, each written in its own language rather than translated word for word.
  2. Use it with kve_config::tr("key"), or add a helper in crates/kve-config/src/lib.rs when it takes arguments (rust_i18n::t!("key", name = name)).
  3. Never write a sentence in Rust. A test fails when the catalogues’ keys differ.

Measure something new

  1. Add a Measurement::of(name, why, budget, iterations, setup) to crates/kve-bench/src/main.rs. why says where the budget comes from: a frame (16 ms), input handling (4 ms), or what is asked for once.
  2. Build what is measured at the size that matters — 2,000 cards, 10,000 files, a 480 KB document — in the setup, and measure only the operation.
  3. Run cargo run --release --locked -p kve-bench. A budget missed is a result, not a nuisance: find why before changing the budget.
  4. Record the numbers in docs/perf/, with what changed them.
  5. For a cost inside a window, add a line with crate::timing::timed(…): it prints only when KVE_TIMINGS=1 is set.

Test a window

  1. In kve-ui, write a #[gpui::test] that opens a window with a_window_with(path, settings, cx) — on editing_alone() or another fixed set of settings, never the real defaults.
  2. Act through the window’s own methods inside handle.update(cx, …), or with cx.simulate_keystrokes(handle.into(), "ctrl-s") and simulate_input.
  3. Wait: cx.run_until_parked(), and cx.executor().advance_clock(…) first for anything debounced.
  4. To check where something is drawn, give the element a .debug_selector(|| "name".into()), draw with VisualTestContext::from_window, and read debug_bounds("name").
  5. Make the test fail with the fix taken out, once, before keeping it.

Look at the real window

  1. make build, and cargo build -p kve-drive.

  2. tools/drive.sh start path/to/file — under cage, invisible; add --nested to watch it on your desktop. Point XDG_CONFIG_HOME and XDG_DATA_HOME at a scratch folder to leave your own settings alone.

  3. Drive it with a script on standard input — move, click, drag, key, type, scroll, sleep:

    tools/drive.sh run <<'EOF'
    move 640 400
    sleep 200
    click
    key ctrl+s
    EOF
    

    Move first and pause before a bare click: a click where the pointer has not been yet is lost.

  4. tools/drive.sh shot out.png, then tools/drive.sh stop.

Retake a screenshot of the website

python3 tools/doc-shots.py en whiteboard retakes one scene in one language; with no arguments, every scene in both. Each runs on a demo project the script builds, so a scene changes by changing the script, never the picture.

Change a dependency

  1. Change the version in the workspace Cargo.toml, then update that crate only: cargo update -p name. Never a bare cargo update.
  2. Run make check, and kve-bench on its own if the crate is on a measured path.
  3. Record the numbers in docs/perf/ and commit Cargo.lock with the change. The toolchain in rust-toolchain.toml is changed the same way.

Change an address, a name or the maintainer

  1. Edit project.toml, at the root — the only place any of them is written.
  2. make sync, for Cargo.toml and the metainfo; the website, the release script and the package read the file as they run.
  3. cargo test -p kve-config --test project confirms every copy agrees.

Make a release

  1. tools/release.sh check 1.0.0 — changes nothing, says what is not ready.
  2. tools/release.sh prepare 1.0.0 — sets the version everywhere and leaves a skeleton of the release notes; write them.
  3. tools/release.sh finish 1.0.0 — the checks, the commit, the tag, the tarball, the .deb and the site, in dist/. Then push, upload and deploy yourself: the script prints the commands and runs none of them.