@@ -1,7 +1,7 @@
1use std::borrow::Cow;
1use std::borrow::Cow;
3use anyhow::{anyhow, Result};
3use anyhow::{anyhow, Result};
4−use helix_core::{SmallVec, smallvec};
4+use helix_core::{smallvec, SmallVec};
6#[derive(Debug, PartialEq, Eq)]
6#[derive(Debug, PartialEq, Eq)]
7pub enum CaseChange {
7pub enum CaseChange {
@@ -210,8 +210,8 @@ mod parser {
213− fn text<'a>() -> impl Parser<'a, Output = &'a str> {
213+ fn text<'a, const SIZE: usize>(cs: [char; SIZE]) -> impl Parser<'a, Output = &'a str> {
214− take_while(|c| c != '$')
214+ take_while(move |c| cs.into_iter().all(|c1| c != c1))
217 fn digit<'a>() -> impl Parser<'a, Output = usize> {
217 fn digit<'a>() -> impl Parser<'a, Output = usize> {
@@ -270,13 +270,15 @@ mod parser {
271 |seq| { Conditional(seq.1, None, Some(seq.4)) }
271 |seq| { Conditional(seq.1, None, Some(seq.4)) }
278 fn regex<'a>() -> impl Parser<'a, Output = Regex<'a>> {
276 fn regex<'a>() -> impl Parser<'a, Output = Regex<'a>> {
277+ let text = map(text(['$', '/']), FormatItem::Text);
279− let replacement = reparse_as(take_until(|c| c == '/'), one_or_more(format()));
278+ let replacement = reparse_as(
279+ take_until(|c| c == '/'),
280+ one_or_more(choice!(format(), text)),
@@ -306,19 +308,20 @@ mod parser {
308 fn placeholder<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
310 fn placeholder<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
309− // TODO: why doesn't parse_as work?
311+ let text = map(text(['$', '}']), SnippetElement::Text);
310− // let value = reparse_as(take_until(|c| c == '}'), anything());
312+ map(
311− // TODO: fix this to parse nested placeholders (take until terminates too early)
313+ seq!(
312− let value = filter_map(take_until(|c| c == '}'), |s| {
314+ "${",
313− snippet().parse(s).map(|parse_result| parse_result.1).ok()
315+ digit(),
315−
317+ one_or_more(choice!(anything(), text)),
316− map(seq!("${", digit(), ":", value, "}"), |seq| {
318+ "}"
317− SnippetElement::Placeholder {
320+ |seq| SnippetElement::Placeholder {
318 tabstop: seq.1,
321 tabstop: seq.1,
319− value: seq.3.elements,
322+ value: seq.3,
324 fn choice<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
327 fn choice<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
@@ -366,12 +369,18 @@ mod parser {
368 fn anything<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
371 fn anything<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
369− let text = map(text(), SnippetElement::Text);
372+ // The parser has to be constructed lazily to avoid infinite opaque type recursion
370− choice!(tabstop(), placeholder(), choice(), variable(), text)
374+ let parser = choice!(tabstop(), placeholder(), choice(), variable());
373 fn snippet<'a>() -> impl Parser<'a, Output = Snippet<'a>> {
379 fn snippet<'a>() -> impl Parser<'a, Output = Snippet<'a>> {
380+ let text = map(text(['$']), SnippetElement::Text);
374− map(one_or_more(anything()), |parts| Snippet { elements: parts })
381+ map(one_or_more(choice!(anything(), text)), |parts| Snippet {
377 pub fn parse(s: &str) -> Result<Snippet, &str> {
386 pub fn parse(s: &str) -> Result<Snippet, &str> {
@@ -439,6 +448,25 @@ mod parser {
452+ fn parse_placeholder_nested_in_placeholder() {
455+ elements: vec![Placeholder {
461+ value: vec!(Text("bar")),
466+ parse("${1:foo ${2:bar}}")
443 fn parse_all() {
471 fn parse_all() {
444 assert_eq!(
472 assert_eq!(