Skip to content

Instantly share code, notes, and snippets.

@ZaneHannanAU
Created March 10, 2020 09:53
Show Gist options
  • Save ZaneHannanAU/389c0761e6975abceec74d72d378feeb to your computer and use it in GitHub Desktop.
Save ZaneHannanAU/389c0761e6975abceec74d72d378feeb to your computer and use it in GitHub Desktop.
stupid structopt thing
[package]
name = "structopt-example"
version = "0.1.0"
authors = ["Zane Hannan <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
structopt = { version = "0.3.11", features = [ "paw" ] }
paw = "1.0.0"
use std::{
error::Error as Er,
ffi::OsStr,
fmt::{self, Display},
fs::{create_dir_all, metadata, File, FileType},
io::stdout,
path::PathBuf,
};
use structopt::{clap::Shell, StructOpt};
#[derive(StructOpt, Debug)]
#[non_exhaustive]
/// A stupid program
enum Opt {
/// Generate completions
Completions {
/// File or folder to generate completions in (- = stdout)
#[structopt(short = "f", long)]
to: Option<PathBuf>,
/// Shell(s) to generate completions for
shells: Vec<Shell>,
},
}
#[paw::main]
fn main(opt: Opt) -> Result<(), Box<dyn Er>> {
match opt {
Opt::Completions { mut shells, mut to } => {
#[derive(Debug)]
struct BadFileType(PathBuf, FileType);
#[derive(Debug)]
struct NoShells;
#[derive(Debug)]
struct TooManyShells;
impl Display for BadFileType {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let BadFileType(path, file_type) = self;
let display = path.display();
write!(
fmt,
"Bad file type: {} is not a file or folder (file type: {:?}).",
display, file_type
)
}
}
impl Display for NoShells {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("No shells")
}
}
impl Display for TooManyShells {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("Too many shells")
}
}
impl Er for BadFileType {}
impl Er for NoShells {}
impl Er for TooManyShells {}
let pkg = &std::env::args()
.nth(0)
.map(PathBuf::from)
.and_then(|bin| bin.file_name().and_then(OsStr::to_str).map(String::from))
.unwrap_or_else(|| env!("CARGO_PKG_NAME").into());
let mut cl = Opt::clap();
if let Some(path) = to.as_ref() {
let fill = |shells: &mut Vec<Shell>| {
if shells.len() == 0 {
shells.extend({
Shell::variants()
.iter()
.filter_map(|s| s.parse::<Shell>().ok())
});
}
};
if path.is_dir() {
fill(&mut shells);
for shell in shells {
cl.gen_completions(pkg, shell, path);
}
} else if !path.exists() || path.is_file() {
if shells.len() == 1 {
let mut file = File::create(path)?;
cl.gen_completions_to(pkg, shells[0], &mut file);
} else {
fill(&mut shells);
create_dir_all(path)?;
for shell in shells {
cl.gen_completions(pkg, shell, path);
}
}
} else {
let meta = metadata(path.to_path_buf())?.file_type();
Err(BadFileType(to.take().unwrap(), meta))?;
}
} else {
if shells.len() > 1 {
Err(TooManyShells)?
} else if shells.len() == 0 {
Err(NoShells)?
}
let st = stdout();
cl.gen_completions_to(pkg, shells[0], &mut st.lock());
}
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment