From 6749d882affdd77e4b2aa3665391e7f150ddad06 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sun, 8 Feb 2026 22:42:37 -0700 Subject: [PATCH 1/2] remove assert causing panic --- src/parser.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 2ca42c7..ecb95b9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -75,13 +75,14 @@ fn consume_content_line(input: Input<'_>) -> IResult, (&str, bool)> { pub(crate) fn parse_single_patch(s: &str) -> Result, ParseError<'_>> { let (remaining_input, patch) = patch(Input::new(s))?; - // Parser should return an error instead of producing remaining input - assert!( - remaining_input.fragment().is_empty(), - "bug: failed to parse entire input. \ - Remaining: '{}'", - remaining_input.fragment() - ); + if !remaining_input.fragment().is_empty() { + return Err(ParseError { + line: remaining_input.location_line(), + offset: 0, + fragment: remaining_input.fragment(), + kind: nom::error::ErrorKind::Fail, + }); + } Ok(patch) } From 95e16230edb5fbc6feee2c0175ec3d414fa4ead1 Mon Sep 17 00:00:00 2001 From: n4n5 Date: Sun, 8 Feb 2026 22:47:41 -0700 Subject: [PATCH 2/2] fix: add safe method --- src/ast.rs | 11 ++++++++++- src/parser.rs | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/ast.rs b/src/ast.rs index ae036c2..e782df2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2,8 +2,11 @@ use std::borrow::Cow; use std::fmt; use chrono::{DateTime, FixedOffset}; +use nom_locate::LocatedSpan; -use crate::parser::{parse_multiple_patches, parse_single_patch, ParseError}; +use crate::parser::{ + parse_multiple_patches, parse_single_patch, parse_single_patch_with_remaining, ParseError, +}; /// A complete patch summarizing the differences between two files #[derive(Debug, Clone, Eq, PartialEq)] @@ -82,6 +85,12 @@ impl<'a> Patch<'a> { parse_single_patch(s) } + pub fn from_single_with_remaining( + s: &'a str, + ) -> Result<(Self, Option>), ParseError<'a>> { + parse_single_patch_with_remaining(s) + } + /// Attempt to parse as many patches as possible from the given string. This is useful for when /// you have a complete diff of many files. /// diff --git a/src/parser.rs b/src/parser.rs index ecb95b9..a16e38f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,6 +12,7 @@ use nom::{ multi::{many0, many1}, sequence::{delimited, preceded, terminated, tuple}, }; +use nom_locate::LocatedSpan; use crate::ast::*; @@ -86,6 +87,16 @@ pub(crate) fn parse_single_patch(s: &str) -> Result, ParseError<'_>> { Ok(patch) } +pub(crate) fn parse_single_patch_with_remaining( + s: &str, +) -> Result<(Patch<'_>, Option>), ParseError<'_>> { + let (remaining_input, patch) = patch(Input::new(s))?; + if remaining_input.fragment().is_empty() { + return Ok((patch, None)); + } + Ok((patch, Some(remaining_input))) +} + pub(crate) fn parse_multiple_patches(s: &str) -> Result>, ParseError<'_>> { let (remaining_input, patches) = multiple_patches(Input::new(s))?; debug_assert!(