use directories::ProjectDirs;
use lazy_static::lazy_static;
use std::path::PathBuf;
use structopt::StructOpt;
lazy_static! {
static ref DEFAULT_CACHE_DIR: String =
ProjectDirs::from("rs", "vimwiki", "vimwiki-cli")
.map(|dir| dir.cache_dir().to_string_lossy().to_string())
.unwrap_or_default();
}
#[derive(Debug, StructOpt)]
#[structopt(name = "vimwiki")]
pub struct Opt {
#[structopt(flatten)]
pub common: CommonOpt,
#[structopt(subcommand)]
pub subcommand: Subcommand,
}
#[derive(Debug, StructOpt)]
pub struct CommonOpt {
#[structopt(short, long, parse(from_occurrences), global = true)]
pub verbose: usize,
#[structopt(short, long, global = true)]
pub quiet: bool,
#[structopt(short, long, global = true)]
pub timestamp: Option<stderrlog::Timestamp>,
#[structopt(long, default_value = &DEFAULT_CACHE_DIR, global = true)]
pub cache: PathBuf,
#[structopt(long, global = true)]
pub no_cache: bool,
#[structopt(long, global = true)]
pub no_prune_cache: bool,
#[structopt(short, long, global = true)]
pub config: Option<PathBuf>,
#[structopt(short, long, global = true)]
pub merge: bool,
#[structopt(short, long, global = true)]
pub include: Vec<IndexOrName>,
}
impl CommonOpt {
pub fn filter_by_wiki_idx_and_name(
&self,
idx: usize,
name: Option<&str>,
) -> bool {
self.include.is_empty()
|| self.include.iter().any(|f| f.matches_either(idx, name))
}
}
#[derive(Debug, StructOpt)]
pub enum Subcommand {
Convert(ConvertSubcommand),
Inspect(InspectSubcommand),
Serve(ServeSubcommand),
}
impl Subcommand {
pub fn extra_paths(&self) -> &[PathBuf] {
match self {
Self::Convert(x) => &x.extra_paths,
Self::Inspect(x) => &x.extra_paths,
Self::Serve(x) => &x.extra_paths,
}
}
}
#[derive(Debug, StructOpt)]
pub struct ConvertSubcommand {
#[structopt(long)]
pub stdout: bool,
#[structopt(long)]
pub include_vimwiki_css: bool,
#[structopt(name = "PATH", parse(from_os_str))]
pub extra_paths: Vec<PathBuf>,
}
#[derive(Debug, StructOpt)]
pub struct ServeSubcommand {
#[structopt(short, long, default_value = "8080")]
pub port: usize,
#[structopt(long)]
pub include_styles_css: bool,
#[structopt(name = "PATH", parse(from_os_str))]
pub extra_paths: Vec<PathBuf>,
}
#[derive(Debug, StructOpt)]
pub struct InspectSubcommand {
#[structopt(short, long)]
pub output: Option<PathBuf>,
#[structopt(name = "JSONPATH")]
pub json_path: String,
#[structopt(name = "PATH", parse(from_os_str))]
pub extra_paths: Vec<PathBuf>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IndexOrName {
Index(usize),
Name(String),
}
impl IndexOrName {
pub fn matches_either<'a, N: Into<Option<&'a str>>>(
&self,
index: usize,
name: N,
) -> bool {
self == &index || name.into().map_or(false, |name| self == name)
}
}
impl PartialEq<usize> for IndexOrName {
fn eq(&self, other: &usize) -> bool {
match self {
Self::Index(x) => x == other,
_ => false,
}
}
}
impl PartialEq<String> for IndexOrName {
fn eq(&self, other: &String) -> bool {
match self {
Self::Name(x) => x == other,
_ => false,
}
}
}
impl PartialEq<str> for IndexOrName {
fn eq(&self, other: &str) -> bool {
match self {
Self::Name(x) => x == other,
_ => false,
}
}
}
impl std::str::FromStr for IndexOrName {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.parse::<usize>() {
Ok(idx) => Ok(Self::Index(idx)),
Err(_) => Ok(Self::Name(s.to_string())),
}
}
}