Skip to content

Commit da12f9b

Browse files
committed
release: 0.6.6
2 parents 0f6d5d8 + a8ca1be commit da12f9b

File tree

8 files changed

+249
-202
lines changed

8 files changed

+249
-202
lines changed

CREDITS.md

Lines changed: 71 additions & 65 deletions
Large diffs are not rendered by default.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cargo-bashman"
3-
version = "0.6.5"
3+
version = "0.6.6"
44
license = "WTFPL"
55
authors = ["Josh Stoik <[email protected]>"]
66
edition = "2021"

release/man/cargo-bashman.1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
.TH "CARGO BASHMAN" "1" "November 2024" "cargo\-bashman v0.6.5" "User Commands"
1+
.TH "CARGO BASHMAN" "1" "November 2024" "cargo\-bashman v0.6.6" "User Commands"
22
.SH NAME
3-
CARGO BASHMAN \- Manual page for cargo\-bashman v0.6.5.
3+
CARGO BASHMAN \- Manual page for cargo\-bashman v0.6.6.
44
.SH DESCRIPTION
55
A Cargo plugin to generate bash completions, man pages, and/or crate credits.
66
.SS USAGE:

skel/metadata.credits

Lines changed: 75 additions & 69 deletions
Large diffs are not rendered by default.

src/credits.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,27 +83,28 @@ impl<'a> fmt::Display for CreditsWriter<'a> {
8383
}
8484

8585
// There may not be any dependencies.
86-
if self.dependencies.is_empty() {
86+
let Some(last) = self.dependencies.last() else {
8787
return f.write_str("This project has no dependencies.\n");
88+
};
89+
90+
// Print a header and each dependency.
91+
f.write_str("| Package | Version | Author(s) | License |\n| ---- | ---- | ---- | ---- |\n")?;
92+
let mut build = false;
93+
let mut children = false;
94+
for dep in self.dependencies {
95+
if dep.build() { build = true; }
96+
if ! dep.direct() { children = true; }
97+
writeln!(f, "{dep}")?;
8898
}
8999

90-
// Some dependencies are context dependent; some work is required.
91-
if self.dependencies.iter().any(Dependency::conditional) {
92-
f.write_str("| Package | Version | Author(s) | License | Context |\n| ---- | ---- | ---- | ---- | ---- |\n")?;
93-
94-
// Required first.
95-
for dep in self.dependencies {
96-
if ! dep.conditional() { writeln!(f, "{dep} |")?; }
97-
}
98-
// Now the specific ones.
99-
for dep in self.dependencies {
100-
if dep.conditional() { writeln!(f, "{dep} {} |", dep.context())?; }
100+
// If we have contexts, note them.
101+
if build || children || last.conditional() {
102+
f.write_str("\n### Legend\n\n")?;
103+
if children {
104+
f.write_str("* **Direct Dependency**\n* Child Dependency\n")?;
101105
}
102-
}
103-
// Everything is needed all the time!
104-
else {
105-
f.write_str("| Package | Version | Author(s) | License |\n| ---- | ---- | ---- | ---- |\n")?;
106-
for dep in self.dependencies { writeln!(f, "{dep}")?; }
106+
if last.conditional() { f.write_str("* _Optional Dependency_\n")?; }
107+
if build { f.write_str("* ⚒️ Build-Only\n")?; }
107108
}
108109

109110
Ok(())

src/parse/cargo.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,9 @@ impl From<RawCredits> for Dependency {
666666
license: src.license,
667667
authors: src.authors,
668668
url: src.repository.map(String::from),
669-
context: if src.optional { Self::FLAG_OPTIONAL } else { 0 },
669+
context:
670+
if src.optional { Self::FLAG_DIRECT | Self::FLAG_OPTIONAL }
671+
else { Self::FLAG_DIRECT },
670672
}
671673
}
672674
}
@@ -1110,8 +1112,8 @@ fn prune_resolve<'a>(resolve: &'a mut RawResolve, mut used: HashSet<&'a str>) {
11101112

11111113
// And with that, let's remove all unused node chains entirely.
11121114
resolve.nodes.retain(|k, _| used.contains(k));
1113-
for deps in resolve.nodes.values_mut() {
1114-
deps.retain(|nd| used.contains(nd.id));
1115+
for v in resolve.nodes.values_mut() {
1116+
v.retain(|nd| used.contains(nd.id));
11151117
}
11161118

11171119
// Now let's do something similar, this time building up a list of "normal"
@@ -1163,6 +1165,13 @@ fn prune_resolve<'a>(resolve: &'a mut RawResolve, mut used: HashSet<&'a str>) {
11631165
}
11641166
}
11651167
}
1168+
1169+
// Lastly, let's mark direct dependencies.
1170+
if let Some(v) = resolve.nodes.get_mut(resolve.root) {
1171+
for nd in v {
1172+
nd.dep_kinds |= Dependency::FLAG_DIRECT;
1173+
}
1174+
}
11661175
}
11671176

11681177

src/parse/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ impl Manifest {
7777
// Abosrb the extra credits into the real dependencies.
7878
deps.extend(credits);
7979

80+
// Collect into a vec and resort, pushing conditional dependencies to
81+
// the end of the list.
82+
let mut dependencies: Vec<Dependency> = deps.into_iter().collect();
83+
dependencies.sort_by(|a, b| {
84+
let a_cond = a.conditional();
85+
let b_cond = b.conditional();
86+
87+
if a_cond == b_cond { a.cmp(b) }
88+
else if a_cond { Ordering::Greater }
89+
else { Ordering::Less }
90+
});
91+
8092
// Finally!
8193
Ok(Self {
8294
src,
@@ -86,7 +98,7 @@ impl Manifest {
8698
dir,
8799
subcommands,
88100
target,
89-
dependencies: deps.into_iter().collect(),
101+
dependencies,
90102
})
91103
}
92104

src/parse/pkg.rs

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,24 @@ impl PartialOrd for Dependency {
6767
}
6868

6969
impl Dependency {
70+
/// # Direct Dependency.
71+
pub(super) const FLAG_DIRECT: u8 = 0b0000_0001;
72+
7073
/// # Feature-Specific.
71-
pub(super) const FLAG_OPTIONAL: u8 = 0b0000_0001;
74+
pub(super) const FLAG_OPTIONAL: u8 = 0b0000_0010;
7275

7376
/// # Not Target-Specific.
74-
pub(super) const FLAG_TARGET_ANY: u8 = 0b0000_0010;
77+
pub(super) const FLAG_TARGET_ANY: u8 = 0b0000_0100;
7578

7679
/// # Target-Specific.
77-
pub(super) const FLAG_TARGET_CFG: u8 = 0b0000_0100;
80+
pub(super) const FLAG_TARGET_CFG: u8 = 0b0000_1000;
7881

7982
/// # Normal Context.
80-
pub(super) const FLAG_CTX_NORMAL: u8 = 0b0000_1000;
83+
pub(super) const FLAG_CTX_NORMAL: u8 = 0b0001_0000;
8184

8285
/// # Build Context.
83-
pub(super) const FLAG_CTX_BUILD: u8 = 0b0001_0000;
86+
pub(super) const FLAG_CTX_BUILD: u8 = 0b0010_0000;
87+
8488

8589
/// # Context Flags.
8690
pub(super) const MASK_CTX: u8 =
@@ -108,6 +112,11 @@ impl Dependency {
108112
/// # Repository URL.
109113
pub(super) fn url(&self) -> Option<&str> { self.url.as_deref() }
110114

115+
/// # Direct?
116+
pub(crate) const fn direct(&self) -> bool {
117+
Self::FLAG_DIRECT == self.context & Self::FLAG_DIRECT
118+
}
119+
111120
/// # Optional?
112121
pub(crate) const fn optional(&self) -> bool {
113122
Self::FLAG_OPTIONAL == self.context & Self::FLAG_OPTIONAL
@@ -127,53 +136,57 @@ impl Dependency {
127136
///
128137
/// Returns `true` if optional or target specific.
129138
pub(crate) const fn conditional(&self) -> bool {
130-
self.optional() || self.build() || self.target_specific()
131-
}
132-
133-
/// # Context Flags as String Slice.
134-
///
135-
/// Return a textual representation of the dependency's context(s). There
136-
/// are only a few combinations so this is pretty easy to construct
137-
/// manually.
138-
pub(crate) const fn context(&self) -> &'static str {
139-
match (self.optional(), self.build(), self.target_specific()) {
140-
(true, true, true) => "optional, build, target-specific",
141-
(true, true, false) => "optional, build",
142-
(true, false, true) => "optional, target-specific",
143-
(false, true, true) => "build, target-specific",
144-
(true, false, false) => "optional",
145-
(false, true, false) => "build",
146-
(false, false, true) => "target-specific",
147-
(false, false, false) => "",
148-
}
139+
self.optional() || self.target_specific()
149140
}
150141
}
151142

152143
impl fmt::Display for Dependency {
153144
/// # Write as Markdown.
154145
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155-
// The name as a link.
156-
if let Some(url) = self.url() {
157-
write!(
158-
f,
159-
"| [{}]({url}) | {} | {} | {} |",
160-
self.name,
161-
self.version,
162-
OxfordJoinFmt::and(self.authors()),
163-
self.license().unwrap_or(""),
164-
)
146+
#[expect(clippy::missing_docs_in_private_items, reason = "Self-Explanatory.")]
147+
/// # Name Formatter.
148+
///
149+
/// This will linkify the name if needed.
150+
struct FmtName<'a> {
151+
name: &'a str,
152+
open: &'a str,
153+
close: &'a str,
154+
url: Option<&'a str>,
165155
}
166-
// The name plain.
167-
else {
168-
write!(
169-
f,
170-
"| {} | {} | {} | {} |",
171-
self.name,
172-
self.version,
173-
OxfordJoinFmt::and(self.authors()),
174-
self.license().unwrap_or(""),
175-
)
156+
impl<'a> fmt::Display for FmtName<'a> {
157+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158+
if let Some(url) = self.url {
159+
write!(f, "[{}{}{}]({url})", self.open, self.name, self.close)
160+
}
161+
else {
162+
write!(f, "{}{}{}", self.open, self.name, self.close)
163+
}
164+
}
176165
}
166+
167+
// Contextual formatting tags.
168+
let (open, close) = match (self.direct(), self.conditional()) {
169+
(true, true) => ("**_", "_**"),
170+
(true, false) => ("**", "**"),
171+
(false, true) => ("_", "_"),
172+
(false, false) => ("", ""),
173+
};
174+
175+
// Build "asterisk".
176+
let asterisk = if self.build() { " ⚒️" } else { "" };
177+
178+
write!(
179+
f,
180+
"| {}{asterisk} | {} | {} | {} |",
181+
FmtName {
182+
name: self.name.as_str(),
183+
open, close,
184+
url: self.url(),
185+
},
186+
self.version,
187+
OxfordJoinFmt::and(self.authors()),
188+
self.license().unwrap_or(""),
189+
)
177190
}
178191
}
179192

0 commit comments

Comments
 (0)