Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
- Prefer `where` clauses when a type has multiple trait bounds.
- Derive order: standard traits, then comparison traits, then `Hash`, then `derive_more`, then feature-gated derives.
- For error types, only derive `Display` and `Error` from `derive_more` when each is actually needed. Not all displayable types are errors.
- Minimize `unwrap()` in non-test code. Use proper error handling instead.
- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
Expand Down
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
- Prefer `where` clauses when a type has multiple trait bounds.
- Derive order: standard traits, then comparison traits, then `Hash`, then `derive_more`, then feature-gated derives.
- For error types, only derive `Display` and `Error` from `derive_more` when each is actually needed. Not all displayable types are errors.
- Minimize `unwrap()` in non-test code. Use proper error handling instead.
- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
Expand Down
1 change: 0 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
- Prefer `where` clauses when a type has multiple trait bounds.
- Derive order: standard traits, then comparison traits, then `Hash`, then `derive_more`, then feature-gated derives.
- For error types, only derive `Display` and `Error` from `derive_more` when each is actually needed. Not all displayable types are errors.
- Minimize `unwrap()` in non-test code. Use proper error handling instead.
- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
Expand Down
14 changes: 5 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,12 @@ pub use event::Event;

### Derive Macro Ordering

When deriving multiple traits, use this order and split across multiple `#[derive(...)]` lines for readability:
The order of trait names within each `#[derive(...)]` attribute is enforced automatically by the `perfectionist::derive_ordering` rule, configured for the `prefix_then_alphabetical` style. The configured `prefix` in `dylint.toml` lists the trait families in their project-preferred order: `Debug`, formatting / error derives (`Display`, `Error`), defaults (`Default`, `SmartDefault`), `Clone` / `Copy`, comparison and `Hash`, reference wrappers (`AsRef`, `AsMut`, `Deref`, `DerefMut`), conversions (`From`, `Into`, `TryFrom`, `TryInto`, `FromStr`), iteration, arithmetic operator pairs and folds, and integer-format derives. Any trait that is not in the `prefix` (project-specific derives such as `Setters` and `Parser`) falls in ASCII-case-insensitive alphabetical order after the prefix entries.

1. **Standard traits:** `Debug`, `Default`, `Clone`, `Copy`
2. **Comparison traits:** `PartialEq`, `Eq`, `PartialOrd`, `Ord`
3. **Hash**
4. **`derive_more` traits:** `Display`, `From`, `Into`, `Add`, `AddAssign`, etc.
5. **Feature-gated derives** on a separate `#[cfg_attr(...)]` line
The remaining conventions are not enforced by the rule and must be applied by hand. When a type derives many traits, split them across multiple `#[derive(...)]` lines for readability, and place feature-gated derives on a separate `#[cfg_attr(...)]` line.

```rust
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Display, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(From, Into, Add, AddAssign, Sub, SubAssign, Sum)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub struct Bytes(u64);
Expand All @@ -92,11 +88,11 @@ Use **descriptive names** for type parameters, not single letters:

- `Size`, `Name`, `SizeGetter`, `HardlinksRecorder`, `Report`

Single-letter generics are acceptable only in very short, self-contained trait impls.
Single-letter generics are acceptable only in very short, self-contained trait impls. Enforced by `perfectionist::single_letter_generic`; the threshold for "very short" is the rule's `short_impl_max_lines` knob in `dylint.toml`.

### Variable and Closure Parameter Naming

Use **descriptive names** for variables and closure parameters by default. Single-letter names are permitted only in the specific cases listed below.
Use **descriptive names** for variables and closure parameters by default. Single-letter names are permitted only in the specific cases listed below. Enforced by `perfectionist::single_letter_let_binding`, `perfectionist::single_letter_function_param`, and `perfectionist::single_letter_closure_param`; the per-rule `allowed_idents` and `extra_trivial_callback_methods` knobs in `dylint.toml` reflect the exceptions documented here.

#### When single-letter names are allowed

Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ terminal_size = "0.4.4"
text-block-macros = "0.2.0"
zero-copy-pads = "0.2.0"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(dylint_lib, values("perfectionist"))'] }

[dev-dependencies]
build-fs-tree = "0.8.1"
command-extra = "1.0.0"
Expand Down
24 changes: 23 additions & 1 deletion dylint.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
[workspace.metadata.dylint]
libraries = [
{ git = "https://github.com/KSXGitHub/perfectionist", tag = "0.0.0-rc.7" },
{ git = "https://github.com/KSXGitHub/perfectionist", tag = "0.0.0-rc.14" },
]

["perfectionist::derive_ordering"]
style = "prefix_then_alphabetical"
prefix = [
"Debug", "Display", "Error",
"Default", "SmartDefault",
"Clone", "Copy",
"PartialEq", "Eq", "PartialOrd", "Ord",
"Hash",
"AsRef", "AsMut", "Deref", "DerefMut",
"From", "Into", "TryFrom", "TryInto", "FromStr",
"IntoIterator",
"Add", "AddAssign", "Sub", "SubAssign", "Mul", "MulAssign", "Div", "DivAssign",
"Sum", "Product",
"LowerHex", "UpperHex", "Octal",
]

["perfectionist::macro_argument_binding"]
deny_extra = ["debug_assert_op", "debug_assert_op_expr"]

["perfectionist::single_letter_closure_param"]
extra_trivial_callback_methods = ["sort_reflection_by"]
6 changes: 3 additions & 3 deletions src/app/overlapping_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait Api {
type RealPathError;
fn canonicalize(path: &Self::Argument) -> Result<Self::RealPath, Self::RealPathError>;
fn is_real_dir(path: &Self::Argument) -> bool;
fn starts_with(a: &Self::RealPath, b: &Self::RealPath) -> bool;
fn starts_with(path: &Self::RealPath, prefix: &Self::RealPath) -> bool;
}

/// Implementation of [`Api`] that interacts with the real system.
Expand All @@ -36,8 +36,8 @@ impl Api for RealApi {
}

#[inline]
fn starts_with(a: &Self::RealPath, b: &Self::RealPath) -> bool {
a.starts_with(b)
fn starts_with(path: &Self::RealPath, prefix: &Self::RealPath) -> bool {
path.starts_with(prefix)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ impl Api for MockedApi {
.all(|(link, _)| PathBuf::from(link).normalize() != path)
}

fn starts_with(a: &Self::RealPath, b: &Self::RealPath) -> bool {
a.starts_with(b)
fn starts_with(path: &Self::RealPath, prefix: &Self::RealPath) -> bool {
path.starts_with(prefix)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use terminal_size::{Width, terminal_size};
use text_block_macros::text_block;

/// The CLI arguments.
#[derive(Debug, SmartDefault, Setters, Clone, Parser)]
#[derive(Debug, SmartDefault, Clone, Parser, Setters)]
#[clap(
name = "pdu",

Expand Down
4 changes: 2 additions & 2 deletions src/args/depth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
const INFINITE: &str = "inf";

/// Maximum depth of the tree.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq)]
pub enum Depth {
#[display("{INFINITE}")]
Infinite,
Expand All @@ -25,7 +25,7 @@ impl Depth {
}

/// Error that occurs when parsing a string as [`Depth`].
#[derive(Debug, Display, Clone, PartialEq, Eq, Error)]
#[derive(Debug, Display, Error, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum FromStrError {
#[display("Value is neither {INFINITE:?} nor a positive integer: {_0}")]
Expand Down
6 changes: 3 additions & 3 deletions src/args/fraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use std::{
};

/// Floating-point value that is greater than or equal to 0 and less than 1.
#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd, AsRef, Deref, Display, Into)]
#[derive(Debug, Display, Default, Clone, Copy, PartialEq, PartialOrd, AsRef, Deref, Into)]
pub struct Fraction(f32);

/// Error that occurs when calling [`Fraction::new`].
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Error)]
#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq)]
pub enum ConversionError {
/// Provided value is greater than or equal to 1.
#[display("greater than or equal to 1")]
Expand Down Expand Up @@ -42,7 +42,7 @@ impl TryFrom<f32> for Fraction {
}

/// Error that occurs when parsing a string as [`Fraction`].
#[derive(Debug, Display, Clone, PartialEq, Eq, Error)]
#[derive(Debug, Display, Error, Clone, PartialEq, Eq)]
pub enum FromStrError {
ParseFloatError(ParseFloatError),
Conversion(ConversionError),
Expand Down
4 changes: 2 additions & 2 deletions src/args/threads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const AUTO: &str = "auto";
const MAX: &str = "max";

/// Number of rayon threads.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Display)]
#[derive(Debug, Display, Default, Clone, Copy, PartialEq, Eq)]
pub enum Threads {
#[default]
#[display("{AUTO}")]
Expand All @@ -19,7 +19,7 @@ pub enum Threads {
}

/// Error that occurs when parsing a string as [`Threads`].
#[derive(Debug, Display, Clone, PartialEq, Eq, Error)]
#[derive(Debug, Display, Error, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum FromStrError {
#[display("Value is neither {AUTO:?}, {MAX:?}, nor a number: {_0}")]
Expand Down
4 changes: 2 additions & 2 deletions src/bytes_format/parsed_value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use derive_more::{Display, Error};
use derive_more::Display;

/// Return value of [`Formatter::parse_value`](super::Formatter::parse_value).
#[derive(Debug, Display, Clone, Copy, Error)]
#[derive(Debug, Display, Clone, Copy)]
pub enum ParsedValue {
/// When input value is less than `scale_base`.
#[display("{value} ")]
Expand Down
2 changes: 1 addition & 1 deletion src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl DeviceBoundary {

/// The device number of a filesystem.
#[derive(
Debug, Display, LowerHex, UpperHex, Octal, Clone, Copy, PartialEq, Eq, Hash, From, Into,
Debug, Display, Clone, Copy, PartialEq, Eq, Hash, From, Into, LowerHex, UpperHex, Octal,
)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub struct DeviceNumber(u64);
Expand Down
2 changes: 1 addition & 1 deletion src/hardlink/hardlink_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use pipe_trait::Pipe;
use std::path::Path;

/// Internal key used to uniquely identify an inode across all filesystems.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct InodeKey {
/// Inode number within the device.
ino: InodeNumber,
Expand Down
2 changes: 1 addition & 1 deletion src/hardlink/hardlink_list/summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
use serde::{Deserialize, Serialize};

/// Summary from [`HardlinkList`] or [`Reflection`].
#[derive(Debug, Default, Setters, Clone, Copy, PartialEq, Eq, Add, AddAssign, Sum)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Add, AddAssign, Sum, Setters)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
#[setters(prefix = "with_")]
#[non_exhaustive]
Expand Down
2 changes: 1 addition & 1 deletion src/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};

/// The inode number of a file or directory.
#[derive(
Debug, Display, LowerHex, UpperHex, Octal, Clone, Copy, PartialEq, Eq, Hash, From, Into,
Debug, Display, Clone, Copy, PartialEq, Eq, Hash, From, Into, LowerHex, UpperHex, Octal,
)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub struct InodeNumber(u64);
Expand Down
2 changes: 1 addition & 1 deletion src/json_data/binary_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
pub const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");

/// Version of the `pdu` program that created the input JSON.
#[derive(Debug, Clone, PartialEq, Eq, AsMut, AsRef, From, FromStr, Into)]
#[derive(Debug, Clone, PartialEq, Eq, AsRef, AsMut, From, Into, FromStr)]
#[cfg_attr(feature = "json", derive(Deserialize, Serialize))]
pub struct BinaryVersion(String);

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
//! [`tree_builder::TreeBuilder`], [`data_tree::DataTree`], or [`visualizer::Visualizer`].

#![deny(warnings)]
#![cfg_attr(dylint_lib = "perfectionist", feature(register_tool))]
#![cfg_attr(dylint_lib = "perfectionist", register_tool(perfectionist))]

Comment thread
KSXGitHub marked this conversation as resolved.
#[cfg(feature = "json")]
pub use serde;
Expand Down
2 changes: 1 addition & 1 deletion src/os_string_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use serde::{Deserialize, Serialize};
Eq,
PartialOrd,
Ord,
AsMut,
AsRef,
AsMut,
Deref,
DerefMut,
From,
Expand Down
2 changes: 1 addition & 1 deletion src/reporter/error_report/text_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ fn test() {
),
};
let actual = TextReport(report).to_string();
let expected = "[error] read_dir \"path/to/a/directory\": Something goes wrong (os error 420)";
let expected = r#"[error] read_dir "path/to/a/directory": Something goes wrong (os error 420)"#;
assert_eq!(actual, expected);
}
2 changes: 1 addition & 1 deletion src/reporter/progress_and_error_reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ where
ReportProgress: Fn(ProgressReport<Size>) + Send + Sync + 'static,
{
let progress = Arc::new(ProgressReportState::default());
let progress_thread = progress.clone();
let progress_thread = Arc::clone(&progress);
let progress_reporter_handle = spawn(move || {
loop {
sleep(progress_report_interval);
Expand Down
2 changes: 1 addition & 1 deletion src/reporter/progress_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use derive_setters::Setters;
use std::fmt::Write;

/// Scan progress.
#[derive(Debug, Default, Setters, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Setters)]
#[setters(prefix = "with_")]
pub struct ProgressReport<Size: size::Size> {
/// Number of scanned items.
Expand Down
2 changes: 1 addition & 1 deletion src/usage_md.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn render_argument(out: &mut String, arg: &Arg) {
.unwrap_or_else(|| arg.get_id().as_str());
let is_multiple = arg
.get_num_args()
.map(|r| r.max_values() > 1)
.map(|range| range.max_values() > 1)
.unwrap_or(false);
let display_name = if arg.is_required_set() {
if is_multiple {
Expand Down
2 changes: 1 addition & 1 deletion src/visualizer/proportion_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use fmt_iter::repeat;
use std::fmt::{Display, Error, Formatter};

/// Block of proportion bar.
#[derive(Debug, Clone, Copy, PartialEq, Eq, AsRef, Deref, Display, Into)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, AsRef, Deref, Into)]
pub struct ProportionBarBlock(char);

macro_rules! make_const {
Expand Down
2 changes: 1 addition & 1 deletion src/visualizer/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct TreeSkeletalComponent {
}

/// String made by calling [`TreeSkeletalComponent::visualize`](TreeSkeletalComponent).
#[derive(Debug, Clone, Copy, PartialEq, Eq, AsRef, Deref, Display, Into)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, AsRef, Deref, Into)]
pub struct TreeSkeletalComponentVisualization(&'static str);

impl TreeSkeletalComponent {
Expand Down
1 change: 0 additions & 1 deletion template/ai-instructions/shared.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Read and follow the CONTRIBUTING.md file in this repository for all code style c
- Use descriptive names for variables and closure parameters. Single letters are permitted only in these cases: (1) conventional names like `n` for count or `f` for formatter; (2) comparison closures like `|a, b|`; (3) trivial single-expression closures; (4) fold accumulators; (5) index variables `i`/`j`/`k` in short closures or index-based loops; and (6) test fixtures with identical roles. Single letters are never permitted in multi-line functions or closures.
- Use `pipe-trait` to chain through unary functions such as constructors, `Some`, `Ok`, and free functions. Use it to flatten nested calls and to continue method chains. Do not use it for simple standalone calls; prefer `foo(value)` over `value.pipe(foo)`.
- Prefer `where` clauses when a type has multiple trait bounds.
- Derive order: standard traits, then comparison traits, then `Hash`, then `derive_more`, then feature-gated derives.
- For error types, only derive `Display` and `Error` from `derive_more` when each is actually needed. Not all displayable types are errors.
- Minimize `unwrap()` in non-test code. Use proper error handling instead.
- Prefer `#[cfg_attr(..., ignore = "reason")]` over `#[cfg(...)]` when skipping tests. Use `#[cfg]` on tests only when the code cannot compile under the condition, such as when it references types or functions that do not exist on other platforms.
Expand Down
4 changes: 2 additions & 2 deletions tests/cli_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ fn fs_errors() {
.map(|line| line.trim_start_matches('\r'))
.collect();
let expected_stderr_lines = btreeset! {
"[error] read_dir \"./nested/0\": Permission denied (os error 13)",
"[error] read_dir \"./empty-dir\": Permission denied (os error 13)",
r#"[error] read_dir "./nested/0": Permission denied (os error 13)"#,
r#"[error] read_dir "./empty-dir": Permission denied (os error 13)"#,
};
assert_eq!(actual_stderr_lines, expected_stderr_lines);

Expand Down
Loading