Skip to content

Commit 65f850b

Browse files
authored
fix(cli): suppress VITE+ header for lint/fmt LSP and stdin flows (#1619)
## Summary The cosmetic `VITE+ - The Unified Toolchain for the Web` banner is printed to stdout before `vp lint` / `vp fmt` delegate to oxlint/oxfmt. For IDE-launched subprocesses (`--lsp`, `--stdin-filepath`) the editor parses stdout as the LSP protocol or as formatted source, so the banner corrupts the stream. Skip the banner exactly when: - `vp lint --lsp` - `vp fmt --lsp` - `vp fmt --stdin-filepath` (also `--stdin-filepath=<path>`) All other invocations of `vp lint` / `vp fmt` are unchanged and remain subject to the existing TTY / `GIT_INDEX_FILE` suppressions in `vite_shared::header::should_print_header()`. Implementation lives in `crates/vite_global_cli/src/cli.rs`: - New `should_suppress_header_for_subcommand("lint"|"fmt", &args)` predicate, mirroring the existing `should_force_global_delegate` shape and reusing `has_flag_before_terminator` (so `--lsp=...`, `--stdin-filepath=...`, and the `--` option terminator are all handled correctly). - New `maybe_print_runtime_header(command, args, show_header)` wrapper around `print_runtime_header`, used at the two call sites. Refs #1557 (first checkbox; the bin-wrapper deprecation and editor-extension updates remain). ## Test plan - [x] `cargo test -p vite_global_cli suppresses_header` — 2 positive tests pass - [x] `cargo test -p vite_global_cli does_not_suppress` — 4 negative tests pass (incl. `--` option terminator, unknown subcommand, fmt `--check`) - [x] `cargo fmt -p vite_global_cli -- --check` clean - [x] `cargo clippy -p vite_global_cli --tests` clean - [ ] Manual smoke (in a Vite+ project, attached TTY): - [ ] `vp lint` → banner printed - [ ] `vp lint --lsp` → no banner; stdout is pure LSP protocol - [ ] `vp fmt` → banner printed - [ ] `vp fmt --lsp` → no banner - [ ] `echo 'const a=1' | vp fmt --stdin-filepath foo.ts` → no banner; stdout is just formatted source - [ ] `echo 'const a=1' | vp fmt --stdin-filepath=foo.ts` → same - [ ] `vp check` (composite) → unaffected
1 parent 4d8ba95 commit 65f850b

1 file changed

Lines changed: 75 additions & 2 deletions

File tree

  • crates/vite_global_cli/src

crates/vite_global_cli/src/cli.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,22 @@ fn should_force_global_delegate(command: &str, args: &[String]) -> bool {
468468
}
469469
}
470470

471+
/// Whether the Vite+ banner should be suppressed for a lint/fmt invocation.
472+
///
473+
/// IDE extensions invoke `vp lint --lsp`, `vp fmt --lsp`, and
474+
/// `vp fmt --stdin-filepath` and parse the subprocess's stdout as the LSP
475+
/// protocol / formatted source; the cosmetic banner would corrupt that stream.
476+
fn should_suppress_header_for_subcommand(command: &str, args: &[String]) -> bool {
477+
match command {
478+
"lint" => has_flag_before_terminator(args, "--lsp"),
479+
"fmt" => {
480+
has_flag_before_terminator(args, "--lsp")
481+
|| has_flag_before_terminator(args, "--stdin-filepath")
482+
}
483+
_ => false,
484+
}
485+
}
486+
471487
/// Get available tasks for shell completion.
472488
///
473489
/// Delegates to the local vite-plus CLI to run `vp run` without arguments,
@@ -777,7 +793,7 @@ pub async fn run_command_with_options(
777793
if help::maybe_print_unified_delegate_help("lint", &args, render_options.show_header) {
778794
return Ok(ExitStatus::default());
779795
}
780-
print_runtime_header(render_options.show_header);
796+
maybe_print_runtime_header("lint", &args, render_options.show_header);
781797
if should_force_global_delegate("lint", &args) {
782798
commands::delegate::execute_global(cwd, "lint", &args).await
783799
} else {
@@ -789,7 +805,7 @@ pub async fn run_command_with_options(
789805
if help::maybe_print_unified_delegate_help("fmt", &args, render_options.show_header) {
790806
return Ok(ExitStatus::default());
791807
}
792-
print_runtime_header(render_options.show_header);
808+
maybe_print_runtime_header("fmt", &args, render_options.show_header);
793809
if should_force_global_delegate("fmt", &args) {
794810
commands::delegate::execute_global(cwd, "fmt", &args).await
795811
} else {
@@ -886,6 +902,13 @@ fn print_runtime_header(show_header: bool) {
886902
vite_shared::header::print_header();
887903
}
888904

905+
fn maybe_print_runtime_header(command: &str, args: &[String], show_header: bool) {
906+
if should_suppress_header_for_subcommand(command, args) {
907+
return;
908+
}
909+
print_runtime_header(show_header);
910+
}
911+
889912
/// Build a clap Command with custom help formatting matching the JS CLI output.
890913
pub fn command_with_help() -> clap::Command {
891914
command_with_help_with_options(RenderOptions::default())
@@ -933,6 +956,7 @@ pub fn try_parse_args_from_with_options(
933956
mod tests {
934957
use super::{
935958
has_flag_before_terminator, is_global_package_up_to_date, should_force_global_delegate,
959+
should_suppress_header_for_subcommand,
936960
};
937961

938962
#[test]
@@ -981,4 +1005,53 @@ mod tests {
9811005
assert!(!should_force_global_delegate("lint", &["src/index.ts".to_string()]));
9821006
assert!(!should_force_global_delegate("fmt", &["--check".to_string()]));
9831007
}
1008+
1009+
#[test]
1010+
fn lint_lsp_suppresses_header() {
1011+
assert!(should_suppress_header_for_subcommand("lint", &["--lsp".to_string()]));
1012+
assert!(should_suppress_header_for_subcommand(
1013+
"lint",
1014+
&["--fix".to_string(), "--lsp".to_string()]
1015+
));
1016+
}
1017+
1018+
#[test]
1019+
fn lint_without_lsp_does_not_suppress_header() {
1020+
assert!(!should_suppress_header_for_subcommand("lint", &[]));
1021+
assert!(!should_suppress_header_for_subcommand("lint", &["src".to_string()]));
1022+
assert!(!should_suppress_header_for_subcommand("lint", &["--fix".to_string()]));
1023+
}
1024+
1025+
#[test]
1026+
fn lint_lsp_after_terminator_does_not_suppress_header() {
1027+
assert!(!should_suppress_header_for_subcommand(
1028+
"lint",
1029+
&["--".to_string(), "--lsp".to_string()]
1030+
));
1031+
}
1032+
1033+
#[test]
1034+
fn fmt_lsp_or_stdin_filepath_suppresses_header() {
1035+
assert!(should_suppress_header_for_subcommand("fmt", &["--lsp".to_string()]));
1036+
assert!(should_suppress_header_for_subcommand(
1037+
"fmt",
1038+
&["--stdin-filepath".to_string(), "foo.ts".to_string()]
1039+
));
1040+
assert!(should_suppress_header_for_subcommand(
1041+
"fmt",
1042+
&["--stdin-filepath=foo.ts".to_string()]
1043+
));
1044+
}
1045+
1046+
#[test]
1047+
fn fmt_without_lsp_or_stdin_does_not_suppress_header() {
1048+
assert!(!should_suppress_header_for_subcommand("fmt", &[]));
1049+
assert!(!should_suppress_header_for_subcommand("fmt", &["src".to_string()]));
1050+
assert!(!should_suppress_header_for_subcommand("fmt", &["--check".to_string()]));
1051+
}
1052+
1053+
#[test]
1054+
fn unknown_subcommand_does_not_suppress_header() {
1055+
assert!(!should_suppress_header_for_subcommand("test", &["--lsp".to_string()]));
1056+
}
9841057
}

0 commit comments

Comments
 (0)