Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/copper-proc-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pistonite-cu-proc-macros"
version = "0.2.7"
version = "0.2.8"
edition = "2024"
description = "Proc-macros for Cu"
repository = "https://github.com/Pistonite/cu"
Expand Down
12 changes: 12 additions & 0 deletions packages/copper-proc-macros/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> pm::Result<TokenStream2>
None => pm::quote! { (|_| {}) },
};

let fn_log_config_impl = match attrs.log_config {
Some(value) => pm::quote! { { #value } },
None => pm::quote! { |_| cu::cli::DefaultLogConfig },
};

let main_impl = if is_async {
pm::quote! {
cu::cli::__co_run(
#fn_preproc_impl,
#fn_log_config_impl,
#generated_main_name,
#fn_flag_impl
)
Expand All @@ -35,6 +41,7 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> pm::Result<TokenStream2>
pm::quote! {
cu::cli::__run(
#fn_preproc_impl,
#fn_log_config_impl,
#generated_main_name,
#fn_flag_impl
)
Expand Down Expand Up @@ -78,6 +85,10 @@ fn parse_attributes(attr: TokenStream) -> pm::Result<ParsedAttributes> {
out.preprocess_fn = Some(attr.value);
continue;
}
if attr.path.is_ident("log_config") {
out.log_config = Some(attr.value);
continue;
}
pm::bail!(attr, "unknown attribute");
}
Ok(out)
Expand All @@ -86,4 +97,5 @@ fn parse_attributes(attr: TokenStream) -> pm::Result<ParsedAttributes> {
struct ParsedAttributes {
flags_ident: Option<syn::Ident>,
preprocess_fn: Option<syn::Expr>,
log_config: Option<syn::Expr>,
}
41 changes: 41 additions & 0 deletions packages/copper-proc-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ use pm::pre::*;
/// }
/// ```
///
/// ## Attributes
///
/// ### `preprocess`
///
/// The attribute can also take a `preprocess` function
/// to process flags before initializing the CLI system.
/// This can be useful to merge multiple Flags instance
Expand Down Expand Up @@ -138,6 +142,43 @@ use pm::pre::*;
/// }
/// ```
///
/// ### `log_config`
/// `log_config` takes a function that returns a `LogConfig` trait implementation,
/// which can be used to alter how each `LogRecord` is displayed.
///
/// Below is an example that: overrides info messages in `some_library` to be debug messages
/// if the print level is info, and always show module path for that library.
///
/// ```rust,ignore
/// # use pistonite_cu as cu;
/// use cu::pre::*;
///
/// struct LogConfig(cu::lv::PrintLevel);
/// impl LogConfig {
/// pub fn new(flags: &cu::cli::Flags) -> Self {
/// Self(flags.print_level())
/// }
/// }
/// impl cu::cli::LogConfig for LogConfig {
/// fn process(&self, record: &cu::lv::LogRecord) -> (cu::lv::Lv, bool) {
/// if self.0 == cu::lv::PrintLevel::Normal {
/// if let Some(m) = record.module_path() {
/// if m == "some_library" {
/// let level: cu::lv::Lv = record.level().into();
/// let is_info = level == cu::lv::I;
/// return (if is_info { cu::lv::D } else { level }, true);
/// }
/// }
/// }
/// cu::cli::DefaultLogConfig.process(record)
/// }
/// }
///
/// #[cu::cli(log_config = LogConfig::new)]
/// fn main(_: cu::cli::Flags) -> cu::Result<()> {
/// Ok(())
/// }
/// ```
#[proc_macro_attribute]
pub fn cli(attr: TokenStream, input: TokenStream) -> TokenStream {
pm::flatten(cli::expand(attr, input))
Expand Down
18 changes: 9 additions & 9 deletions packages/copper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pistonite-cu"
version = "0.8.0"
version = "0.8.1"
edition = "2024"
description = "Battery-included common utils to speed up development of rust tools"
repository = "https://github.com/Pistonite/cu"
Expand All @@ -11,24 +11,24 @@ exclude = [
]

[dependencies]
pistonite-cu-proc-macros = { version = "0.2.7", path = "../copper-proc-macros" }
pistonite-cu-proc-macros = { version = "0.2.8", path = "../copper-proc-macros" }

# --- Always enabled ---
anyhow = "1.0.102"
log = "0.4.29"

# --- Command Line Interface ---
oneshot = { version = "0.2.1", optional = true, features = ["std"] }
env_filter = { version = "1.0.0", optional = true }
terminal_size = { version = "0.4.3", optional = true }
env_filter = { version = "1.0.1", optional = true }
terminal_size = { version = "0.4.4", optional = true }
unicode-width = { version = "0.2.2", features = ["cjk"], optional = true }
clap = { version = "4.5.60", features = ["derive"], optional = true }
clap = { version = "4.6.1", features = ["derive"], optional = true }
regex = { version = "1.12.3", optional = true }
ctrlc = { version = "3.5.2", optional = true }

# --- Coroutine ---
num_cpus = { version = "1.17.0", optional = true }
tokio = { version = "1.50.0", optional = true, features = [
tokio = { version = "1.52.1", optional = true, features = [
"macros", "rt-multi-thread"
] }

Expand All @@ -44,21 +44,21 @@ spin = {version = "0.10.0", optional = true} # for PIO
serde = { version = "1.0.228", features = ["derive"], optional = true }
serde_json = { version = "1.0.149", optional = true }
serde_yaml_ng = { version = "0.10.0", optional = true }
toml = { version = "1.0.6", optional = true }
toml = { version = "1.1.2", optional = true }

# derive
derive_more = { version = "2.1.1", features = ["full"], optional = true }

[target.'cfg(unix)'.dependencies]
libc = "0.2.183"
libc = "0.2.185"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61.2", features = ["Win32_Foundation", "Win32_System_Console", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_SystemServices"] }

[dev-dependencies]

[dev-dependencies.tokio]
version = "1.50.0"
version = "1.52.1"
features = [ "macros", "rt-multi-thread", "time" ]

[features]
Expand Down
43 changes: 36 additions & 7 deletions packages/copper/src/cli/flags.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::ffi::OsString;
use std::sync::Arc;
use std::time::Instant;

use clap::{Command, CommandFactory, FromArgMatches, Parser};

use crate::cli::LogConfig;
use crate::lv;

/// Common flags for `cu::cli`
#[derive(Default, Debug, Clone, PartialEq, Parser)]
pub struct Flags {
/// Verbose. More -v makes it more verbose (opposite of --quiet)
Expand Down Expand Up @@ -43,9 +46,8 @@ impl Flags {
/// This is unsafe because it modifies environment variables.
/// The [`cu::cli`](macro@crate::cli) macro generates safe call to this
/// when the program only has the main thread.
pub unsafe fn apply(&self) {
let level = (self.verbose as i8 - self.quiet as i8).clamp(-2, 2);
let level: lv::Print = level.into();
pub unsafe fn apply(&self, log_config: Arc<dyn LogConfig + Send + Sync>) {
let level = self.print_level();
if level == lv::Print::VerboseVerbose {
if std::env::var("RUST_BACKTRACE")
.unwrap_or_default()
Expand Down Expand Up @@ -80,7 +82,12 @@ impl Flags {
None
}
};
super::print_init::init_options(self.color.unwrap_or_default(), level, prompt);
super::print_init::init_options(self.color.unwrap_or_default(), level, prompt, log_config);
}

pub fn print_level(&self) -> lv::Print {
let level = (self.verbose as i8 - self.quiet as i8).clamp(-2, 2);
level.into()
}

/// Merge `other` into self. Options in other will be applied on top of self (equivalent
Expand Down Expand Up @@ -111,16 +118,25 @@ impl Flags {
#[doc(hidden)]
pub unsafe fn __run<
TArg: clap::Parser,
TLogConfig: LogConfig + Send + Sync + 'static,
FPreproc: FnOnce(&mut TArg),
FLogConfig: FnOnce(&Flags) -> TLogConfig,
FExecute: FnOnce(TArg) -> crate::Result<()>,
FFlag: FnOnce(&TArg) -> &Flags,
>(
fn_preproc: FPreproc,
fn_log_config: FLogConfig,
fn_execute: FExecute,
fn_flag: FFlag,
) -> std::process::ExitCode {
let start = std::time::Instant::now();
let args = unsafe { parse_args_or_help::<TArg, FPreproc, FFlag>(fn_preproc, fn_flag) };
let args = unsafe {
parse_args_or_help::<TArg, TLogConfig, FPreproc, FLogConfig, FFlag>(
fn_preproc,
fn_log_config,
fn_flag,
)
};
let result = fn_execute(args);
handle_result(start, result)
}
Expand All @@ -135,17 +151,26 @@ pub unsafe fn __run<
#[doc(hidden)]
pub unsafe fn __co_run<
TArg: clap::Parser + Send + 'static,
TLogConfig: LogConfig + Send + Sync + 'static,
FPreproc: FnOnce(&mut TArg),
FLogConfig: FnOnce(&Flags) -> TLogConfig,
FExecute: FnOnce(TArg) -> TResult + Send + 'static,
TResult: Future<Output = crate::Result<()>> + Send + 'static,
FFlag: FnOnce(&TArg) -> &Flags,
>(
fn_preproc: FPreproc,
fn_log_config: FLogConfig,
fn_execute: FExecute,
fn_flag: FFlag,
) -> std::process::ExitCode {
let start = std::time::Instant::now();
let args = unsafe { parse_args_or_help::<TArg, FPreproc, FFlag>(fn_preproc, fn_flag) };
let args = unsafe {
parse_args_or_help::<TArg, TLogConfig, FPreproc, FLogConfig, FFlag>(
fn_preproc,
fn_log_config,
fn_flag,
)
};
#[cfg(not(feature = "coroutine-heavy"))]
let result = crate::co::block(async move { fn_execute(args).await });
#[cfg(feature = "coroutine-heavy")]
Expand All @@ -156,16 +181,20 @@ pub unsafe fn __co_run<

unsafe fn parse_args_or_help<
TArg: Parser,
TLogConfig: LogConfig + Send + Sync + 'static,
FPreproc: FnOnce(&mut TArg),
FLogConfig: FnOnce(&Flags) -> TLogConfig,
FFlag: FnOnce(&TArg) -> &Flags,
>(
fn_preproc: FPreproc,
fn_log_config: FLogConfig,
fn_flag: FFlag,
) -> TArg {
let mut parsed = parse_args::<TArg>();
fn_preproc(&mut parsed);
let flags = fn_flag(&parsed);
unsafe { flags.apply() };
let log_config: Arc<dyn LogConfig + Send + Sync> = Arc::new(fn_log_config(flags));
unsafe { flags.apply(log_config) };
parsed
}

Expand Down
2 changes: 1 addition & 1 deletion packages/copper/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ pub use flags::__co_run;
pub use flags::{__run, Flags, print_help, try_parse};

mod print_init;
pub use print_init::level;
pub use print_init::{DefaultLogConfig, LogConfig, level};
mod macros;
pub use macros::__print_with_level;

Expand Down
Loading
Loading