122 lines
4.2 KiB
Markdown
122 lines
4.2 KiB
Markdown
# Coding Standards
|
|
|
|
Rules of the road for pikl-menu. If something's not covered
|
|
here, use good judgement and keep it consistent with the rest
|
|
of the codebase.
|
|
|
|
## Error Handling
|
|
|
|
- **No `anyhow`.** Every error type is a proper enum. No
|
|
stringly-typed errors, no `Box<dyn Error>` as a crutch.
|
|
- Use `thiserror` where it helps (derive `Error` +
|
|
`Display`), but it's not mandatory. Hand-written impls
|
|
are fine too.
|
|
- Use `Result` and `?` everywhere. Convert between error
|
|
types with `.map_err(YourVariant)`. Keep it simple, no
|
|
closures when a variant constructor will do.
|
|
- It's fine to stringify an error when crossing thread/async
|
|
boundaries (e.g. `JoinError` to `Io`), but always wrap
|
|
it in a typed variant with context.
|
|
|
|
## No Panics
|
|
|
|
- **No `unwrap()`, `expect()`, or `panic!()` in library or
|
|
binary code.** CI lints enforce this.
|
|
- We know IO and FFI can't be made perfectly safe. The goal
|
|
is to not *add* unsafe situations. Handle failures, don't
|
|
crash through them.
|
|
|
|
## Clippy & Lints
|
|
|
|
- Deny `clippy::unwrap_used`, `clippy::expect_used`,
|
|
`clippy::panic` workspace-wide. These are the guardrails
|
|
for the no-panic rule.
|
|
- Deny `clippy::dbg_macro`, `clippy::print_stdout`,
|
|
`clippy::print_stderr`. Use `tracing` instead.
|
|
- Enable `clippy::must_use_candidate`. If a function returns
|
|
a `Result`, `Option`, or any value the caller shouldn't
|
|
silently ignore, it gets `#[must_use]`.
|
|
- Run `cargo clippy -- -D warnings` in CI. Warnings are
|
|
errors.
|
|
|
|
## Unsafe Code
|
|
|
|
- `unsafe` blocks need a `// SAFETY:` comment explaining
|
|
why it's sound.
|
|
- Keep unsafe surface area minimal. If there's a safe
|
|
alternative that's not meaningfully worse, use it.
|
|
|
|
## Logging & Diagnostics
|
|
|
|
- **All logging goes through `tracing` and
|
|
`tracing-subscriber`.** No `println!`, `eprintln!`,
|
|
`dbg!()`, or manual log files.
|
|
- No temp files for logs. No `/tmp/pikl-debug.log`. None
|
|
of that.
|
|
- We'll eventually build a debug subscriber tool (think
|
|
tokio-console style). Design logging with structured
|
|
events in mind.
|
|
|
|
## Async Conventions
|
|
|
|
- Tokio is the async runtime. No mixing in other runtimes.
|
|
- Prefer structured concurrency with `JoinSet` over
|
|
fire-and-forget `tokio::spawn`. If you spawn a task, you
|
|
should be able to cancel it and know when it's done.
|
|
- Be explicit about cancellation safety. If a future holds
|
|
state that would be lost on drop, document it. This
|
|
matters for hooks and IPC especially.
|
|
- Use `tokio::select!` carefully. Every branch should be
|
|
cancellation-safe or documented as not.
|
|
|
|
## Public API Surface
|
|
|
|
- `pikl-core` is an embeddable library. Treat its public
|
|
API like a contract.
|
|
- Don't make things `pub` unless they need to be. Default
|
|
to `pub(crate)` and open up intentionally.
|
|
- Re-export the public interface from `lib.rs`. Consumers
|
|
shouldn't need to reach into submodules.
|
|
- Breaking changes to the public API should be deliberate,
|
|
not accidental side effects of refactoring.
|
|
|
|
## Performance
|
|
|
|
- **Avoid cloning** where possible. Cheap copies (small
|
|
`Copy` types, `Arc::clone`) are fine. Cloning strings
|
|
and vecs as a convenience? Try harder.
|
|
- **Use zero-copy** patterns: borrowed slices, `Cow`, views
|
|
into existing data.
|
|
- **Prefer iterators** over collecting into intermediate
|
|
`Vec`s. Chain, filter, map. Only collect when you
|
|
actually need the collected result.
|
|
|
|
## Testing
|
|
|
|
- Every module in `pikl-core` gets unit tests. Every filter,
|
|
hook lifecycle event, I/O format.
|
|
- Integration tests exercise the real binary with real
|
|
pipes. No mocked IO at that level.
|
|
- Cross-platform: tests must pass on Linux and macOS. Gate
|
|
platform-specific tests with `#[cfg]`.
|
|
- When the GUI frontend lands, add snapshot/visual
|
|
regression tests.
|
|
- Build toward an e2e framework that can drive the full
|
|
tool.
|
|
|
|
## Dependencies
|
|
|
|
- `pikl-core` stays free of rendering, terminal, and GUI
|
|
deps. It's an embeddable library.
|
|
- Prefer pure-Rust deps. C deps behind feature flags only
|
|
(e.g. `pcre2`).
|
|
- Be intentional about what you pull in. If the standard
|
|
library does it, use the standard library.
|
|
|
|
## Import Ordering
|
|
|
|
- Group imports in this order: `std`, external crates,
|
|
workspace crates (`pikl_*`), then `self`/`super`/`crate`.
|
|
- Blank line between each group.
|
|
- `rustfmt` handles the rest. Don't fight it.
|