use clap::{Parser, Subcommand};
use std::path::PathBuf;
const LONG_ABOUT: &str = r#"
Obsidian CLI Inspector - A local-first, read-only CLI/TUI for Obsidian vaults
ABOUT:
This tool helps you inspect, search, and navigate your Obsidian vault from the terminal.
All data is stored locally in a SQLite database for fast, offline access.
USE CASES:
• Search: Find notes quickly with full-text search across your entire vault
• Link Analysis: Discover backlinks, forward links, and unresolved references
• Tag Management: Filter and organize notes by tags with AND/OR logic
• Graph Exploration: Visualize note relationships and connection depths
• Content Quality: Identify bloated notes that may need refactoring
• Related Notes: Get AI-style suggestions for notes you might want to link
• Scripting: Integrate with shell scripts and automation workflows
• Interactive TUI: Browse your vault in a terminal user interface
WORKFLOW:
1. Run 'init init' to set up the database
2. Run 'index index' to scan and parse your vault
3. Use search commands (notes, backlinks, tags, etc.)
4. Re-run 'index index' periodically to catch changes
CLI STRUCTURE:
obsidian-cli-inspector <group> <function> [args...]
Groups:
init - Database initialization
index - Vault indexing (scan, status)
search - Search and retrieval (notes, backlinks, links, tags, unresolved)
graph - Graph operations (neighbors, paths, centrality, components)
analyze - Content analysis (bloat, related, similar, quality)
diagnose - Diagnostics (orphans, broken-links, conflicts)
view - Display commands (stats, describe, health)
EXAMPLES:
# Initialize and index your vault
obsidian-cli-inspector init init
obsidian-cli-inspector index index
# Search for notes containing 'rust'
obsidian-cli-inspector search notes rust --limit 10
# Find all notes linking to 'Project Ideas'
obsidian-cli-inspector search backlinks "Project Ideas"
# List all notes tagged with 'work'
obsidian-cli-inspector search tags work
# Find large notes that might need splitting
obsidian-cli-inspector analyze bloat --threshold 100000
# Launch interactive mode
obsidian-cli-inspector tui
CONFIG:
Place config at ~/.config/obsidian-cli-inspector/config.toml
Specify vault path and database location there.
"#;
const HELP_TEMPLATE: &str =
"{about-with-newline}Version: {version}\n\nUsage: {usage}\n\n{all-args}{after-help}";
#[derive(Parser)]
#[command(name = "obsidian-cli-inspector")]
#[command(author, version)]
#[command(help_template = HELP_TEMPLATE)]
#[command(about = "Local-first CLI/TUI for indexing and gain insight in Obsidian vaults")]
#[command(long_about = LONG_ABOUT)]
pub struct Cli {
#[arg(short, long, value_name = "FILE")]
pub config: Option<PathBuf>,
#[arg(short = 'o', long = "output", value_name = "FORMAT", global = true)]
pub output: Option<String>,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
#[command(arg_required_else_help(true))]
pub enum Commands {
#[command(subcommand)]
Init(InitCommands),
#[command(subcommand)]
Index(IndexCommands),
#[command(subcommand)]
Search(SearchCommands),
#[command(subcommand)]
Analyze(AnalyzeCommands),
#[command(subcommand)]
Diagnose(DiagnoseCommands),
#[command(subcommand)]
View(ViewCommands),
Tui,
}
#[derive(Subcommand)]
pub enum InitCommands {
Init {
#[arg(short, long)]
force: bool,
},
}
#[derive(Subcommand)]
pub enum IndexCommands {
Index {
#[arg(short = 'n', long)]
dry_run: bool,
#[arg(short, long)]
force: bool,
#[arg(short, long)]
verbose: bool,
},
}
#[derive(Subcommand)]
pub enum SearchCommands {
Notes {
query: String,
#[arg(short, long, default_value = "20")]
limit: usize,
},
Backlinks {
note: String,
},
Links {
note: String,
},
Unresolved,
Tags {
tag: Option<String>,
#[arg(short, long)]
list: bool,
},
}
#[derive(Subcommand)]
pub enum AnalyzeCommands {
Bloat {
#[arg(short, long, default_value = "50000")]
threshold: usize,
#[arg(short, long, default_value = "10")]
limit: usize,
},
Related {
note: String,
#[arg(short, long, default_value = "10")]
limit: usize,
},
}
#[derive(Subcommand)]
pub enum DiagnoseCommands {
Orphans {
#[arg(long)]
exclude_templates: bool,
#[arg(long)]
exclude_daily: bool,
},
BrokenLinks,
}
#[derive(Subcommand)]
pub enum ViewCommands {
Stats,
Describe {
filename: String,
},
}