Connect applications to schemes, filetypes, and more on macOS (more to come)
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

setup clap complete

+163 -85
+10
Cargo.lock
··· 138 138 ] 139 139 140 140 [[package]] 141 + name = "clap_complete" 142 + version = "4.5.58" 143 + source = "registry+https://github.com/rust-lang/crates.io-index" 144 + checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a" 145 + dependencies = [ 146 + "clap", 147 + ] 148 + 149 + [[package]] 141 150 name = "clap_derive" 142 151 version = "4.5.47" 143 152 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 300 309 version = "2.5.2" 301 310 dependencies = [ 302 311 "clap", 312 + "clap_complete", 303 313 "color-eyre", 304 314 "eyre", 305 315 "infat-lib",
+7
infat-cli/Cargo.toml
··· 17 17 eyre = { workspace = true } 18 18 color-eyre = { workspace = true } 19 19 tracing = { workspace = true } 20 + clap_complete = "4.5.58" 21 + 22 + [build-dependencies] 23 + clap_complete = "4.5.58" 24 + infat-lib = { path = "../infat-lib" } 25 + clap = { workspace = true } 26 +
+55
infat-cli/build.rs
··· 1 + use clap::{CommandFactory, ValueEnum}; 2 + use clap_complete::{generate_to, Shell}; 3 + use std::{env, error::Error, fs, path::Path}; 4 + 5 + include!("src/cli.rs"); 6 + 7 + fn main() -> Result<(), Box<dyn Error>> { 8 + // Always re-run if OUT_DIR or build.rs or your CLI model changes: 9 + println!("cargo:rerun-if-env-changed=OUT_DIR"); 10 + println!("cargo:rerun-if-changed=build.rs"); 11 + println!("cargo:rerun-if-changed=src/main.rs"); 12 + 13 + // grab OUT_DIR 14 + let out_dir = PathBuf::from(env::var("OUT_DIR")?); 15 + println!("OUT_DIR = {}", out_dir.display()); 16 + 17 + // grab PROFILE ("debug" or "release") 18 + let profile = env::var("PROFILE")?; 19 + println!("PROFILE = {}", profile); 20 + 21 + // walk up ancestors until we find the profile directory 22 + let mut candidate: &Path = out_dir.as_path(); 23 + let dest = loop { 24 + if let Some(name) = candidate.file_name().and_then(|s| s.to_str()) { 25 + if name == profile { 26 + break candidate.to_path_buf(); 27 + } 28 + } 29 + candidate = candidate 30 + .parent() 31 + .ok_or("could not locate `debug` or `release` in OUT_DIR")?; 32 + }; 33 + 34 + println!("writing completions into `{}`", dest.display()); 35 + 36 + // make sure destination directory exists 37 + fs::create_dir_all(&dest)?; 38 + 39 + // generate completions 40 + let bin_name = env!("CARGO_PKG_NAME"); 41 + let mut cmd = Cli::command(); 42 + 43 + for &shell in Shell::value_variants() { 44 + match generate_to(shell, &mut cmd, bin_name, &dest) { 45 + Ok(path) => { 46 + println!(" • {:?} -> {}", shell, path.display()); 47 + } 48 + Err(e) => { 49 + println!("failed to generate {:?}: {}", shell, e); 50 + } 51 + } 52 + } 53 + 54 + Ok(()) 55 + }
+88
infat-cli/src/cli.rs
··· 1 + use clap::{Parser, Subcommand}; 2 + use infat_lib::GlobalOptions; 3 + use std::path::PathBuf; 4 + 5 + #[derive(Parser, Debug, Clone)] 6 + #[command( 7 + author, 8 + version, 9 + about = "Declaratively manage macOS file associations and URL schemes", 10 + long_about = "Infat allows you to inspect and modify default applications for file types \ 11 + and URL schemes on macOS. It supports declarative configuration through TOML \ 12 + files for reproducible setups across machines." 13 + )] 14 + pub(crate) struct Cli { 15 + #[command(subcommand)] 16 + pub(crate) command: Option<Commands>, 17 + 18 + /// Path to the configuration file 19 + #[arg(short, long, value_name = "PATH")] 20 + config: Option<PathBuf>, 21 + 22 + /// Enable verbose logging 23 + #[arg(short, long)] 24 + verbose: bool, 25 + 26 + /// Suppress all output except errors 27 + #[arg(short, long)] 28 + quiet: bool, 29 + 30 + /// Continue processing on errors when possible 31 + #[arg(long)] 32 + robust: bool, 33 + } 34 + 35 + #[derive(Subcommand, Debug, Clone)] 36 + pub(crate) enum Commands { 37 + /// Show file association information 38 + Info { 39 + /// Application name to inspect 40 + #[arg(short, long, value_name = "APP")] 41 + app: Option<String>, 42 + 43 + /// File extension (without dot) 44 + #[arg(short, long, value_name = "EXT")] 45 + ext: Option<String>, 46 + 47 + /// File type/supertype 48 + #[arg(short, long, value_name = "TYPE")] 49 + r#type: Option<String>, 50 + }, 51 + 52 + /// Set an application association 53 + Set { 54 + /// Application name or bundle identifier 55 + #[arg(value_name = "APP")] 56 + app_name: String, 57 + 58 + /// File extension (without dot) 59 + #[arg(long, value_name = "EXT")] 60 + ext: Option<String>, 61 + 62 + /// URL scheme 63 + #[arg(long, value_name = "SCHEME")] 64 + scheme: Option<String>, 65 + 66 + /// File type/supertype 67 + #[arg(long, value_name = "TYPE")] 68 + r#type: Option<String>, 69 + }, 70 + 71 + /// Initialize configuration from current Launch Services settings 72 + Init { 73 + /// Output configuration file path (defaults to XDG config location) 74 + #[arg(short, long, value_name = "PATH")] 75 + output: Option<PathBuf>, 76 + }, 77 + } 78 + 79 + impl From<&Cli> for GlobalOptions { 80 + fn from(cli: &Cli) -> Self { 81 + Self { 82 + config_path: cli.config.clone(), 83 + verbose: cli.verbose, 84 + quiet: cli.quiet, 85 + robust: cli.robust, 86 + } 87 + } 88 + }
+3 -85
infat-cli/src/main.rs
··· 1 - // infat-cli/src/main.rs 2 - use clap::{Parser, Subcommand}; 1 + use clap::Parser; 3 2 use color_eyre::{ 4 3 eyre::{Context, Result}, 5 4 owo_colors::OwoColorize, ··· 8 7 use std::path::PathBuf; 9 8 use tracing::info; 10 9 11 - #[derive(Parser, Debug, Clone)] 12 - #[command( 13 - author, 14 - version, 15 - about = "Declaratively manage macOS file associations and URL schemes", 16 - long_about = "Infat allows you to inspect and modify default applications for file types \ 17 - and URL schemes on macOS. It supports declarative configuration through TOML \ 18 - files for reproducible setups across machines." 19 - )] 20 - struct Cli { 21 - #[command(subcommand)] 22 - command: Option<Commands>, 23 - 24 - /// Path to the configuration file 25 - #[arg(short, long, value_name = "PATH")] 26 - config: Option<PathBuf>, 27 - 28 - /// Enable verbose logging 29 - #[arg(short, long)] 30 - verbose: bool, 31 - 32 - /// Suppress all output except errors 33 - #[arg(short, long)] 34 - quiet: bool, 35 - 36 - /// Continue processing on errors when possible 37 - #[arg(long)] 38 - robust: bool, 39 - } 40 - 41 - #[derive(Subcommand, Debug, Clone)] 42 - enum Commands { 43 - /// Show file association information 44 - Info { 45 - /// Application name to inspect 46 - #[arg(short, long, value_name = "APP")] 47 - app: Option<String>, 48 - 49 - /// File extension (without dot) 50 - #[arg(short, long, value_name = "EXT")] 51 - ext: Option<String>, 52 - 53 - /// File type/supertype 54 - #[arg(short, long, value_name = "TYPE")] 55 - r#type: Option<String>, 56 - }, 57 - 58 - /// Set an application association 59 - Set { 60 - /// Application name or bundle identifier 61 - #[arg(value_name = "APP")] 62 - app_name: String, 63 - 64 - /// File extension (without dot) 65 - #[arg(long, value_name = "EXT")] 66 - ext: Option<String>, 67 - 68 - /// URL scheme 69 - #[arg(long, value_name = "SCHEME")] 70 - scheme: Option<String>, 71 - 72 - /// File type/supertype 73 - #[arg(long, value_name = "TYPE")] 74 - r#type: Option<String>, 75 - }, 76 - 77 - /// Initialize configuration from current Launch Services settings 78 - Init { 79 - /// Output configuration file path (defaults to XDG config location) 80 - #[arg(short, long, value_name = "PATH")] 81 - output: Option<PathBuf>, 82 - }, 83 - } 10 + mod cli; 84 11 85 - impl From<&Cli> for GlobalOptions { 86 - fn from(cli: &Cli) -> Self { 87 - Self { 88 - config_path: cli.config.clone(), 89 - verbose: cli.verbose, 90 - quiet: cli.quiet, 91 - robust: cli.robust, 92 - } 93 - } 94 - } 12 + use cli::{Cli, Commands}; 95 13 96 14 #[tokio::main] 97 15 async fn main() -> Result<()> {