Shell completions

This commit is contained in:
Nox Sluijtman 2025-07-02 23:07:43 +02:00
parent c21072727c
commit 49f7746f57
Signed by: Egg
SSH key fingerprint: SHA256:2sG9X3C7Xvq2svGumz1/k7cm8l4G9+qAtAeugqB4J9M
6 changed files with 219 additions and 86 deletions

29
Cargo.lock generated
View file

@ -86,6 +86,15 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.32"
@ -104,6 +113,16 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "clap_mangen"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc33c849748320656a90832f54a5eeecaa598e92557fb5dedebc3355746d31e4"
dependencies = [
"clap",
"roff",
]
[[package]]
name = "colorchoice"
version = "1.0.4"
@ -249,9 +268,11 @@ dependencies = [
[[package]]
name = "noise"
version = "0.1.4"
version = "0.1.6"
dependencies = [
"clap",
"clap_complete",
"clap_mangen",
"libnotify",
"mpd",
]
@ -286,6 +307,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "roff"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "strsim"
version = "0.11.1"

View file

@ -1,9 +1,16 @@
[package]
name = "noise"
version = "0.1.4"
version = "0.1.6"
edition = "2024"
authors = ["Nox Sluijtman"]
[dependencies]
clap = { version = "4.5.39", features = ["derive"] }
clap_complete = "4.5.54"
libnotify = "1.0.3"
mpd = "0.1.0"
[build-dependencies]
clap = { version = "4.5.39", features = ["derive"] }
clap_complete = "4.5.54"
clap_mangen = "0.2.27"

39
build.rs Normal file
View file

@ -0,0 +1,39 @@
use clap::{Command, CommandFactory};
// use clap_complete as complete;
use clap_mangen as mangen;
// use complete::Shell;
use std::{path::PathBuf, str::FromStr};
#[path = "src/cli.rs"]
mod cli;
use cli::*;
fn generate_manpage(cmd: Command, out_dir: PathBuf) -> std::io::Result<()> {
let _path = mangen::generate_to(cmd, &out_dir)?;
println!("cargo:warning=manpage is generated: {out_dir:?}");
Ok(())
}
// fn generate_completions(cmd: &mut Command, out_dir: PathBuf) -> std::io::Result<()> {
// let path = complete::generate_to(Shell::Zsh, cmd, "noise", out_dir)?;
// println!("cargo:warning=completion file is generated: {path:?}");
// Ok(())
// }
fn main() -> std::io::Result<()> {
let out_dir =
std::path::PathBuf::from(std::env::var_os("OUT_DIR").ok_or(std::io::ErrorKind::NotFound)?);
// let out_dir = PathBuf::from_str("./").unwrap();
let cmd = Cli::command();
generate_manpage(cmd, out_dir.clone())?;
// eprintln!("{out_dir:?}");
// println!("cargo:warning=out_dir: {out_dir:?}");
Ok(())
}

View file

@ -23,10 +23,24 @@
src = ./.;
nativeBuildInputs = with pkgs; [
libnotify
installShellFiles
];
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath nativeBuildInputs;
RUST_SRC_PATH = pkgs.rustPlatform.rustLibSrc;
postInstall =
with pkgs;
lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
# installShellCompletion --cmd noise \
# --bash <($out/bin/fd --generate-completions bash) \
# --fish <($out/bin/fd --generate-completions fish)
# installShellCompletion --zsh contrib/completion/_fd
installShellCompletion --cmd noise \
--bash <($out/bin/noise --generate-completions bash) \
--zsh <($out/bin/noise --generate-completions zsh) \
--fish <($out/bin/noise --generate-completions fish)
'';
};
devShell =
with pkgs;

94
src/cli.rs Normal file
View file

@ -0,0 +1,94 @@
use clap::{Parser, Subcommand, ValueHint};
use clap_complete::Shell;
#[derive(Parser, Debug, PartialEq)]
#[command(
author = "Nox Sluijtman",
version,
about,
long_about = "A small, opinionated MPD client",
name = "noise"
)]
#[command(propagate_version = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
/// Enables verbose output
#[arg(short, long, global = true)]
pub verbose: bool,
/// Hostname where MPD listens at
#[arg(short = 'H', long, global = true)]
pub host: Option<String>,
/// Generate shell completions
#[arg(long = "generate-completions", value_enum)]
pub completions: Option<Shell>,
// /// Generate manpage
// #[arg(long = "generate-manpage", value_enum)]
// pub manpage: bool,
}
#[derive(Subcommand, Debug, PartialEq)]
pub enum Commands {
/// Toggle MPD stream
Toggle,
/// Skip to the next track
Next,
/// Revert to the previous track
Prev,
/// Stops playing
Stop,
/// Play queueueu
Play {
#[arg(short, long, value_hint = ValueHint::Other)]
track: Option<u32>,
},
/// Set or get crossfade
Crossfade {
#[arg(short, long, value_hint = ValueHint::Other)]
seconds: Option<i64>,
},
///Update still needs some work
Update,
/// Return currently playing song
Current,
/// Clear current queueueu
Clear,
/// Query database
Search {
///Search query
#[arg(trailing_var_arg = true, value_hint = ValueHint::Other)]
query: Vec<String>,
///Only return the first n results
#[arg(short, long, value_hint = ValueHint::Other)]
max: Option<u32>,
// #[arg(short, long)]
// append: bool,
// #[arg(short, long)]
// insert: Option<u32>,
},
/// Query database differently
Find {
///Search query
#[arg(trailing_var_arg = true, value_hint = ValueHint::Other)]
query: Vec<String>,
///Only return the first n results
#[arg(short, long, value_hint = ValueHint::Other)]
max: Option<u32>,
#[arg(short, long)]
append: bool,
},
/// List items in the current queueueu
List {
#[arg(short, long)]
file: bool,
},
// Add {
// #[arg(short, long)]
// position: Option<u32>,
// },
/// Shuffles the current queueue
Shuffle,
}

View file

@ -1,88 +1,37 @@
extern crate libnotify;
extern crate mpd;
use clap::{Parser, Subcommand};
mod cli;
use cli::*;
use clap::{Command, CommandFactory, Parser};
use clap_complete::{generate, Generator};
use libnotify::Notification;
use mpd::{Client, Query, Song, State, Term};
use std::time::Duration;
use std::{io, time::Duration};
#[derive(Parser)]
#[command(author, version, about, long_about = "Banaan")]
#[command(propagate_version = true)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
#[arg(short, long, global = true)]
verbose: bool,
///hostname where MPD listens at
#[arg(short = 'H', long, global = true)]
host: Option<String>,
}
#[derive(Subcommand)]
enum Commands {
/// Toggle MPD stream
Toggle,
/// Skip to the next track
Next,
/// Revert to the previous track
Prev,
/// Stops playing
Stop,
/// Play queueueu
Play { track: Option<u32> },
/// Set or get crossfade
Crossfade { seconds: Option<i64> },
///Update still needs some work
Update,
/// Return currently playing song
Current,
/// Clear current queueueu
Clear,
/// Query database
Search {
///Search query
#[arg(trailing_var_arg = true)]
query: Vec<String>,
///Only return the first n results
#[arg(short, long)]
max: Option<u32>,
// #[arg(short, long)]
// append: bool,
// #[arg(short, long)]
// insert: Option<u32>,
},
/// Query database differently
Find {
///Search query
#[arg(trailing_var_arg = true)]
query: Vec<String>,
///Only return the first n results
#[arg(short, long)]
max: Option<u32>,
#[arg(short, long)]
append: bool,
},
/// List items in the current queueueu
List {
#[arg(short, long)]
file: bool,
},
// Add {
// #[arg(short, long)]
// position: Option<u32>,
// },
/// Shuffles the current queueue
Shuffle,
fn print_completions<G: Generator>(generator: G, cmd: &mut Command) {
generate(
generator,
cmd,
cmd.get_name().to_string(),
&mut io::stdout(),
);
}
fn main() {
let cli = Cli::parse();
if let Some(completions) = cli.completions {
let mut cmd = Cli::command();
eprintln!("Generating completion file for {completions:?}...");
print_completions(completions, &mut cmd);
return;
}
libnotify::init("noise").unwrap();
let n = libnotify::Notification::new("Noise", None, None);
let cli = Cli::parse();
let host = cli.host.unwrap_or("localhost:6600".into());
@ -109,17 +58,20 @@ fn main() {
}
Commands::Next => conn.next().unwrap(),
Commands::Prev => conn.prev().unwrap(),
Commands::List { file } => conn.queue().unwrap().iter().for_each(|x| {
println!(
"{:<02} {}",
x.place.unwrap().pos,
if *file {
x.file.clone()
} else {
format_song(x.clone())
}
)
}),
Commands::List { file } => {
let _current_song = conn.currentsong().unwrap();
conn.queue().unwrap().iter().for_each(|x| {
println!(
"{:<02} {}",
x.place.unwrap().pos,
if *file {
x.file.clone()
} else {
format_song(x.clone())
}
)
});
}
Commands::Update => {
let thing = conn.update().unwrap();
println!("{thing}")