From 92f5c977b42d1322f3cebb260024179e1285b9d0 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 2 Aug 2026 08:42:56 +0900 Subject: fix(symfony-console): dispatch parse_token to CompletionInput in bind PHP's Input::bind() -> ArgvInput::parse() calls $this->parseToken(), which late-binds to CompletionInput::parseToken; that override swallows per-token RuntimeExceptions so an incomplete command line still parses. Delegating CompletionInput::bind to ArgvInput::bind pinned the call to ArgvInput's parseToken, aborting the whole parse on the first invalid token and leaving CompletionInput::parse_token dead. parseToken is protected and not on any trait, so ArgvInput::base_bind threads the concrete implementation in as a callback instead of a trait object. Co-Authored-By: Claude Fable 5 --- .../src/symfony/console/input/argv_input.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'crates/shirabe-external-packages/src/symfony/console/input/argv_input.rs') diff --git a/crates/shirabe-external-packages/src/symfony/console/input/argv_input.rs b/crates/shirabe-external-packages/src/symfony/console/input/argv_input.rs index bf1ea659..59828631 100644 --- a/crates/shirabe-external-packages/src/symfony/console/input/argv_input.rs +++ b/crates/shirabe-external-packages/src/symfony/console/input/argv_input.rs @@ -76,21 +76,37 @@ impl ArgvInput { } pub fn bind(&mut self, definition: &InputDefinition) -> anyhow::Result<()> { + self.base_bind(definition, ArgvInput::parse_token) + } + + /// Shared body of `bind` (PHP `Input::bind`). PHP's `$this->parse()` ends in + /// `$this->parseToken()`, which late-binds to `CompletionInput::parseToken`; `parseToken` + /// is protected and not part of any trait, so the concrete implementation is threaded in + /// as a callback taking the embedded ArgvInput. + pub(crate) fn base_bind( + &mut self, + definition: &InputDefinition, + parse_token: impl FnMut(&mut ArgvInput, &str, bool) -> anyhow::Result, + ) -> anyhow::Result<()> { self.inner.arguments = IndexMap::new(); self.inner.options = IndexMap::new(); self.inner.definition = definition.clone(); - self.parse()?; + self.base_parse(parse_token)?; Ok(()) } - fn parse(&mut self) -> anyhow::Result<()> { + /// Shared body of `parse`; see `base_bind` for why `parse_token` is a parameter. + fn base_parse( + &mut self, + mut parse_token: impl FnMut(&mut ArgvInput, &str, bool) -> anyhow::Result, + ) -> anyhow::Result<()> { let mut parse_options = true; self.parsed = self.tokens.clone(); while !self.parsed.is_empty() { let token = self.parsed.remove(0); - parse_options = self.parse_token(&token, parse_options)?; + parse_options = parse_token(self, &token, parse_options)?; } Ok(()) } -- cgit v1.3.1