Skip to content

Commit 3dc99eb

Browse files
committed
fix(cli): prevent TTY hang during command delegation by removing eager header evaluation (#1396)
Commands like `vp run` or `vp test` running under background/reporter environments (e.g., lefthook with certain Node.js versions) would hang due to `query_terminal_colors()` blocking on `/dev/tty`. The root cause was `apply_custom_help()` eagerly evaluating the `vite_plus_header()` (and its OSC queries) to build the clap help template during argument parsing, prior to command dispatch. This commit: - Removes the eager header evaluation from clap help templates. - Prints the dynamic `vite_plus_header()` lazily only on `ErrorKind::DisplayHelp`. - Explicitly passes `dynamic_colors` flags into `print_runtime_header()`, allowing delegate commands to safely use `vite_plus_header_static()` right before execution without blocking on TTY queries.
1 parent 9b57c4b commit 3dc99eb

File tree

3 files changed

+40
-22
lines changed

3 files changed

+40
-22
lines changed

crates/vite_global_cli/src/cli.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ pub async fn run_command_with_options(
16461646
packages,
16471647
pass_through_args,
16481648
} => {
1649-
print_runtime_header(render_options.show_header && !silent);
1649+
print_runtime_header(render_options.show_header && !silent, true);
16501650
// If packages are provided, redirect to Add command
16511651
if let Some(pkgs) = packages
16521652
&& !pkgs.is_empty()
@@ -1972,31 +1972,31 @@ pub async fn run_command_with_options(
19721972
if help::maybe_print_unified_delegate_help("dev", &args, render_options.show_header) {
19731973
return Ok(ExitStatus::default());
19741974
}
1975-
print_runtime_header(render_options.show_header);
1975+
print_runtime_header(render_options.show_header, false);
19761976
commands::delegate::execute(cwd, "dev", &args).await
19771977
}
19781978

19791979
Commands::Build { args } => {
19801980
if help::maybe_print_unified_delegate_help("build", &args, render_options.show_header) {
19811981
return Ok(ExitStatus::default());
19821982
}
1983-
print_runtime_header(render_options.show_header);
1983+
print_runtime_header(render_options.show_header, false);
19841984
commands::delegate::execute(cwd, "build", &args).await
19851985
}
19861986

19871987
Commands::Test { args } => {
19881988
if help::maybe_print_unified_delegate_help("test", &args, render_options.show_header) {
19891989
return Ok(ExitStatus::default());
19901990
}
1991-
print_runtime_header(render_options.show_header);
1991+
print_runtime_header(render_options.show_header, false);
19921992
commands::delegate::execute(cwd, "test", &args).await
19931993
}
19941994

19951995
Commands::Lint { args } => {
19961996
if help::maybe_print_unified_delegate_help("lint", &args, render_options.show_header) {
19971997
return Ok(ExitStatus::default());
19981998
}
1999-
print_runtime_header(render_options.show_header);
1999+
print_runtime_header(render_options.show_header, false);
20002000
if should_force_global_delegate("lint", &args) {
20012001
commands::delegate::execute_global(cwd, "lint", &args).await
20022002
} else {
@@ -2008,7 +2008,7 @@ pub async fn run_command_with_options(
20082008
if help::maybe_print_unified_delegate_help("fmt", &args, render_options.show_header) {
20092009
return Ok(ExitStatus::default());
20102010
}
2011-
print_runtime_header(render_options.show_header);
2011+
print_runtime_header(render_options.show_header, false);
20122012
if should_force_global_delegate("fmt", &args) {
20132013
commands::delegate::execute_global(cwd, "fmt", &args).await
20142014
} else {
@@ -2020,31 +2020,31 @@ pub async fn run_command_with_options(
20202020
if help::maybe_print_unified_delegate_help("check", &args, render_options.show_header) {
20212021
return Ok(ExitStatus::default());
20222022
}
2023-
print_runtime_header(render_options.show_header);
2023+
print_runtime_header(render_options.show_header, false);
20242024
commands::delegate::execute(cwd, "check", &args).await
20252025
}
20262026

20272027
Commands::Pack { args } => {
20282028
if help::maybe_print_unified_delegate_help("pack", &args, render_options.show_header) {
20292029
return Ok(ExitStatus::default());
20302030
}
2031-
print_runtime_header(render_options.show_header);
2031+
print_runtime_header(render_options.show_header, false);
20322032
commands::delegate::execute(cwd, "pack", &args).await
20332033
}
20342034

20352035
Commands::Run { args } => {
20362036
if help::maybe_print_unified_delegate_help("run", &args, render_options.show_header) {
20372037
return Ok(ExitStatus::default());
20382038
}
2039-
print_runtime_header(render_options.show_header);
2039+
print_runtime_header(render_options.show_header, false);
20402040
commands::delegate::execute(cwd, "run", &args).await
20412041
}
20422042

20432043
Commands::Exec { args } => {
20442044
if help::maybe_print_unified_delegate_help("exec", &args, render_options.show_header) {
20452045
return Ok(ExitStatus::default());
20462046
}
2047-
print_runtime_header(render_options.show_header);
2047+
print_runtime_header(render_options.show_header, false);
20482048
commands::delegate::execute(cwd, "exec", &args).await
20492049
}
20502050

@@ -2053,15 +2053,15 @@ pub async fn run_command_with_options(
20532053
{
20542054
return Ok(ExitStatus::default());
20552055
}
2056-
print_runtime_header(render_options.show_header);
2056+
print_runtime_header(render_options.show_header, false);
20572057
commands::delegate::execute(cwd, "preview", &args).await
20582058
}
20592059

20602060
Commands::Cache { args } => {
20612061
if help::maybe_print_unified_delegate_help("cache", &args, render_options.show_header) {
20622062
return Ok(ExitStatus::default());
20632063
}
2064-
print_runtime_header(render_options.show_header);
2064+
print_runtime_header(render_options.show_header, false);
20652065
commands::delegate::execute(cwd, "cache", &args).await
20662066
}
20672067

@@ -2098,11 +2098,16 @@ pub(crate) fn exit_status(code: i32) -> ExitStatus {
20982098
}
20992099
}
21002100

2101-
fn print_runtime_header(show_header: bool) {
2101+
fn print_runtime_header(show_header: bool, dynamic_colors: bool) {
21022102
if !show_header {
21032103
return;
21042104
}
2105-
println!("{}", vite_shared::header::vite_plus_header());
2105+
let header = if dynamic_colors {
2106+
vite_shared::header::vite_plus_header()
2107+
} else {
2108+
vite_shared::header::vite_plus_header_static()
2109+
};
2110+
println!("{header}");
21062111
println!();
21072112
}
21082113

@@ -2117,15 +2122,10 @@ pub fn command_with_help_with_options(render_options: RenderOptions) -> clap::Co
21172122
}
21182123

21192124
/// Apply custom help formatting to a clap Command to match the JS CLI output.
2120-
fn apply_custom_help(cmd: clap::Command, render_options: RenderOptions) -> clap::Command {
2125+
fn apply_custom_help(cmd: clap::Command, _render_options: RenderOptions) -> clap::Command {
21212126
let after_help = help::render_help_doc(&help::top_level_help_doc());
21222127
let options_heading = help::render_heading("Options");
2123-
let header = if render_options.show_header {
2124-
vite_shared::header::vite_plus_header()
2125-
} else {
2126-
String::new()
2127-
};
2128-
let help_template = format!("{header}{{after-help}}\n{options_heading}\n{{options}}\n");
2128+
let help_template = format!("{{after-help}}\n{options_heading}\n{{options}}\n");
21292129

21302130
cmd.after_help(after_help).help_template(help_template)
21312131
}

crates/vite_global_cli/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ async fn main() -> ExitCode {
338338

339339
// --help and --version are clap "errors" but should exit successfully.
340340
if matches!(e.kind(), ErrorKind::DisplayHelp | ErrorKind::DisplayVersion) {
341+
if e.kind() == ErrorKind::DisplayHelp {
342+
println!("{}", vite_shared::header::vite_plus_header());
343+
println!();
344+
}
341345
e.print().ok();
342346
ExitCode::SUCCESS
343347
} else if matches!(e.kind(), ErrorKind::InvalidSubcommand) {

crates/vite_shared/src/header.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ fn is_osc_query_unsupported() -> bool {
240240
if std::env::var_os("TMUX").is_some() || std::env::var_os("STY").is_some() {
241241
return true;
242242
}
243-
244243
false
245244
})
246245
}
@@ -536,6 +535,21 @@ pub fn vite_plus_header() -> String {
536535
render_header_variant(header_colors.blue, &header_colors.suffix_gradient, true, true)
537536
}
538537

538+
#[must_use]
539+
pub fn vite_plus_header_static() -> String {
540+
if !should_colorize() || !supports_true_color() {
541+
return format!("VITE+{HEADER_SUFFIX}");
542+
}
543+
544+
let suffix_gradient = gradient_eased(
545+
HEADER_SUFFIX.chars().count(),
546+
DEFAULT_BLUE,
547+
DEFAULT_MAGENTA,
548+
HEADER_SUFFIX_FADE_GAMMA,
549+
);
550+
render_header_variant(DEFAULT_BLUE, &suffix_gradient, true, true)
551+
}
552+
539553
#[cfg(all(test, unix))]
540554
mod tests {
541555
use std::io::{BufReader, Cursor};

0 commit comments

Comments
 (0)