grid_min_cell( width ) adds the adaptive mode WrapGrid was missing: instead of a fixed column count, the count is derived at layout time from the available width so every cell is at least `width` wide (any Length, so a fluid threshold works; never fewer than one column), re-derived on every resize. Cells then share the width equally, and WrapGrid::max_columns( n ) caps the derived count so cells grow instead of multiplying on very wide surfaces — the cap only applies to the adaptive mode, grid( n ) keeps the fixed behaviour untouched. Four new layout tests cover width derivation, spacing accounting, the one-column floor and the cap; the row-wrap assertions check X positions rather than Y because zero-height spacer children produce zero-height rows. flex( child ) now distributes leftover height inside a Column, mirroring its leftover-width behaviour in a Row: flex children join the weight pool alongside weight-only spacers and y-scrolls, draw their child inside the allocated share at full inner width, and contribute zero to the column's natural height exactly like a row counts flex width. This closes the documented "vertical flex is not yet implemented" gap; the Flex rustdoc and the widgets.md entry now describe both axes. Add scripts/style-check.sh and a make stylecheck target, wired into CI: mechanical verification of the grep-checkable subset of code_style_guide.md — tab indentation and spaces inside attribute brackets — with comment lines skipped so prose may cite raw attribute syntax. To turn the check on green, the 82 unspaced attribute sites across 24 files (#[test], #[derive(...)], #[cfg(...)], #[allow(...)]) were normalized to the spaced form. CONTRIBUTING and the style guide reference the new target; brace placement and paren spacing remain review concerns.
137 lines
3.8 KiB
Markdown
Executable File
137 lines
3.8 KiB
Markdown
Executable File
# Code Style Guide
|
|
|
|
This project follows a **Modified Allman** brace and formatting style, applied to Rust. It prioritizes **visual clarity, symmetry, and logical separation of blocks** over strict line compactness.
|
|
|
|
This file is the canonical style reference; the style bullets in [CONTRIBUTING.md](CONTRIBUTING.md) are a summary of it.
|
|
|
|
---
|
|
|
|
## Key principles
|
|
|
|
- Indentation with **tabs** (width = 4).
|
|
- **Opening braces `{`** start on their own line — for `fn`, `impl`, `struct`, `enum`, `trait`, `mod`, `if`, `for`, `while`, `loop` and `match`.
|
|
- **`} else {`** and **`} else if … {`** stay on the same line for compact flow.
|
|
- **Spaces inside parentheses only when non-empty:**
|
|
- `( arg1, arg2 )`
|
|
- `main()`
|
|
- **Spaces inside attribute brackets only when non-empty:** `#[ derive( Clone, Debug ) ]`, `#[ cfg( test ) ]`.
|
|
- **No spaces inside generics:** `Vec<String>`, `Option<i32>`, `Element<Msg>`.
|
|
- **Types, traits, and enum variants:** PascalCase.
|
|
- **Functions, methods, variables, and modules:** snake_case (the Rust convention; `rustc` warns on anything else).
|
|
- **Constants and statics:** UPPER_CASE_WITH_UNDERSCORES.
|
|
- **Aligned columns** in consecutive struct fields, match arms, or `let` groups where it aids scanning.
|
|
- **Comments in English**, only where the code cannot say it itself.
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### `if / else` structure
|
|
|
|
```rust
|
|
if condition
|
|
{
|
|
do_something();
|
|
} else if other_condition {
|
|
do_other_thing();
|
|
} else {
|
|
do_something_else( arg1, arg2 );
|
|
}
|
|
```
|
|
|
|
### `match` structure
|
|
|
|
```rust
|
|
match points.len()
|
|
{
|
|
0 => None,
|
|
1 => Some( points[0].value ),
|
|
n => Some( total / n as f32 ),
|
|
}
|
|
```
|
|
|
|
### Error handling
|
|
|
|
Rust has no `try / catch`; recoverable errors travel as `Result` and propagate with `?`. The block style applies to the `match` when a result is handled in place:
|
|
|
|
```rust
|
|
fn load_config( path: &Path ) -> Result<Config, ConfigError>
|
|
{
|
|
let text = std::fs::read_to_string( path )?;
|
|
match toml::from_str( &text )
|
|
{
|
|
Ok( cfg ) => Ok( cfg ),
|
|
Err( e ) => Err( ConfigError::Parse( e ) ),
|
|
}
|
|
}
|
|
```
|
|
|
|
`if let` follows the same brace rules as `if`:
|
|
|
|
```rust
|
|
if let Some( ( rgba, w, h ) ) = icon( "general/right" )
|
|
{
|
|
it = it.trailing_icon( rgba, w, h );
|
|
}
|
|
```
|
|
|
|
### Structs, impls, and attributes
|
|
|
|
```rust
|
|
#[ derive( Clone, Debug ) ]
|
|
pub struct DataPoint
|
|
{
|
|
value: f32,
|
|
label: String,
|
|
}
|
|
|
|
impl DataPoint
|
|
{
|
|
pub fn new( value: f32, label: impl Into<String> ) -> Self
|
|
{
|
|
Self
|
|
{
|
|
value,
|
|
label: label.into(),
|
|
}
|
|
}
|
|
|
|
pub fn scaled( &self, factor: f32 ) -> f32
|
|
{
|
|
if factor <= 0.0
|
|
{
|
|
self.value
|
|
} else {
|
|
self.value * factor
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### `main()` function
|
|
|
|
```rust
|
|
fn main()
|
|
{
|
|
let analyzer = DataAnalyzer::new( "results.csv" );
|
|
|
|
if let Err( e ) = analyzer.process_and_report()
|
|
{
|
|
eprintln!( "Error: {e}" );
|
|
std::process::exit( 1 );
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Tooling: do not run `cargo fmt`
|
|
|
|
`rustfmt` cannot express this style, so **never run `cargo fmt` on this codebase** — it would rewrite every file into the default style. Specifically:
|
|
|
|
- There is **no rustfmt option for spaces inside parentheses or attribute brackets** (the historical `spaces_within_parens` options were removed from rustfmt).
|
|
- The item brace styles (`brace_style`, `control_brace_style`) are **unstable, nightly-only** options.
|
|
- Even on nightly, the combination of Allman opening braces with a compact `} else {` is not representable: `control_brace_style = "AlwaysNextLine"` also pushes `else` onto its own line.
|
|
|
|
The repository ships a `rustfmt.toml` containing only `disable_all_formatting = true`, so an accidental `cargo fmt` — or an editor with format-on-save wired to rustfmt — is a no-op instead of a 40 000-line diff. The mechanically verifiable subset (tab indentation, attribute-bracket spacing) is enforced by `make stylecheck` (`scripts/style-check.sh`), which CI runs on every push; everything else — brace placement, paren spacing, naming — is enforced by review.
|