diff --git a/Cargo.lock b/Cargo.lock index c67305e..e7eaa97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -63,9 +63,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -73,6 +73,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.18" @@ -97,12 +106,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - [[package]] name = "heck" version = "0.5.0" @@ -115,15 +118,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "proc-macro2" version = "1.0.89" @@ -153,7 +147,7 @@ name = "subtitle-merge" version = "0.1.0" dependencies = [ "clap", - "itertools", + "clap_complete", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 98de9bd..d733ffc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -clap = { version = "4.5.20", features = ["derive"] } -itertools = "0.13.0" +clap = { version = "4.5.21", features = ["derive"] } + +[build-dependencies] +clap = { version = "4.5.21", features = ["derive"] } +clap_complete = "4.5.38" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..16a0996 --- /dev/null +++ b/build.rs @@ -0,0 +1,22 @@ +use std::{env, io}; + +use clap_complete::{generate_to, Shell}; +use cli_args::Args; +use clap::{CommandFactory, ValueEnum}; + +mod cli_args { + include!("src/cli_args.rs"); +} + +fn main() -> io::Result<()> { + let Some(outdir) = env::var_os("OUT_DIR") else { + return Ok(()); + }; + let mut command = Args::command(); + + for shell in Shell::value_variants() { + generate_to(*shell, &mut command, "subtitle-merge", &outdir)?; + // println!("cargo:warning=completion file is generated: {path:?}"); + } + Ok(()) +} diff --git a/flake.nix b/flake.nix index 64e5674..0a0de22 100644 --- a/flake.nix +++ b/flake.nix @@ -18,15 +18,24 @@ overlays.default = final: prev: { subtitle-merge = final.rustPlatform.buildRustPackage { name = "subtitle-merge"; - version = "1.0"; + version = "0.1"; src = ./.; cargoLock.lockFile = ./Cargo.lock; - buildInputs = [ final.mkvtoolnix-cli ]; + buildInputs = builtins.attrValues { + inherit (final) installShellFiles mkvtoolnix-cli; + }; + + postInstall = '' + installShellCompletion --cmd subtitle-merge \ + --bash ./target/release-tmp/build/*/out/subtitle-merge.bash \ + --fish ./target/release-tmp/build/*/out/subtitle-merge.fish \ + --zsh ./target/release-tmp/build/*/out/_subtitle-merge + ''; }; }; packages."${system}" = rec { - subtitle-merge = (overlays.default pkgs pkgs).subtitle-merge; + inherit (overlays.default pkgs pkgs) subtitle-merge; default = subtitle-merge; }; }; diff --git a/src/cli_args.rs b/src/cli_args.rs new file mode 100644 index 0000000..76f8365 --- /dev/null +++ b/src/cli_args.rs @@ -0,0 +1,25 @@ +use std::path::PathBuf; + +use clap::Parser; + +#[derive(Parser)] +pub enum Args { + Single(Single), + Dir(Dir), +} + +#[derive(Parser)] +pub struct Single { + pub source: PathBuf, + #[arg(long)] + pub subtitles: Option, + #[arg(long)] + pub fonts_dir: Option, + pub output: PathBuf, +} + +#[derive(Parser)] +pub struct Dir { + pub input_dir: PathBuf, + pub output_dir: PathBuf, +} diff --git a/src/main.rs b/src/main.rs index 033710c..31dd22f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,36 +1,16 @@ +mod cli_args; + use std::{ ffi::{OsStr, OsString}, fs::ReadDir, io, os::unix::{ffi::OsStrExt, process::CommandExt}, path::{Path, PathBuf}, - process::{Command, ExitCode, ExitStatus}, + process::{Command, ExitCode}, }; use clap::Parser; -use itertools::Either; - -#[derive(Parser)] -enum Args { - Single(Single), - Dir(Dir), -} - -#[derive(Parser)] -struct Single { - source: PathBuf, - #[arg(long)] - subtitles: Option, - #[arg(long)] - fonts_dir: Option, - output: PathBuf, -} - -#[derive(Parser)] -struct Dir { - input_dir: PathBuf, - output_dir: PathBuf, -} +use cli_args::{Args, Single}; fn find_subs(root: &Path, match_str: &OsStr) -> io::Result> { for entry in root.read_dir()? { @@ -59,7 +39,10 @@ fn find_subs(root: &Path, match_str: &OsStr) -> io::Result> { Ok(None) } -fn find_files(root: &Path, extension: &OsStr) -> impl Iterator> { +fn find_files( + root: &Path, + extension: &OsStr, +) -> io::Result>> { struct FindFonts { read_dirs: Vec, extension: OsString, @@ -74,11 +57,10 @@ fn find_files(root: &Path, extension: &OsStr) -> impl Iterator return Some(Err(e)), Ok(entry) => entry, + Err(e) => return Some(Err(e)), }; - let file_type = entry.file_type(); - let file_type = match file_type { + let file_type = match entry.file_type() { Err(e) => return Some(Err(e)), Ok(file_type) => file_type, }; @@ -101,14 +83,10 @@ fn find_files(root: &Path, extension: &OsStr) -> impl Iterator Either::Left(FindFonts { - read_dirs: vec![read_dir], - extension: extension.to_owned(), - }), - Err(e) => Either::Right(std::iter::once(Err(e))), - } + Ok(FindFonts { + read_dirs: vec![root.read_dir()?], + extension: extension.to_owned(), + }) } fn convert_single( @@ -119,18 +97,18 @@ fn convert_single( output, }: Single, ) -> io::Result { - let subtitles = if let Some(subtitles) = subtitles { - subtitles - } else { - find_subs(&source.parent().unwrap(), source.file_stem().unwrap())?.unwrap() - }; + let subtitles = subtitles.map_or_else(|| { + find_subs(source.parent().unwrap(), source.file_stem().unwrap()) + .transpose() + .unwrap() + }, Ok)?; let fonts: Vec = if let Some(fonts_dir) = fonts_dir { fonts_dir .read_dir()? .map(|r| r.map(|entry| entry.path())) .collect::>()? } else { - find_files(source.parent().unwrap(), OsStr::new("ttf")).collect::>()? + find_files(source.parent().unwrap(), OsStr::new("ttf"))?.collect::>()? }; let mut command = Command::new("mkvmerge"); @@ -141,7 +119,7 @@ fn convert_single( ]); for font in fonts { command - .args(&["--attachment-mime-type", "font/ttf", "--attach-file"]) + .args(["--attachment-mime-type", "font/ttf", "--attach-file"]) .arg(font.into_os_string()); } Ok(command) @@ -155,7 +133,7 @@ fn main() -> io::Result { Err(command.exec()) } Args::Dir(dir) => { - let files = find_files(&dir.input_dir, OsStr::new("mkv")); + let files = find_files(&dir.input_dir, OsStr::new("mkv"))?; let mut commands = Vec::new(); for file in files { let input_file = file?;