aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/example-completion/src/main.rs16
-rw-r--r--mingling/Cargo.lock59
-rw-r--r--mingling/Cargo.toml3
-rw-r--r--mingling/src/example_docs.rs16
-rw-r--r--mingling_core/Cargo.lock77
-rw-r--r--mingling_core/Cargo.toml3
-rw-r--r--mingling_core/src/builds/comp.rs23
-rw-r--r--mingling_core/src/comp.rs6
-rw-r--r--mingling_core/src/comp/installation.rs72
-rw-r--r--mingling_core/src/lib.rs2
-rw-r--r--mling/Cargo.lock1
-rw-r--r--mling/Cargo.toml1
-rw-r--r--mling/src/project_installer.rs8
13 files changed, 274 insertions, 13 deletions
diff --git a/examples/example-completion/src/main.rs b/examples/example-completion/src/main.rs
index 413afd3..3f1a377 100644
--- a/examples/example-completion/src/main.rs
+++ b/examples/example-completion/src/main.rs
@@ -3,13 +3,23 @@
//! # How to Deploy
//! 1. Enable the `comp` feature
//! ```toml
+//! [dependencies]
//! mingling = { version = "...", features = [
//! "comp", // Enable this feature
//! "parser"
//! ] }
//! ```
//!
-//! 2. Write `build.rs` to generate completion scripts at compile time
+//! 2. Add `mingling` as a build dependency, enabling the `builds` and `comp` features
+//! ```toml
+//! [build-dependencies]
+//! mingling = { version = "...", features = [
+//! "builds", // Enable this feature for build scripts
+//! "comp"
+//! ] }
+//! ```
+//!
+//! 3. Write `build.rs` to generate completion scripts at compile time
//! ```ignore
//! use mingling::build::{build_comp_scripts, build_comp_scripts_with_bin_name};
//! fn main() {
@@ -21,8 +31,8 @@
//! }
//! ```
//!
-//! 3. Write `main.rs`, adding completion logic for your command entry point
-//! 4. Execute `cargo install --path ./`, then run the corresponding completion script in your shell
+//! 4. Write `main.rs`, adding completion logic for your command entry point
+//! 5. Execute `cargo install --path ./`, then run the corresponding completion script in your shell
use mingling::{
EnumTag, Groupped, ShellContext, Suggest,
diff --git a/mingling/Cargo.lock b/mingling/Cargo.lock
index 879973d..56c591c 100644
--- a/mingling/Cargo.lock
+++ b/mingling/Cargo.lock
@@ -89,6 +89,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys",
+]
+
+[[package]]
name = "env_filter"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -128,6 +149,17 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
name = "hashbrown"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -201,6 +233,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
+name = "libredox"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -237,6 +278,7 @@ dependencies = [
name = "mingling_core"
version = "0.1.8"
dependencies = [
+ "dirs",
"env_logger",
"just_fmt",
"just_template",
@@ -285,6 +327,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -356,6 +404,17 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
name = "regex"
version = "1.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml
index dd93a5e..ebe3620 100644
--- a/mingling/Cargo.toml
+++ b/mingling/Cargo.toml
@@ -16,12 +16,13 @@ tokio = { version = "1", features = ["full"] }
mingling = { path = ".", features = ["comp", "general_renderer", "parser"] }
[package.metadata.docs.rs]
-features = ["general_renderer", "repl", "comp", "parser"]
+features = ["builds", "general_renderer", "repl", "comp", "parser"]
[features]
nightly = ["mingling_core/nightly", "mingling_macros/nightly"]
debug = ["mingling_core/debug"]
async = ["mingling_core/async", "mingling_macros/async"]
+builds = ["mingling_core/builds"]
default = ["mingling_core/default", "mingling_macros/default"]
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index 9f1b46b..0a6c1b9 100644
--- a/mingling/src/example_docs.rs
+++ b/mingling/src/example_docs.rs
@@ -133,13 +133,23 @@ pub mod example_basic {}
/// # How to Deploy
/// 1. Enable the `comp` feature
/// ```toml
+/// [dependencies]
/// mingling = { version = "...", features = [
/// "comp", // Enable this feature
/// "parser"
/// ] }
/// ```
///
-/// 2. Write `build.rs` to generate completion scripts at compile time
+/// 2. Add `mingling` as a build dependency, enabling the `builds` and `comp` features
+/// ```toml
+/// [build-dependencies]
+/// mingling = { version = "...", features = [
+/// "builds", // Enable this feature for build scripts
+/// "comp"
+/// ] }
+/// ```
+///
+/// 3. Write `build.rs` to generate completion scripts at compile time
/// ```ignore
/// use mingling::build::{build_comp_scripts, build_comp_scripts_with_bin_name};
/// fn main() {
@@ -151,8 +161,8 @@ pub mod example_basic {}
/// }
/// ```
///
-/// 3. Write `main.rs`, adding completion logic for your command entry point
-/// 4. Execute `cargo install --path ./`, then run the corresponding completion script in your shell
+/// 4. Write `main.rs`, adding completion logic for your command entry point
+/// 5. Execute `cargo install --path ./`, then run the corresponding completion script in your shell
///
/// Cargo.toml
/// ```ignore
diff --git a/mingling_core/Cargo.lock b/mingling_core/Cargo.lock
index 9c2f9aa..358fa67 100644
--- a/mingling_core/Cargo.lock
+++ b/mingling_core/Cargo.lock
@@ -71,12 +71,39 @@ dependencies = [
]
[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys",
+]
+
+[[package]]
name = "env_filter"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -106,6 +133,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
name = "hashbrown"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -173,6 +211,21 @@ dependencies = [
]
[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libredox"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -188,6 +241,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
name = "mingling_core"
version = "0.1.8"
dependencies = [
+ "dirs",
"env_logger",
"just_fmt",
"just_template",
@@ -214,6 +268,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
name = "portable-atomic"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -247,6 +307,17 @@ dependencies = [
]
[[package]]
+name = "redox_users"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
name = "regex"
version = "1.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -455,6 +526,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/mingling_core/Cargo.toml b/mingling_core/Cargo.toml
index 4a8d593..f3ba9a2 100644
--- a/mingling_core/Cargo.toml
+++ b/mingling_core/Cargo.toml
@@ -10,6 +10,7 @@ repository = "https://github.com/catilgrass/mingling"
nightly = []
default = []
async = []
+builds = ["dep:dirs"]
dispatch_tree = []
general_renderer = [
@@ -31,6 +32,8 @@ thiserror = "2"
once_cell = "1.21.4"
+dirs = { version = "6", optional = true }
+
# comp
just_template = { version = "0.1.3", optional = true }
diff --git a/mingling_core/src/builds/comp.rs b/mingling_core/src/builds/comp.rs
index 228ef81..ad70cd2 100644
--- a/mingling_core/src/builds/comp.rs
+++ b/mingling_core/src/builds/comp.rs
@@ -1,3 +1,5 @@
+use std::path::PathBuf;
+
use just_template::tmpl_param;
use crate::ShellFlag;
@@ -84,6 +86,27 @@ pub fn build_comp_script_to(
std::fs::write(&output_path, tmpl.to_string())
}
+/// Generate a shell completion script and write it to a specified file path.
+///
+/// This function takes a shell flag, a binary name, and an output file path,
+/// selects the appropriate template, substitutes the binary name into the template,
+/// and writes the resulting completion script directly to the specified file path.
+///
+/// # Example
+/// ```
+/// build_comp_script_to_file(&ShellFlag::Bash, "myapp", "target/completions/myapp_comp.sh").unwrap();
+/// ```
+pub fn build_comp_script_to_file(
+ shell_flag: &ShellFlag,
+ bin_name: &str,
+ output_path: impl Into<PathBuf>,
+) -> Result<(), std::io::Error> {
+ let (tmpl_str, _ext) = get_tmpl(shell_flag);
+ let mut tmpl = just_template::Template::from(tmpl_str);
+ tmpl_param!(tmpl, bin_name = bin_name);
+ std::fs::write(output_path.into(), tmpl.to_string())
+}
+
fn get_tmpl(shell_flag: &ShellFlag) -> (&'static str, &'static str) {
match shell_flag {
ShellFlag::Bash => (TMPL_COMP_BASH, ".sh"),
diff --git a/mingling_core/src/comp.rs b/mingling_core/src/comp.rs
index 4fb17c7..fd26e1b 100644
--- a/mingling_core/src/comp.rs
+++ b/mingling_core/src/comp.rs
@@ -2,11 +2,17 @@ mod flags;
mod shell_ctx;
mod suggest;
+#[cfg(feature = "builds")]
+mod installation;
+
use std::collections::BTreeSet;
use std::fmt::Display;
#[doc(hidden)]
pub use flags::*;
+#[cfg(feature = "builds")]
+#[doc(hidden)]
+pub use installation::*;
#[doc(hidden)]
pub use shell_ctx::*;
#[doc(hidden)]
diff --git a/mingling_core/src/comp/installation.rs b/mingling_core/src/comp/installation.rs
new file mode 100644
index 0000000..d3d31d6
--- /dev/null
+++ b/mingling_core/src/comp/installation.rs
@@ -0,0 +1,72 @@
+use crate::{build::build_comp_script_to_file, ShellFlag};
+
+pub fn install_comp_script(
+ flag: ShellFlag,
+ bin_name: impl AsRef<str>,
+) -> Result<(), std::io::Error> {
+ match flag {
+ // ~/.local/share/bash-completion/completions/
+ ShellFlag::Bash => {
+ let Some(data_dir) = dirs::data_dir() else {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::Unsupported,
+ "Data directory not found!",
+ ));
+ };
+
+ let bin_name = bin_name.as_ref();
+
+ let comp_script_path = data_dir
+ .join("bash-completion")
+ .join("completions")
+ .join(format!("{}.sh", bin_name));
+
+ build_comp_script_to_file(&ShellFlag::Bash, bin_name, comp_script_path)?;
+ Ok(())
+ }
+
+ // ~/.zsh/completions/
+ ShellFlag::Zsh => {
+ let Some(home_dir) = dirs::home_dir() else {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::Unsupported,
+ "Home directory not found!",
+ ));
+ };
+
+ let bin_name = bin_name.as_ref();
+
+ let comp_script_path = home_dir
+ .join(".zsh")
+ .join("completions")
+ .join(format!("{}.zsh", bin_name));
+
+ build_comp_script_to_file(&ShellFlag::Zsh, bin_name, comp_script_path)?;
+ Ok(())
+ }
+
+ // ~/.config/fish/completions/
+ ShellFlag::Fish => {
+ let Some(config_dir) = dirs::config_dir() else {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::Unsupported,
+ "Config directory not found!",
+ ));
+ };
+
+ let bin_name = bin_name.as_ref();
+
+ let comp_script_path = config_dir
+ .join("fish")
+ .join("completions")
+ .join(format!("{}.fish", bin_name));
+
+ build_comp_script_to_file(&ShellFlag::Fish, bin_name, comp_script_path)?;
+ Ok(())
+ }
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::Unsupported,
+ "unsupported shell flag",
+ )),
+ }
+}
diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs
index 83edda8..e1c188f 100644
--- a/mingling_core/src/lib.rs
+++ b/mingling_core/src/lib.rs
@@ -51,10 +51,12 @@ pub mod setup {
pub use crate::program::setup::*;
}
+#[cfg(feature = "builds")]
#[doc(hidden)]
pub mod builds;
/// Provides build scripts for users
+#[cfg(feature = "builds")]
pub mod build {
#[cfg(feature = "comp")]
pub use crate::builds::comp::*;
diff --git a/mling/Cargo.lock b/mling/Cargo.lock
index fbcd4a7..073b69b 100644
--- a/mling/Cargo.lock
+++ b/mling/Cargo.lock
@@ -149,6 +149,7 @@ dependencies = [
name = "mingling_core"
version = "0.1.8"
dependencies = [
+ "dirs",
"just_fmt",
"just_template",
"once_cell",
diff --git a/mling/Cargo.toml b/mling/Cargo.toml
index bbee212..c2985f7 100644
--- a/mling/Cargo.toml
+++ b/mling/Cargo.toml
@@ -24,6 +24,7 @@ strip = true
[dependencies]
mingling = { path = "../mingling", features = [
+ "builds",
"parser",
"comp",
"general_renderer",
diff --git a/mling/src/project_installer.rs b/mling/src/project_installer.rs
index 5c21462..2e9ca8d 100644
--- a/mling/src/project_installer.rs
+++ b/mling/src/project_installer.rs
@@ -44,9 +44,7 @@ pub fn install_this_project(
.current_dir(workspace_root)
.status()?;
if !status.success() {
- return Err(std::io::Error::other(
- "exec `cargo clean` failed",
- ));
+ return Err(std::io::Error::other("exec `cargo clean` failed"));
}
}
@@ -56,9 +54,7 @@ pub fn install_this_project(
.current_dir(workspace_root)
.status()?;
if !status.success() {
- return Err(std::io::Error::other(
- "cargo build --release failed",
- ));
+ return Err(std::io::Error::other("cargo build --release failed"));
}
// Parse package.name from workspace_root's Cargo.toml as namespace