diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index 7d1aeeb47..743f124dc 100644 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -1692,6 +1692,19 @@ fn parse_macro_item_impl<'a>( } Ok(Action::Custom(custom)) => Ok((vec![SequenceEvent::Custom(custom)], &acs[1..])), _ => { + if let Some(submacro) = acs[0].list(s.vars()) { + // If it's just a list that's not parsable as a usable action, try parsing the + // content. + let mut submacro_remainder = submacro; + let mut all_events = vec![]; + while !submacro_remainder.is_empty() { + let mut events; + (events, submacro_remainder) = parse_macro_item(submacro_remainder, s)?; + all_events.append(&mut events); + } + return Ok((all_events, &acs[1..])); + } + let (held_mods, unparsed_str) = parse_mods_held_for_submacro(&acs[0], s)?; let mut all_events = vec![]; diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 23af04154..fc69003f2 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -733,6 +733,38 @@ fn parse_bad_submacro_2() { .unwrap_err(); } +#[test] +fn parse_nested_macro() { + // Test exists since it used to crash. It should not crash. + let _lk = match CFG_PARSE_LOCK.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + }; + let mut s = ParsedState::default(); + let source = r#" +(defvar m1 (a b c)) +(defsrc a b) +(deflayer base + (macro $m1) + (macro bspc bspc $m1) +) +"#; + parse_cfg_raw_string( + source, + &mut s, + &PathBuf::from("test"), + &mut FileContentProvider { + get_file_content_fn: &mut |_| unimplemented!(), + }, + DEF_LOCAL_KEYS, + ) + .map_err(|e| { + eprintln!("{:?}", miette::Error::from(e)); + "" + }) + .unwrap(); +} + #[test] fn parse_switch() { let _lk = match CFG_PARSE_LOCK.lock() { @@ -877,7 +909,6 @@ fn parse_on_idle_fakekey() { DEF_LOCAL_KEYS, ) .map_err(|_e| { - // uncomment to see what this looks like when running test eprintln!("{:?}", _e); "" })