summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcyqsimon <28627918+cyqsimon@users.noreply.github.com>2024-01-28 04:21:06 +0800
committerGitHub <noreply@github.com>2024-01-28 04:21:06 +0800
commitdc0468c8e72d2979a4daa167bfcd726501564ace (patch)
treea5348d074d7f2fcc3d12629fee398d2c6137edd0
parent592f733082d2e2b46c52f8bae822ee75c4c9fb62 (diff)
Generate completion & manpage (#357)
* Generate completion & manpage * Write changelog
-rw-r--r--CHANGELOG.md6
-rw-r--r--Cargo.lock27
-rw-r--r--Cargo.toml10
-rw-r--r--build.rs33
-rw-r--r--src/cli.rs24
-rw-r--r--src/display/components/display_bandwidth.rs33
-rw-r--r--src/display/ui.rs2
7 files changed, 111 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7a8623..50e080a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Unreleased]
+## [0.22.2] - 2024-01-28
+
+## Added
+
+* Generate completion & manpage #357 - @cyqsimon
+
## [0.22.1] - 2024-01-28
## Fixed
diff --git a/Cargo.lock b/Cargo.lock
index 029e70a..9750474 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -168,6 +168,8 @@ dependencies = [
"chrono",
"clap",
"clap-verbosity-flag",
+ "clap_complete",
+ "clap_mangen",
"crossterm",
"derivative",
"http_req",
@@ -341,6 +343,15 @@ dependencies = [
]
[[package]]
+name = "clap_complete"
+version = "4.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df631ae429f6613fcd3a7c1adbdb65f637271e561b03680adaa6573015dfb106"
+dependencies = [
+ "clap",
+]
+
+[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -359,6 +370,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
+name = "clap_mangen"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a7c2b01e5e779c19f46a94bbd398f33ae63b0f78c07108351fb4536845bb7fd"
+dependencies = [
+ "clap",
+ "roff",
+]
+
+[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1515,6 +1536,12 @@ dependencies = [
]
[[package]]
+name = "roff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
+
+[[package]]
name = "rstest"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3d02830..e795554 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -60,7 +60,15 @@ pnet_base = "0.34.0"
regex = "1.10.3"
rstest = "0.18.2"
-[target.'cfg(target_os = "windows")'.build-dependencies]
+[build-dependencies]
anyhow = "1.0.79"
+clap = { version = "4.4.18", features = ["derive"] }
+clap-verbosity-flag = "2.1.2"
+clap_complete = "4.4.9"
+clap_mangen = "0.2.17"
+derivative = "2.2.0"
+strum = { version = "0.25.0", features = ["derive"] }
+
+[target.'cfg(target_os = "windows")'.build-dependencies]
http_req = "0.10.2"
zip = "0.6.6"
diff --git a/build.rs b/build.rs
index d20e5b5..7481214 100644
--- a/build.rs
+++ b/build.rs
@@ -1,8 +1,41 @@
+use std::{env, fs::File};
+
+use anyhow::anyhow;
+use clap::CommandFactory;
+use clap_complete::Shell;
+use clap_mangen::Man;
+
fn main() {
+ build_completion_manpage().unwrap();
+
#[cfg(target_os = "windows")]
download_windows_npcap_sdk().unwrap();
}
+include!("src/cli.rs");
+
+fn build_completion_manpage() -> anyhow::Result<()> {
+ let mut cmd = Opt::command();
+
+ // build into `BANDWHICH_GEN_DIR` with a fallback to `OUT_DIR`
+ let gen_dir: PathBuf = env::var_os("BANDWHICH_GEN_DIR")
+ .or_else(|| env::var_os("OUT_DIR"))
+ .ok_or(anyhow!("OUT_DIR is unset"))?
+ .into();
+
+ // completion
+ for &shell in Shell::value_variants() {
+ clap_complete::generate_to(shell, &mut cmd, "bandwhich", &gen_dir)?;
+ }
+
+ // manpage
+ let mut manpage_out = File::create(gen_dir.join("bandwhich.1"))?;
+ let manpage = Man::new(cmd);
+ manpage.render(&mut manpage_out)?;
+
+ Ok(())
+}
+
#[cfg(target_os = "windows")]
fn download_windows_npcap_sdk() -> anyhow::Result<()> {
use std::{
diff --git a/src/cli.rs b/src/cli.rs
index 644a500..7a2fbc3 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,10 +1,9 @@
use std::{net::Ipv4Addr, path::PathBuf};
-use clap::{Args, Parser};
+use clap::{Args, Parser, ValueEnum, ValueHint};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use derivative::Derivative;
-
-use crate::display::BandwidthUnitFamily;
+use strum::EnumIter;
#[derive(Clone, Debug, Derivative, Parser)]
#[derivative(Default)]
@@ -30,7 +29,7 @@ pub struct Opt {
/// A dns server ip to use instead of the system default
pub dns_server: Option<Ipv4Addr>,
- #[arg(long)]
+ #[arg(long, value_hint = ValueHint::FilePath)]
/// Enable debug logging to a file
pub log_to: Option<PathBuf>,
@@ -58,9 +57,24 @@ pub struct RenderOpts {
#[arg(short, long, value_enum, default_value_t)]
/// Choose a specific family of units
- pub unit_family: BandwidthUnitFamily,
+ pub unit_family: UnitFamily,
#[arg(short, long)]
/// Show total (cumulative) usages
pub total_utilization: bool,
}
+
+// IMPRV: it would be nice if we can `#[cfg_attr(not(build), derive(strum::EnumIter))]` this
+// unfortunately there is no configuration option for build script detection
+#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, ValueEnum, EnumIter)]
+pub enum UnitFamily {
+ #[default]
+ /// bytes, in powers of 2^10
+ BinBytes,
+ /// bits, in powers of 2^10
+ BinBits,
+ /// bytes, in powers of 10^3
+ SiBytes,
+ /// bits, in powers of 10^3
+ SiBits,
+}
diff --git a/src/display/components/display_bandwidth.rs b/src/display/components/display_bandwidth.rs
index 5d7a510..bf2b526 100644
--- a/src/display/components/display_bandwidth.rs
+++ b/src/display/components/display_bandwidth.rs
@@ -1,7 +1,8 @@
use std::fmt;
-use clap::ValueEnum;
-use strum::EnumIter;
+use derivative::Derivative;
+
+use crate::cli::UnitFamily;
#[derive(Copy, Clone, Debug)]
pub struct DisplayBandwidth {
@@ -16,17 +17,14 @@ impl fmt::Display for DisplayBandwidth {
}
}
-#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, ValueEnum, EnumIter)]
-pub enum BandwidthUnitFamily {
- #[default]
- /// bytes, in powers of 2^10
- BinBytes,
- /// bits, in powers of 2^10
- BinBits,
- /// bytes, in powers of 10^3
- SiBytes,
- /// bits, in powers of 10^3
- SiBits,
+/// Type wrapper around [`UnitFamily`] to provide extra functionality.
+#[derive(Copy, Clone, Derivative, Default, Eq, PartialEq)]
+#[derivative(Debug = "transparent")]
+pub struct BandwidthUnitFamily(UnitFamily);
+impl From<UnitFamily> for BandwidthUnitFamily {
+ fn from(value: UnitFamily) -> Self {
+ Self(value)
+ }
}
impl BandwidthUnitFamily {
#[inline]
@@ -39,9 +37,9 @@ impl BandwidthUnitFamily {
/// Binary base: 2^10.
const BB: f64 = 1024.0;
- use BandwidthUnitFamily as F;
+ use UnitFamily as F;
// probably could macro this stuff, but I'm too lazy
- match self {
+ match self.0 {
F::BinBytes => [
(1.0, BB * STEP_UP_FRAC, "B"),
(BB, BB.powi(2) * STEP_UP_FRAC, "KiB"),
@@ -99,11 +97,12 @@ mod tests {
use itertools::Itertools;
use strum::IntoEnumIterator;
- use crate::display::{BandwidthUnitFamily, DisplayBandwidth};
+ use crate::{cli::UnitFamily, display::DisplayBandwidth};
#[test]
fn bandwidth_formatting() {
- let test_bandwidths_formatted = BandwidthUnitFamily::iter()
+ let test_bandwidths_formatted = UnitFamily::iter()
+ .map_into()
.cartesian_product(
// I feel like this is a decent selection of values
(-6..60)
diff --git a/src/display/ui.rs b/src/display/ui.rs
index 4b6d716..4a2866e 100644
--- a/src/display/ui.rs
+++ b/src/display/ui.rs
@@ -33,7 +33,7 @@ where
let state = {
let mut state = UIState::default();
state.interface_name = opts.interface.clone();
- state.unit_family = opts.render_opts.unit_family;
+ state.unit_family = opts.render_opts.unit_family.into();
state.cumulative_mode = opts.render_opts.total_utilization;
state
};