Editor for papermario-dx mods

Contributing#

Enter the dev shell with nix develop (or use direnv), then:

just run

Dependencies#

  • Dependencies that could feasibly be used by multiple crates should go in the workspace Cargo.toml.
  • When adding a new dependency, ensure it is up to date.

Formatting#

Run just fmt before committing. This formats code and adds REUSE-compliant SPDX license headers to any new files, using your git config user.name and git config user.email as the copyright holder.

If you contribute to an existing file, you may add your own SPDX-FileCopyrightText line alongside the existing one.

Style#

  • Check your code against just check and just test.
  • Try to follow the Rust API Guidelines Checklist.
  • Write unit tests for all public functions containing business logic, data transformations, or state management. They go in a #[cfg(test)] mod tests at the bottom of each file. GUI/rendering code does not require unit tests.
  • Write integration tests using egui_kittest for GUI code. Binary crates (like kammy) cannot use the tests/ directory at the crate root because there is no library target to import. Instead, use a src/tests.rs module gated behind #[cfg(test)], with submodules in src/tests/ organized by feature (e.g. src/tests/undo.rs). Shared test utilities go in src/tests.rs. Library crates should use the standard tests/ directory at the crate root.
  • Prefer module-level inner doc comments (//!) at the top of a file over outer doc comments (///) on the mod declaration. This keeps the documentation next to the code it describes.
  • Avoid just #[expect] or #[allow]ing lines. The checks are there for a reason. For example, as should usually be .into(), or .try_into()?.

Error handling#

  • The code should only panic if there is a bug in the code. User input should never cause a panic.
  • Use thiserror to validate user data and return errors.
  • Use anyhow to attach context to errors as they bubble up the stack.
  • Never ignore an error: either pass it on, or log it.
  • If a problem is recoverable, use ka_log::warn! and recover.
  • UI code should never panic. Do not use #[expect(clippy::expect_used)] etc. in UI code - warn and have a fallback.

Strive to encode code invariants and contracts in the type system as much as possible. Parse, don't validate. If you can't enforce a contract in the type system, enforce them using assert and in documentation (if its part of a public API).

Logging#

Use tracing, or, if a library isn't multithreaded, use log.

  • error! is for unrecoverable problems. The program couldn't complete an operation.
    • Libraries should ideally not log error, but instead return Err in a Result.
  • warn! is for when you recover from an error. The operation completed, but it couldn't do exactly what it was asked to do.
    • Sometimes an Err is handled by logging it as a warning and then running some fallback code.
    • Warnings are also used for things that might be errors, but could be intended.
    • If data is lost, it is an error and not a warning.
  • info! should be used by application code to write interesting and rare things to the user. For instance, you might log that a file was saved to a specific path.
  • debug! is a level you opt-in to debug. These are logged when high-level, important operations are performed.
  • trace! is a last resort and is mostly for spam. If it generates a lot of continuous logging (e.g. ui function called every frame), it should go to trace.

Use debug formatting {:?} in logs.