mirror of
https://github.com/openai/codex.git
synced 2026-04-29 08:56:38 +00:00
81 lines
2.7 KiB
Markdown
81 lines
2.7 KiB
Markdown
**DOs**
|
||
- Align UI text with config: Use a single source of truth by deriving `Display` and `Serialize/Deserialize` on the enum with kebab-case.
|
||
```rust
|
||
use serde::{Deserialize, Serialize};
|
||
use strum_macros::Display;
|
||
|
||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
|
||
#[serde(rename_all = "kebab-case")]
|
||
#[strum(serialize_all = "kebab-case")]
|
||
pub enum AskForApproval {
|
||
#[default]
|
||
#[serde(rename = "untrusted")]
|
||
#[strum(serialize = "untrusted")]
|
||
UnlessTrusted,
|
||
OnFailure,
|
||
Never,
|
||
}
|
||
```
|
||
|
||
- Render policies via `Display`: Show the kebab-case value with `to_string()` (or `format!("{}", ...)`) in summaries and TUI.
|
||
```rust
|
||
("approval", config.approval_policy.to_string())
|
||
// or
|
||
("approval", format!("{}", config.approval_policy))
|
||
```
|
||
|
||
- Override per-variant when needed: Explicitly rename variants whose desired label isn’t the kebab-case of the Rust identifier.
|
||
```rust
|
||
#[serde(rename = "untrusted")]
|
||
#[strum(serialize = "untrusted")]
|
||
UnlessTrusted,
|
||
```
|
||
|
||
- Keep changes centralized: Put naming logic on the enum, not scattered across UI layers.
|
||
```rust
|
||
// Good: UI just uses Display everywhere
|
||
let approval = config.approval_policy.to_string();
|
||
```
|
||
|
||
- Verify and update snapshots when UI text changes: Regenerate and accept TUI snapshots that include the new strings.
|
||
```sh
|
||
cargo test -p codex-tui
|
||
cargo insta pending-snapshots -p codex-tui
|
||
cargo insta accept -p codex-tui
|
||
```
|
||
|
||
**DON'Ts**
|
||
- Don’t use Debug for user-facing strings: `{:?}` exposes Rust variant names that don’t match config values.
|
||
```rust
|
||
// Bad: prints "UnlessTrusted"
|
||
("approval", format!("{:?}", config.approval_policy))
|
||
```
|
||
|
||
- Don’t use `serde_json::to_string` for display: It adds quotes/JSON formatting and increases complexity.
|
||
```rust
|
||
// Bad: results in "\"untrusted\""
|
||
("approval", serde_json::to_string(&config.approval_policy).unwrap())
|
||
```
|
||
|
||
- Don’t duplicate mapping in the UI: Avoid hand-written matches or ad-hoc conversions in multiple files.
|
||
```rust
|
||
// Bad: scattered, easy to drift
|
||
let label = match config.approval_policy {
|
||
AskForApproval::UnlessTrusted => "untrusted",
|
||
AskForApproval::OnFailure => "on-failure",
|
||
AskForApproval::Never => "never",
|
||
};
|
||
```
|
||
|
||
- Don’t rely on implicit case conversion to match external spec: Handle exceptions like `UnlessTrusted` → `untrusted` explicitly.
|
||
```rust
|
||
// Bad: assumes kebab-case of identifier is correct
|
||
#[strum(serialize_all = "kebab-case")] // without per-variant override
|
||
// "UnlessTrusted" would become "unless-trusted" (wrong)
|
||
```
|
||
|
||
- Don’t leak internal names into UX: Users should see config-aligned values, not Rust identifiers.
|
||
```rust
|
||
// Bad UX: shows "OnFailure" instead of "on-failure"
|
||
format!("{:?}", AskForApproval::OnFailure);
|
||
``` |