use anyhow::{Context, Result};
use clap::Parser;
use std::path::PathBuf;
use bookmarks_core::config::{edit_config, print_config};
use bookmarks_core::open::open_links;
use bookmarks_core::storage::Storage;
use bookmarks_core::toml_storage::TomlStorage;
#[derive(Parser, Debug)]
#[command(name = "bookmarks")]
#[command(about = "Bookmarks in your filesystem")]
#[command(version)]
pub struct Args {
#[arg(short = 'f', long = "bookmarks-file", conflicts_with = "global")]
pub bookmarks_file: Option<PathBuf>,
#[arg(short, long, conflicts_with_all = ["bookmarks_file", "local"])]
pub global: bool,
#[arg(short, long, conflicts_with_all = ["bookmarks_file", "global"])]
pub local: bool,
#[arg(short, long)]
pub config: bool,
#[cfg(feature = "app")]
#[arg(short = 'a', long)]
pub app: bool,
#[cfg(feature = "webapp")]
#[arg(short = 'w', long)]
pub webapp: bool,
pub urls: Vec<String>,
}
fn resolve_storage(
bookmarks_file: Option<PathBuf>,
global: bool,
local: bool,
) -> Result<TomlStorage> {
if let Some(path) = bookmarks_file {
anyhow::ensure!(
path.exists(),
"bookmarks file not found: {}",
path.display()
);
return Ok(TomlStorage::new(path));
}
if local {
let cwd_path = TomlStorage::cwd_path().context("failed to get current directory")?;
let storage = TomlStorage::new(cwd_path);
storage.init()?;
return Ok(storage);
}
if !global
&& let Some(cwd_path) = TomlStorage::cwd_path()
&& cwd_path.exists()
{
return Ok(TomlStorage::new(cwd_path));
}
let storage = TomlStorage::with_default_path()?;
storage.init()?;
Ok(storage)
}
pub fn run_cli<I, T>(args: I) -> Result<()>
where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
let args = Args::parse_from(args);
let storage = resolve_storage(args.bookmarks_file, args.global, args.local)?;
#[cfg(feature = "app")]
if args.app {
return bookmarks_app::run_app(Box::new(storage)).map_err(|e| anyhow::anyhow!("{e}"));
}
#[cfg(feature = "webapp")]
if args.webapp {
return bookmarks_webapp::run_webapp(Box::new(storage));
}
if args.config {
match storage.path() {
Some(path) => edit_config(path)?,
None => anyhow::bail!("no bookmarks file found to edit"),
}
return Ok(());
}
let config = storage.load()?;
if args.urls.is_empty() {
print_config(&config);
} else {
open_links(&args.urls, &config)?;
}
if let Some(path) = storage.path() {
println!(
"(using {}, use --bookmarks-file to override)",
path.display()
);
}
Ok(())
}