mod alias;
pub(crate) mod command_approval;
pub(crate) mod command_executor;
pub(crate) mod commit;
pub(crate) mod config;
pub(crate) mod configure_shell;
pub(crate) mod context;
mod eval;
pub(crate) mod external;
mod for_each;
mod handle_switch;
mod hook_commands;
mod hook_filter;
pub(crate) mod hooks;
pub(crate) mod init;
pub(crate) mod list;
pub(crate) mod merge;
#[cfg(unix)]
pub(crate) mod picker;
pub(crate) mod pipeline_spec;
pub(crate) mod process;
pub(crate) mod project_config;
mod relocate;
pub(crate) mod repository_ext;
mod run_pipeline;
pub(crate) mod statusline;
pub(crate) mod step_commands;
pub(crate) mod worktree;
pub(crate) use alias::{AliasOptions, augment_step_help, step_alias};
pub(crate) use config::{
handle_claude_install, handle_claude_install_statusline, handle_claude_uninstall,
handle_config_create, handle_config_show, handle_config_update, handle_hints_clear,
handle_hints_get, handle_logs_list, handle_opencode_install, handle_opencode_uninstall,
handle_state_clear, handle_state_clear_all, handle_state_get, handle_state_set,
handle_state_show, handle_vars_clear, handle_vars_get, handle_vars_list, handle_vars_set,
};
pub(crate) use configure_shell::{
handle_configure_shell, handle_show_theme, handle_unconfigure_shell,
};
pub(crate) use eval::step_eval;
pub(crate) use external::handle_external_command;
pub(crate) use for_each::step_for_each;
pub(crate) use handle_switch::{SwitchOptions, handle_switch};
pub(crate) use hook_commands::{add_approvals, clear_approvals, handle_hook_show, run_hook};
pub(crate) use init::{handle_completions, handle_init};
pub(crate) use list::handle_list;
pub(crate) use merge::{MergeOptions, handle_merge};
#[cfg(unix)]
pub(crate) use picker::handle_picker;
pub(crate) use repository_ext::RemoveTarget;
pub(crate) use run_pipeline::run_pipeline;
pub(crate) use step_commands::{
PromoteResult, RebaseResult, SquashResult, handle_promote, handle_rebase, handle_squash,
step_commit, step_copy_ignored, step_diff, step_prune, step_relocate, step_show_squash_prompt,
};
pub(crate) use worktree::{
OperationMode, is_worktree_at_expected_path, resolve_worktree_arg, worktree_display_name,
};
pub(crate) use worktrunk::shell::Shell;
use color_print::cformat;
use worktrunk::styling::{eprintln, format_with_gutter};
pub(crate) fn format_command_label(command_type: &str, name: Option<&str>) -> String {
match name {
Some(name) => cformat!("Running {command_type} <bold>{name}</>"),
None => format!("Running {command_type}"),
}
}
pub(crate) fn force_serial_concurrent() -> bool {
std::env::var_os("WORKTRUNK_TEST_SERIAL_CONCURRENT").is_some()
}
pub(crate) fn show_diffstat(repo: &worktrunk::git::Repository, range: &str) -> anyhow::Result<()> {
let term_width = crate::display::terminal_width();
let stat_width = term_width.saturating_sub(worktrunk::styling::GUTTER_OVERHEAD);
let diff_stat = repo
.run_command(&[
"diff",
"--color=always",
"--stat",
&format!("--stat-width={}", stat_width),
range,
])?
.trim_end()
.to_string();
if !diff_stat.is_empty() {
eprintln!("{}", format_with_gutter(&diff_stat, None));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_command_label() {
use insta::assert_snapshot;
assert_snapshot!(format_command_label("post-create", Some("install")), @"Running post-create [1minstall[22m");
assert_snapshot!(format_command_label("pre-merge", None), @"Running pre-merge");
assert_snapshot!(format_command_label("post-start", Some("build")), @"Running post-start [1mbuild[22m");
assert_snapshot!(format_command_label("pre-commit", None), @"Running pre-commit");
}
}