Editor for papermario-dx mods
at main 64 lines 3.9 kB view raw view rendered
1<!-- 2SPDX-FileCopyrightText: 2026 Alex Bates <alex@bates64.com> 3 4SPDX-License-Identifier: AGPL-3.0-or-later 5--> 6 7# Contributing 8 9Enter the dev shell with `nix develop` (or use [direnv](https://direnv.net/)), then: 10 11```sh 12just run 13``` 14 15## Dependencies 16 17- Dependencies that could feasibly be used by multiple crates should go in the workspace `Cargo.toml`. 18- When adding a new dependency, ensure it is up to date. 19 20## Formatting 21 22Run `just fmt` before committing. This formats code and adds 23[REUSE](https://reuse.software/)-compliant SPDX license headers to any new 24files, using your `git config user.name` and `git config user.email` as the 25copyright holder. 26 27If you contribute to an existing file, you may add your own 28`SPDX-FileCopyrightText` line alongside the existing one. 29 30## Style 31 32- Check your code against `just check` and `just test`. 33- Try to follow the [Rust API Guidelines Checklist](https://rust-lang.github.io/api-guidelines/checklist.html). 34- 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. 35- 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. 36- 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. 37- Avoid just `#[expect]` or `#[allow]`ing lines. The checks are there for a reason. For example, `as` should usually be `.into()`, or `.try_into()?`. 38 39## Error handling 40 41- The code should only panic if there is a bug in the code. User input should never cause a panic. 42- Use `thiserror` to validate user data and return errors. 43- Use `anyhow` to attach context to errors as they bubble up the stack. 44- Never ignore an error: either pass it on, or log it. 45- If a problem is recoverable, use `ka_log::warn!` and recover. 46- UI code should never panic. Do not use `#[expect(clippy::expect_used)]` etc. in UI code - warn and have a fallback. 47 48Strive to encode code invariants and contracts in the type system as much as possible. [Parse, don't validate.](https://lexi-lambda.github.io/blog/2019/11/05/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). 49 50## Logging 51 52Use `tracing`, or, if a library isn't multithreaded, use `log`. 53 54- `error!` is for _unrecoverable_ problems. The program couldn't complete an operation. 55 - Libraries should ideally not log error, but instead return Err in a Result. 56- `warn!` is for when you recover from an error. The operation completed, but it couldn't do exactly what it was asked to do. 57 - Sometimes an `Err` is handled by logging it as a warning and then running some fallback code. 58 - Warnings are also used for things that might be errors, but could be intended. 59 - If data is lost, it is an error and not a warning. 60- `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. 61- `debug!` is a level you opt-in to debug. These are logged when high-level, important operations are performed. 62- `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. 63 64Use debug formatting `{:?}` in logs.