From bbf480007d87631ef7b7f93cef170ec1af961406 Mon Sep 17 00:00:00 2001
From: Pascal Kuthe <pascal.kuthe@semimod.de>
Date: Mon, 13 Mar 2023 19:22:39 +0100
Subject: [PATCH] always parse the entire snippet

Previously any remaining text of the snippet that could not be parsed
was ignored. This commit adds the `parse_all` function which reports
an error if any text was not consumed by the parser
---
 helix-lsp/src/snippet.rs | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/helix-lsp/src/snippet.rs b/helix-lsp/src/snippet.rs
index 4713ad8b..77f44d4e 100644
--- a/helix-lsp/src/snippet.rs
+++ b/helix-lsp/src/snippet.rs
@@ -384,9 +384,14 @@ mod parser {
     }
 
     pub fn parse(s: &str) -> Result<Snippet, &str> {
-        snippet().parse(s).map(|(_input, elements)| elements)
+        snippet().parse(s).and_then(|(remainder, snippet)| {
+            if remainder.is_empty() {
+                Ok(snippet)
+            } else {
+                Err(remainder)
+            }
+        })
     }
-
     #[cfg(test)]
     mod test {
         use super::SnippetElement::*;
@@ -414,6 +419,28 @@ mod parser {
             )
         }
 
+        #[test]
+        fn parse_unterminated_placeholder_error() {
+            assert_eq!(Err("${1:)"), parse("match(${1:)"))
+        }
+
+        #[test]
+        fn parse_empty_placeholder() {
+            assert_eq!(
+                Ok(Snippet {
+                    elements: vec![
+                        Text("match(".into()),
+                        Placeholder {
+                            tabstop: 1,
+                            value: vec![],
+                        },
+                        Text(")".into())
+                    ]
+                }),
+                parse("match(${1:})")
+            )
+        }
+
         #[test]
         fn parse_placeholders_in_statement() {
             assert_eq!(