From 4e11527ccd02830d8a44566b10b8aa5bfa079736 Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 10:37:52 -0300 Subject: [PATCH 1/8] chore: migrate to clap 4.x --- Cargo.toml | 2 +- src/main.rs | 46 +++++++++++++--------------------------------- src/tuning.rs | 7 +++---- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6175401..5bad810 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ rust-version = "1.74" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = {version = "3.2", features = ["derive"]} +clap = {version = "4.3", features = ["derive"] } itertools = "0.10" lazy_static = "1.4" petgraph = "0.6" diff --git a/src/main.rs b/src/main.rs index 34cb869..b8b0ebc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,9 +26,9 @@ lazy_static! { #[derive(Parser)] struct Ukebox { /// Type of tuning to be used - #[clap(short, long, global = true, value_name = "TUNING", default_value = &TUNING_STR, arg_enum)] + #[arg(short, long, global = true, value_name = "TUNING", default_value = &**TUNING_STR, value_enum)] tuning: Tuning, - #[clap(subcommand)] + #[command(subcommand)] cmd: Subcommand, } @@ -43,29 +43,29 @@ enum Subcommand { /// Add 'b' for flat notes, e.g. Eb. /// /// Run "ukebox chords" to get a list of the chord types and symbols currently supported. - #[clap(verbatim_doc_comment)] + #[command(verbatim_doc_comment)] Chart { /// Print out all voicings of that fulfill the given conditions - #[clap(short, long)] + #[arg(short, long)] all: bool, - #[clap(flatten)] + #[command(flatten)] voicing_opts: VoicingOpts, /// Name of the chord to be shown - #[clap(value_name = "CHORD")] + #[arg(value_name = "CHORD")] chord: Chord, }, /// Chord name lookup Name { /// A compact chart representing the finger positions of the chord to be looked up - #[clap(value_name = "FRET_PATTERN")] + #[arg(value_name = "FRET_PATTERN")] fret_pattern: FretPattern, }, /// Voice leading for a sequence of chords VoiceLead { - #[clap(flatten)] + #[command(flatten)] voicing_opts: VoicingOpts, /// Chord sequence - #[clap(value_name = "CHORD_SEQUENCE")] + #[arg(value_name = "CHORD_SEQUENCE")] chord_seq: ChordSequence, }, } @@ -73,16 +73,16 @@ enum Subcommand { #[derive(Parser)] pub struct VoicingOpts { /// Minimal fret (= minimal position) from which to play - #[clap(long, value_name = "FRET_ID", default_value = &MIN_FRET_STR, validator = validate_fret_id)] + #[arg(long, value_name = "FRET_ID", default_value = &**MIN_FRET_STR, value_parser = clap::value_parser!(FretID).range(0..=MAX_FRET_ID as i64))] min_fret: FretID, /// Maximal fret up to which to play - #[clap(long, value_name = "FRET_ID", default_value = &MAX_FRET_STR, validator = validate_fret_id)] + #[arg(long, value_name = "FRET_ID", default_value = &**MAX_FRET_STR, value_parser = clap::value_parser!(FretID).range(0..=MAX_FRET_ID as i64))] max_fret: FretID, /// Maximal span between the first and the last fret pressed down when playing - #[clap(long, value_name = "FRET_COUNT", default_value = &MAX_SPAN_STR, validator = validate_span)] + #[arg(long, value_name = "FRET_COUNT", default_value = &**MAX_SPAN_STR, value_parser = clap::value_parser!(Semitones).range(0..=MAX_SPAN as i64))] max_span: Semitones, /// Number of semitones to add (e.g. 1, +1) or to subtract (e.g. -1) - #[clap( + #[arg( long, value_name = "SEMITONES", allow_hyphen_values = true, @@ -91,26 +91,6 @@ pub struct VoicingOpts { transpose: i8, } -fn validate_fret_id(s: &str) -> Result<(), String> { - if let Ok(fret) = s.parse::() { - if fret <= MAX_FRET_ID { - return Ok(()); - } - } - - Err(String::from("must be a number between 0 and 21")) -} - -fn validate_span(s: &str) -> Result<(), String> { - if let Ok(span) = s.parse::() { - if span <= MAX_SPAN { - return Ok(()); - } - } - - Err(String::from("must be a number between 0 and 5")) -} - fn main() { let args = Ukebox::parse(); let tuning = args.tuning; diff --git a/src/tuning.rs b/src/tuning.rs index f0d9f29..e034cd8 100644 --- a/src/tuning.rs +++ b/src/tuning.rs @@ -1,14 +1,13 @@ use std::fmt; use std::str::FromStr; -use clap; -use clap::ArgEnum; +use clap::ValueEnum; use crate::{Interval, Note, Semitones}; -// Using clap's `arg_enum` macro allows the specification of all Tuning +// Using clap's `value_enum` macro allows the specification of all Tuning // variants as `possible_values` for the CLI `--tuning` option. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ArgEnum)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] #[clap(rename_all = "UPPER")] pub enum Tuning { C, From 9be18d4b620aa008cb6a92784276f0676c21c420 Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 10:52:30 -0300 Subject: [PATCH 2/8] refactor: use thiserror for simplifying defining errors --- Cargo.toml | 1 + src/chord.rs | 19 ++++++------------- src/chord_sequence.rs | 10 +++++++--- src/chord_type.rs | 15 +++++++++++---- src/fret_pattern.rs | 22 +++++----------------- src/interval.rs | 10 ++-------- src/lib.rs | 1 + src/note.rs | 9 ++------- 8 files changed, 35 insertions(+), 52 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5bad810..6ba7ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ clap = {version = "4.3", features = ["derive"] } itertools = "0.10" lazy_static = "1.4" petgraph = "0.6" +thiserror = "1.0.58" [dev-dependencies] assert_cmd = "2.0" diff --git a/src/chord.rs b/src/chord.rs index f9cf87d..50e55a6 100644 --- a/src/chord.rs +++ b/src/chord.rs @@ -1,5 +1,4 @@ use std::convert::TryFrom; -use std::error::Error; use std::fmt; use std::ops::{Add, Sub}; use std::str::FromStr; @@ -7,23 +6,17 @@ use std::str::FromStr; use itertools::Itertools; use crate::{ - ChordType, Note, PitchClass, Semitones, UkeString, Voicing, VoicingConfig, STRING_COUNT, + ChordType, NoMatchingChordTypeFoundError, Note, PitchClass, Semitones, UkeString, Voicing, + VoicingConfig, STRING_COUNT, }; /// Custom error for strings that cannot be parsed into chords. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("could not parse chord name '{name}'")] pub struct ParseChordError { name: String, } -impl Error for ParseChordError {} - -impl fmt::Display for ParseChordError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Could not parse chord name \"{}\"", self.name) - } -} - /// A chord such as C, Cm and so on. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Chord { @@ -122,7 +115,7 @@ impl FromStr for Chord { } impl TryFrom<&[PitchClass]> for Chord { - type Error = &'static str; + type Error = NoMatchingChordTypeFoundError; /// Determine the chord that is represented by a list of pitch classes. fn try_from(pitches: &[PitchClass]) -> Result { @@ -167,7 +160,7 @@ mod tests { case("CmMaj7b5") )] fn test_from_str_fail(chord: &str) { - assert!(Chord::from_str(chord).is_err()) + assert!(Chord::from_str(chord).is_err()); } #[rstest( diff --git a/src/chord_sequence.rs b/src/chord_sequence.rs index f5ec01c..c8a5920 100644 --- a/src/chord_sequence.rs +++ b/src/chord_sequence.rs @@ -19,8 +19,12 @@ impl ChordSequence { } } +#[derive(Debug, thiserror::Error)] +#[error("could not parse chord sequence")] +pub struct ParseChordSequenceError; + impl FromStr for ChordSequence { - type Err = &'static str; + type Err = ParseChordSequenceError; fn from_str(s: &str) -> Result { let res: Result, _> = s.split_whitespace().map(Chord::from_str).collect(); @@ -29,7 +33,7 @@ impl FromStr for ChordSequence { return Ok(Self { chords }); } - Err("Could not parse chord sequence") + Err(ParseChordSequenceError) } } @@ -55,7 +59,7 @@ mod tests { #[rstest(chord_seq, case("Z"), case("A Z"))] fn test_from_str_fail(chord_seq: &str) { - assert!(ChordSequence::from_str(chord_seq).is_err()) + assert!(ChordSequence::from_str(chord_seq).is_err()); } #[rstest( diff --git a/src/chord_type.rs b/src/chord_type.rs index c60304d..cce4a0d 100644 --- a/src/chord_type.rs +++ b/src/chord_type.rs @@ -291,18 +291,25 @@ impl fmt::Display for ChordType { } } +#[derive(Debug)] +pub struct NoValidChordTypeError; + impl FromStr for ChordType { - type Err = &'static str; + type Err = NoValidChordTypeError; fn from_str(s: &str) -> Result { ChordType::values() .find(|ct| ct.symbols().any(|sym| sym == s)) - .ok_or("no valid chord type") + .ok_or(NoValidChordTypeError) } } +#[derive(Debug, thiserror::Error)] +#[error("no matching chord type found")] +pub struct NoMatchingChordTypeFoundError; + impl TryFrom<&[PitchClass]> for ChordType { - type Error = &'static str; + type Error = NoMatchingChordTypeFoundError; /// Determine the chord type from a list of pitch classes representing a chord. fn try_from(pitches: &[PitchClass]) -> Result { @@ -349,7 +356,7 @@ impl TryFrom<&[PitchClass]> for ChordType { } } - Err("No matching chord type found.") + Err(NoMatchingChordTypeFoundError) } } diff --git a/src/fret_pattern.rs b/src/fret_pattern.rs index b022007..c70aada 100644 --- a/src/fret_pattern.rs +++ b/src/fret_pattern.rs @@ -1,25 +1,13 @@ use std::convert::TryInto; -use std::error::Error; -use std::fmt; use std::slice::Iter; use std::str::FromStr; use crate::{FretID, STRING_COUNT}; /// Custom error for strings that cannot be parsed into a fret pattern. -#[derive(Debug)] -pub struct ParseFretPatternError {} - -impl Error for ParseFretPatternError {} - -impl fmt::Display for ParseFretPatternError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Fret pattern has wrong format (should be something like 1234 or \"7 8 9 10\")" - ) - } -} +#[derive(Debug, thiserror::Error)] +#[error("fret pattern has wrong format (should be something like 1234 or '7 8 9 10')")] +pub struct ParseFretPatternError; /// A pattern of frets to press down for playing a chord. /// Each index of the array corresponds to a ukulele string. @@ -62,7 +50,7 @@ impl FromStr for FretPattern { } } - Err(ParseFretPatternError {}) + Err(ParseFretPatternError) } } @@ -84,6 +72,6 @@ mod tests { #[rstest(s, case(""), case("Cm"), case("222"), case("22201"))] fn test_from_str_fail(s: &str) { - assert!(FretPattern::from_str(s).is_err()) + assert!(FretPattern::from_str(s).is_err()); } } diff --git a/src/interval.rs b/src/interval.rs index 0992899..7632995 100644 --- a/src/interval.rs +++ b/src/interval.rs @@ -1,20 +1,14 @@ -use std::fmt; use std::str::FromStr; use crate::{Semitones, StaffSteps}; /// Custom error for strings that cannot be parsed into intervals. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("could not parse interval name '{name}'")] pub struct ParseIntervalError { name: String, } -impl fmt::Display for ParseIntervalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Could not parse interval name \"{}\"", self.name) - } -} - /// An interval is the difference between two notes. /// https://en.wikipedia.org/wiki/Interval_(music) #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/lib.rs b/src/lib.rs index 5cb26b0..5ffe751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub use chord::Chord; pub use chord_chart::ChordChart; pub use chord_sequence::ChordSequence; pub use chord_type::ChordType; +pub use chord_type::NoMatchingChordTypeFoundError; pub use distance::Distance; pub use fingering::Fingering; pub use fret_pattern::FretPattern; diff --git a/src/note.rs b/src/note.rs index d83f9a9..b2562b1 100644 --- a/src/note.rs +++ b/src/note.rs @@ -5,17 +5,12 @@ use std::str::FromStr; use crate::{Interval, PitchClass, Semitones, StaffPosition}; /// Custom error for strings that cannot be parsed into notes. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("could not parse note name '{name}'")] pub struct ParseNoteError { name: String, } -impl fmt::Display for ParseNoteError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Could not parse note name \"{}\"", self.name) - } -} - /// A note such a C, C# and so on. #[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord)] pub struct Note { From 54f7b023cd21f530c74cd1248114c0a4777edb9b Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 11:15:26 -0300 Subject: [PATCH 3/8] feat: make ChordSequence clonable (required by clap) --- src/chord_sequence.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chord_sequence.rs b/src/chord_sequence.rs index c8a5920..5ec436d 100644 --- a/src/chord_sequence.rs +++ b/src/chord_sequence.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use crate::Chord; -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ChordSequence { chords: Vec, } From b99e4e707de8d370b04d27949268e6002c67283b Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 10:40:07 -0300 Subject: [PATCH 4/8] test: modify to highlight changes --- tests/ukebox.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tests/ukebox.rs b/tests/ukebox.rs index 040c956..2aef90d 100644 --- a/tests/ukebox.rs +++ b/tests/ukebox.rs @@ -11,7 +11,7 @@ fn test_no_args() -> Result<(), Box> { let mut cmd = Command::cargo_bin("ukebox")?; cmd.assert() .failure() - .stderr(predicate::str::contains("USAGE:")); + .stderr(predicate::str::contains("Usage:")); Ok(()) } @@ -22,7 +22,7 @@ fn test_unknown_chord() -> Result<(), Box> { cmd.arg("chart"); cmd.arg("blafoo"); cmd.assert().failure().stderr(predicate::str::contains( - "error: Invalid value \"blafoo\" for '': Could not parse chord name \"blafoo\"", + "error: invalid value 'blafoo' for '': could not parse chord name 'blafoo'", )); Ok(()) @@ -49,10 +49,7 @@ fn test_invalid_min_fret(min_fret: &str) -> Result<(), Box> { cmd.arg("C"); cmd.assert() .failure() - .stderr(predicate::str::contains(format!( - "error: Invalid value \"{}\" for '--min-fret ': must be a number between 0 and 21", - min_fret - ))); + .stderr(predicate::str::contains(format!("error: invalid value '{min_fret}' for '--min-fret ': 22 is not in 0..=21")).or(predicate::str::contains(format!("error: invalid value '{min_fret}' for '--min-fret ': invalid digit found in string")))); Ok(()) } @@ -65,10 +62,7 @@ fn test_invalid_max_fret(max_fret: &str) -> Result<(), Box> { cmd.arg("C"); cmd.assert() .failure() - .stderr(predicate::str::contains(format!( - "error: Invalid value \"{}\" for '--max-fret ': must be a number between 0 and 21", - max_fret - ))); + .stderr(predicate::str::contains(format!("error: invalid value '{max_fret}' for '--max-fret ': 22 is not in 0..=21")).or(predicate::str::contains(format!("error: invalid value '{max_fret}' for '--max-fret ': invalid digit found in string")))); Ok(()) } @@ -79,9 +73,9 @@ fn test_invalid_max_span(max_span: &str) -> Result<(), Box> { cmd.arg("chart"); cmd.arg("--max-span").arg(max_span); cmd.arg("C"); - cmd.assert().failure().stderr(predicate::str::contains( - format!("error: Invalid value \"{}\" for '--max-span ': must be a number between 0 and 5", max_span), - )); + cmd.assert() + .failure() + .stderr(predicate::str::contains(format!("error: invalid value '{max_span}' for '--max-span ': 6 is not in 0..=5")).or(predicate::str::contains(format!("error: invalid value '{max_span}' for '--max-span ': invalid digit found in string")))); Ok(()) } @@ -92,7 +86,7 @@ fn test_invalid_pattern() -> Result<(), Box> { cmd.arg("name"); cmd.arg("blafoo"); cmd.assert().failure().stderr(predicate::str::contains( - "error: Invalid value \"blafoo\" for '': Fret pattern has wrong format (should be something like 1234 or \"7 8 9 10\")", + "error: invalid value 'blafoo' for '': fret pattern has wrong format (should be something like 1234 or '7 8 9 10')", )); Ok(()) From 84ae212496ff8c6a4c15cd3eee23aa6c92a4347a Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 10:58:42 -0300 Subject: [PATCH 5/8] refactor: inline variable substitution in format! --- src/chord.rs | 70 +++++++++++++++++++++++----------------------- src/chord_chart.rs | 6 ++-- src/chord_type.rs | 2 +- src/main.rs | 14 +++++----- src/note.rs | 4 +-- src/tuning.rs | 2 +- tests/ukebox.rs | 18 ++++++------ 7 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/chord.rs b/src/chord.rs index 50e55a6..44357f7 100644 --- a/src/chord.rs +++ b/src/chord.rs @@ -85,7 +85,7 @@ impl Chord { impl fmt::Display for Chord { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let name = format!("{}{}", self.root, self.chord_type.to_symbol()); - write!(f, "{} - {} {}", name, self.root, self.chord_type) + write!(f, "{name} - {} {}", self.root, self.chord_type) } } @@ -193,7 +193,7 @@ mod tests { third: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth]); assert_eq!(chord.chord_type, ChordType::Major); @@ -231,7 +231,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::MajorSeventh); @@ -271,7 +271,7 @@ mod tests { seventh: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh, ninth]); assert_eq!(chord.chord_type, ChordType::MajorNinth); @@ -313,7 +313,7 @@ mod tests { ninth: Note, eleventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -360,7 +360,7 @@ mod tests { eleventh: Note, thirteenth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -401,7 +401,7 @@ mod tests { fifth: Note, sixth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, sixth]); assert_eq!(chord.chord_type, ChordType::MajorSixth); @@ -441,7 +441,7 @@ mod tests { sixth: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, sixth, ninth]); assert_eq!(chord.chord_type, ChordType::SixthNinth); @@ -479,7 +479,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::DominantSeventh); @@ -519,7 +519,7 @@ mod tests { seventh: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh, ninth]); assert_eq!(chord.chord_type, ChordType::DominantNinth); @@ -561,7 +561,7 @@ mod tests { ninth: Note, eleventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -608,7 +608,7 @@ mod tests { eleventh: Note, thirteenth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -651,7 +651,7 @@ mod tests { seventh: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh, ninth]); assert_eq!(chord.chord_type, ChordType::DominantSeventhFlatNinth); @@ -691,7 +691,7 @@ mod tests { seventh: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh, ninth]); assert_eq!(chord.chord_type, ChordType::DominantSeventhSharpNinth); @@ -729,7 +729,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::DominantSeventhFlatFifth); @@ -765,7 +765,7 @@ mod tests { fourth: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, fourth, fifth]); assert_eq!(chord.chord_type, ChordType::SuspendedFourth); @@ -801,7 +801,7 @@ mod tests { second: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, second, fifth]); assert_eq!(chord.chord_type, ChordType::SuspendedSecond); @@ -839,7 +839,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, fourth, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::DominantSeventhSuspendedFourth); @@ -877,7 +877,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, second, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::DominantSeventhSuspendedSecond); @@ -913,7 +913,7 @@ mod tests { third: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth]); assert_eq!(chord.chord_type, ChordType::Minor); @@ -951,7 +951,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::MinorSeventh); @@ -989,7 +989,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::MinorMajorSeventh); @@ -1027,7 +1027,7 @@ mod tests { fifth: Note, sixth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, sixth]); assert_eq!(chord.chord_type, ChordType::MinorSixth); @@ -1067,7 +1067,7 @@ mod tests { seventh: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh, ninth]); assert_eq!(chord.chord_type, ChordType::MinorNinth); @@ -1109,7 +1109,7 @@ mod tests { ninth: Note, eleventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -1156,7 +1156,7 @@ mod tests { eleventh: Note, thirteenth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!( chord.notes, @@ -1195,7 +1195,7 @@ mod tests { third: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth]); assert_eq!(chord.chord_type, ChordType::Diminished); @@ -1233,7 +1233,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::DiminishedSeventh); @@ -1271,7 +1271,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::HalfDiminishedSeventh); @@ -1305,7 +1305,7 @@ mod tests { root: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, fifth]); assert_eq!(chord.chord_type, ChordType::Fifth); @@ -1341,7 +1341,7 @@ mod tests { third: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth]); assert_eq!(chord.chord_type, ChordType::Augmented); @@ -1379,7 +1379,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::AugmentedSeventh); @@ -1417,7 +1417,7 @@ mod tests { fifth: Note, seventh: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, seventh]); assert_eq!(chord.chord_type, ChordType::AugmentedMajorSeventh); @@ -1455,7 +1455,7 @@ mod tests { fifth: Note, ninth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fifth, ninth]); assert_eq!(chord.chord_type, ChordType::AddedNinth); @@ -1493,7 +1493,7 @@ mod tests { fourth: Note, fifth: Note, ) { - let chord = Chord::from_str(&format!("{}{}", chord_base, chord_suffix)).unwrap(); + let chord = Chord::from_str(&format!("{chord_base}{chord_suffix}")).unwrap(); assert_eq!(chord.notes, vec![root, third, fourth, fifth]); assert_eq!(chord.chord_type, ChordType::AddedFourth); diff --git a/src/chord_chart.rs b/src/chord_chart.rs index 2cd5cf9..428b51e 100644 --- a/src/chord_chart.rs +++ b/src/chord_chart.rs @@ -82,7 +82,7 @@ impl ChordChart { output }); - format!("{} {}{}{}- {}\n", root_str, sym, nut, s, note) + format!("{root_str} {sym}{nut}{s}- {note}\n") } } @@ -109,10 +109,10 @@ impl fmt::Display for ChordChart { // If the fretboard section shown does not include the nut, // indicate the number of the first fret shown. if base_fret > 1 { - return writeln!(f, "{}{:width$}", s, base_fret, width = root_width + 6); + return writeln!(f, "{s}{base_fret:width$}", width = root_width + 6); } - write!(f, "{}", s) + write!(f, "{s}") } } diff --git a/src/chord_type.rs b/src/chord_type.rs index cce4a0d..c799e79 100644 --- a/src/chord_type.rs +++ b/src/chord_type.rs @@ -287,7 +287,7 @@ impl fmt::Display for ChordType { AddedFourth => "added 4th", }; - write!(f, "{}", s) + write!(f, "{s}") } } diff --git a/src/main.rs b/src/main.rs index b8b0ebc..ab82ef3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,8 +101,8 @@ fn main() { println!("The root note C is used as an example.\n"); for chord_type in ChordType::values() { - let symbols = chord_type.symbols().map(|s| format!("C{}", s)).join(", "); - println!("C {} - {}", chord_type, symbols); + let symbols = chord_type.symbols().map(|s| format!("C{s}")).join(", "); + println!("C {chord_type} - {symbols}"); } } Subcommand::Chart { @@ -124,12 +124,12 @@ fn main() { if voicings.peek().is_none() { println!("No matching chord voicing was found"); } else { - println!("[{}]\n", chord); + println!("[{chord}]\n"); } for voicing in voicings { let chart = ChordChart::new(voicing, voicing_opts.max_span); - println!("{}", chart); + println!("{chart}"); if !all { break; @@ -145,7 +145,7 @@ fn main() { } for chord in chords { - println!("{}", chord); + println!("{chord}"); } } Subcommand::VoiceLead { @@ -168,9 +168,9 @@ fn main() { for (path, _dist) in voicing_graph.paths(1) { for (chord, voicing) in chord_seq.chords().zip(path.iter()) { - println!("[{}]\n", chord); + println!("[{chord}]\n"); let chart = ChordChart::new(*voicing, voicing_opts.max_span); - println!("{}", chart); + println!("{chart}"); } //println!("{:?}\n", dist); //println!("---------------------------\n"); diff --git a/src/note.rs b/src/note.rs index b2562b1..a4762ff 100644 --- a/src/note.rs +++ b/src/note.rs @@ -94,7 +94,7 @@ impl fmt::Display for Note { _ => panic!("Impossible combination of PitchClass and StaffPosition"), }; - write!(f, "{}", s) + write!(f, "{s}") } } @@ -235,7 +235,7 @@ mod tests { )] fn test_from_and_to_str(s: &str) { let note = Note::from_str(s).unwrap(); - assert_eq!(format!("{}", note), s); + assert_eq!(format!("{note}"), s); } #[rstest( diff --git a/src/tuning.rs b/src/tuning.rs index e034cd8..56fb238 100644 --- a/src/tuning.rs +++ b/src/tuning.rs @@ -49,6 +49,6 @@ impl fmt::Display for Tuning { Tuning::G => "G", }; - write!(f, "{}", s) + write!(f, "{s}") } } diff --git a/tests/ukebox.rs b/tests/ukebox.rs index 2aef90d..17939fa 100644 --- a/tests/ukebox.rs +++ b/tests/ukebox.rs @@ -157,7 +157,7 @@ fn test_no_voicing_seq_found() -> Result<(), Box> { fn test_chart(chord: &str, chart: &'static str) -> Result<(), Box> { let mut cmd = Command::cargo_bin("ukebox")?; cmd.arg("chart").arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -212,7 +212,7 @@ fn test_tuning( cmd.arg("chart"); cmd.arg("--tuning").arg(tuning); cmd.arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -270,7 +270,7 @@ fn test_min_fret( cmd.arg("chart"); cmd.arg("--min-fret").arg(min_fret); cmd.arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -314,7 +314,7 @@ fn test_max_span( cmd.arg("chart"); cmd.arg("--max-span").arg(max_span); cmd.arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -381,7 +381,7 @@ fn test_transpose( cmd.arg("chart"); cmd.arg("--transpose").arg(semitones); cmd.arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -524,7 +524,7 @@ fn test_all( } cmd.arg(chord); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } @@ -542,7 +542,7 @@ fn test_all( fn test_name(chart: &str, names: &'static str) -> Result<(), Box> { let mut cmd = Command::cargo_bin("ukebox")?; cmd.arg("name").arg(chart); - cmd.assert().success().stdout(format!("{}\n", names)); + cmd.assert().success().stdout(format!("{names}\n")); Ok(()) } @@ -567,7 +567,7 @@ fn test_name_with_tuning( cmd.arg("name"); cmd.arg("--tuning").arg(tuning); cmd.arg(chart); - cmd.assert().success().stdout(format!("{}\n", names)); + cmd.assert().success().stdout(format!("{names}\n")); Ok(()) } @@ -698,7 +698,7 @@ fn test_voice_lead( cmd.arg(arg).arg(value); } cmd.arg(chord_seq); - cmd.assert().success().stdout(format!("{}\n", chart)); + cmd.assert().success().stdout(format!("{chart}\n")); Ok(()) } From eda30a16df8ec04127ad3713ff1d25bb40eac90a Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 11:04:13 -0300 Subject: [PATCH 6/8] refactor: use Self when able --- src/chord.rs | 2 +- src/chord_sequence.rs | 2 +- src/chord_type.rs | 6 +++--- src/distance.rs | 4 ++-- src/fingering.rs | 2 +- src/tuning.rs | 6 +++--- src/voicing.rs | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/chord.rs b/src/chord.rs index 44357f7..8036dc6 100644 --- a/src/chord.rs +++ b/src/chord.rs @@ -74,7 +74,7 @@ impl Chord { .sorted() } - pub fn transpose(&self, semitones: i8) -> Chord { + pub fn transpose(&self, semitones: i8) -> Self { match semitones { s if s < 0 => self.clone() - semitones.unsigned_abs() as Semitones, _ => self.clone() + semitones as Semitones, diff --git a/src/chord_sequence.rs b/src/chord_sequence.rs index 5ec436d..f49d254 100644 --- a/src/chord_sequence.rs +++ b/src/chord_sequence.rs @@ -13,7 +13,7 @@ impl ChordSequence { self.chords.iter() } - pub fn transpose(&self, semitones: i8) -> ChordSequence { + pub fn transpose(&self, semitones: i8) -> Self { let chords = self.chords().map(|c| c.transpose(semitones)).collect(); Self { chords } } diff --git a/src/chord_type.rs b/src/chord_type.rs index c799e79..0911848 100644 --- a/src/chord_type.rs +++ b/src/chord_type.rs @@ -65,7 +65,7 @@ impl ChordType { /// /// Unfortunately, we have to list them all and make sure to update /// this list if a value is added or removed. - pub fn values() -> impl Iterator { + pub fn values() -> impl Iterator { use ChordType::*; [ @@ -298,7 +298,7 @@ impl FromStr for ChordType { type Err = NoValidChordTypeError; fn from_str(s: &str) -> Result { - ChordType::values() + Self::values() .find(|ct| ct.symbols().any(|sym| sym == s)) .ok_or(NoValidChordTypeError) } @@ -328,7 +328,7 @@ impl TryFrom<&[PitchClass]> for ChordType { } }; - for chord_type in ChordType::values() { + for chord_type in Self::values() { // If a chord has less required intervals than we have strings, add optional intervals // until all strings are used. let min_len = min(chord_type.intervals().count(), STRING_COUNT); diff --git a/src/distance.rs b/src/distance.rs index 61ef9e3..258906a 100644 --- a/src/distance.rs +++ b/src/distance.rs @@ -23,8 +23,8 @@ impl Distance { impl Add for Distance { type Output = Self; - fn add(self, other: Distance) -> Self { - Distance(self.0 + other.0, self.1 + other.1) + fn add(self, other: Self) -> Self { + Self(self.0 + other.0, self.1 + other.1) } } diff --git a/src/fingering.rs b/src/fingering.rs index 380d405..ae28200 100644 --- a/src/fingering.rs +++ b/src/fingering.rs @@ -10,7 +10,7 @@ pub struct Fingering { impl Fingering { /// Compute the distance between two fingerings, inspired by /// http://www.petecorey.com/blog/2018/08/27/computing-fingering-distance-with-dr-levenshtein/ - pub fn distance(&self, other: Fingering) -> u8 { + pub fn distance(&self, other: Self) -> u8 { let dist = |(&(s1, f1), &(s2, f2))| { let add = s1 == 0 && s2 != 0; let remove = s1 != 0 && s2 == 0; diff --git a/src/tuning.rs b/src/tuning.rs index 56fb238..c2086d6 100644 --- a/src/tuning.rs +++ b/src/tuning.rs @@ -44,9 +44,9 @@ impl Tuning { impl fmt::Display for Tuning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { - Tuning::C => "C", - Tuning::D => "D", - Tuning::G => "G", + Self::C => "C", + Self::D => "D", + Self::G => "G", }; write!(f, "{s}") diff --git a/src/voicing.rs b/src/voicing.rs index 5c58938..370b80d 100644 --- a/src/voicing.rs +++ b/src/voicing.rs @@ -226,21 +226,21 @@ impl Voicing { /// It's computed by simply summing up the distances between the frets that /// are pressed down on the same string when moving from one voicing to the other. /// Inspired by http://www.petecorey.com/blog/2018/07/30/voice-leading-with-elixir/ - pub fn semitone_distance(&self, other: Voicing) -> u8 { + pub fn semitone_distance(&self, other: Self) -> u8 { self.frets() .zip(other.frets()) .map(|(f1, f2)| max(f1, f2) - min(f1, f2)) .sum() } - pub fn fingering_distance(&self, other: Voicing) -> u8 { + pub fn fingering_distance(&self, other: Self) -> u8 { let l_fingering = Fingering::from(*self); let r_fingering = Fingering::from(other); l_fingering.distance(r_fingering) } - pub fn distance(&self, other: Voicing) -> Distance { + pub fn distance(&self, other: Self) -> Distance { let semitone_distance = self.semitone_distance(other); let fingering_distance = self.fingering_distance(other); From 07a39044c897517f1ed3e295dda95f3c4ab6a2e5 Mon Sep 17 00:00:00 2001 From: "Felipe S. S. Schneider" Date: Sat, 30 Mar 2024 11:23:39 -0300 Subject: [PATCH 7/8] test: remove CLI validation (= trust clap) --- tests/ukebox.rs | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/tests/ukebox.rs b/tests/ukebox.rs index 17939fa..0d29b2b 100644 --- a/tests/ukebox.rs +++ b/tests/ukebox.rs @@ -41,45 +41,6 @@ fn test_no_voicing_found() -> Result<(), Box> { Ok(()) } -#[rstest(min_fret, case("22"), case("foo"))] -fn test_invalid_min_fret(min_fret: &str) -> Result<(), Box> { - let mut cmd = Command::cargo_bin("ukebox")?; - cmd.arg("chart"); - cmd.arg("--min-fret").arg(min_fret); - cmd.arg("C"); - cmd.assert() - .failure() - .stderr(predicate::str::contains(format!("error: invalid value '{min_fret}' for '--min-fret ': 22 is not in 0..=21")).or(predicate::str::contains(format!("error: invalid value '{min_fret}' for '--min-fret ': invalid digit found in string")))); - - Ok(()) -} - -#[rstest(max_fret, case("22"), case("foo"))] -fn test_invalid_max_fret(max_fret: &str) -> Result<(), Box> { - let mut cmd = Command::cargo_bin("ukebox")?; - cmd.arg("chart"); - cmd.arg("--max-fret").arg(max_fret); - cmd.arg("C"); - cmd.assert() - .failure() - .stderr(predicate::str::contains(format!("error: invalid value '{max_fret}' for '--max-fret ': 22 is not in 0..=21")).or(predicate::str::contains(format!("error: invalid value '{max_fret}' for '--max-fret ': invalid digit found in string")))); - - Ok(()) -} - -#[rstest(max_span, case("6"), case("foo"))] -fn test_invalid_max_span(max_span: &str) -> Result<(), Box> { - let mut cmd = Command::cargo_bin("ukebox")?; - cmd.arg("chart"); - cmd.arg("--max-span").arg(max_span); - cmd.arg("C"); - cmd.assert() - .failure() - .stderr(predicate::str::contains(format!("error: invalid value '{max_span}' for '--max-span ': 6 is not in 0..=5")).or(predicate::str::contains(format!("error: invalid value '{max_span}' for '--max-span ': invalid digit found in string")))); - - Ok(()) -} - #[test] fn test_invalid_pattern() -> Result<(), Box> { let mut cmd = Command::cargo_bin("ukebox")?; From b427f33baf743f9c97b199a336a8d9bcff96f82c Mon Sep 17 00:00:00 2001 From: Anett Seeker Date: Wed, 8 May 2024 21:17:01 +0200 Subject: [PATCH 8/8] chore: update Cargo.lock --- Cargo.lock | 297 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 181 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 646bf7a..c3697c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,55 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "assert_cmd" version = "2.0.4" @@ -25,29 +74,12 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bstr" version = "0.2.17" @@ -67,42 +99,49 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.5" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "indexmap", - "once_cell", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.5" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.61", ] [[package]] name = "clap_lex" -version = "0.2.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613" -dependencies = [ - "os_str_bytes", -] +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "difflib" @@ -145,18 +184,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" @@ -174,6 +204,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -216,18 +252,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "once_cell" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" - -[[package]] -name = "os_str_bytes" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" - [[package]] name = "petgraph" version = "0.6.2" @@ -268,44 +292,20 @@ dependencies = [ "termtree", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.32" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -343,7 +343,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.82", ] [[package]] @@ -363,9 +363,9 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -379,12 +379,14 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "syn" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ - "winapi-util", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] @@ -394,10 +396,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] -name = "textwrap" -version = "0.15.0" +name = "thiserror" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] [[package]] name = "ukebox" @@ -411,8 +427,15 @@ dependencies = [ "petgraph", "predicates", "rstest", + "thiserror", ] +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -420,10 +443,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "version_check" -version = "0.9.3" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "wait-timeout" @@ -435,32 +458,74 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-targets", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-targets" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] [[package]] -name = "winapi-util" -version = "0.1.5" +name = "windows_aarch64_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"