diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index 403303183..793cd5d58 100644 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -825,19 +825,33 @@ fn parse_layer_indexes(exprs: &[Spanned>], expected_len: usize) -> Re if layer_indexes.get(&layer_name).is_some() { bail_expr!(layer_expr, "duplicate layer name: {}", layer_name); } - // Check if user tried to map parentheses by using them directly - `(` and `)` + // Check if user tried to use parentheses directly - `(` and `)` // or escaped them like in kmonad - `\(` and `\)`. for subexpr in subexprs { - if subexpr.list(None).is_some_and(|l| { - l.is_empty() - || l.len() == 1 - && l.first() - .is_some_and(|s| s.atom(None).is_some_and(|atom| atom == "\\")) - }) { - bail_expr!(subexpr, "If you meant to map keys to `(` and `)`, you have to use `S-0` and `S-9` instead (for US layout).\nSee https://github.com/jtroo/kanata/issues/163 for context.",) + if let Some(list) = subexpr.list(None) { + if list.is_empty() { + bail_expr!( + subexpr, + "You can't put parentheses in deflayer directly, because they are special characters for delimiting lists.\n\ + To get `(` and `)` in US layout, you should use `S-9` and `S-0` respectively.\n\ + For more context, see: https://github.com/jtroo/kanata/issues/459" + ) + } + if list.len() == 1 + && list + .first() + .is_some_and(|s| s.atom(None).is_some_and(|atom| atom == "\\")) + { + bail_expr!( + subexpr, + "Escaping shifted characters with `\\` is currently not supported in kanata.\n\ + To get `(` and `)` in US layout, you should use `S-9` and `S-0` respectively.\n\ + For more context, see: https://github.com/jtroo/kanata/issues/163" + ) + } } } - let num_actions = expr.t.len() - 1; + let num_actions = expr.t.len() - 2; if num_actions != expected_len { bail_span!( expr, diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index fa55ac4f6..a46ed9eba 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -1249,3 +1249,55 @@ fn parse_all_defcfg() { ) .expect("succeeds"); } + +#[test] +fn using_parentheses_in_deflayer_directly_fails_with_custom_message() { + let _lk = match CFG_PARSE_LOCK.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + }; + let mut s = ParsedState::default(); + let source = r#" +(defsrc a b) +(deflayer base ( )) +"#; + let err = parse_cfg_raw_string( + source, + &mut s, + &PathBuf::from("test"), + &mut FileContentProvider { + get_file_content_fn: &mut |_| unimplemented!(), + }, + DEF_LOCAL_KEYS, + ) + .expect_err("should err"); + assert!(err + .msg + .contains("You can't put parentheses in deflayer directly")); +} + +#[test] +fn using_escaped_parentheses_in_deflayer_fails_with_custom_message() { + let _lk = match CFG_PARSE_LOCK.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + }; + let mut s = ParsedState::default(); + let source = r#" +(defsrc a b) +(deflayer base \( \)) +"#; + let err = parse_cfg_raw_string( + source, + &mut s, + &PathBuf::from("test"), + &mut FileContentProvider { + get_file_content_fn: &mut |_| unimplemented!(), + }, + DEF_LOCAL_KEYS, + ) + .expect_err("should err"); + assert!(err + .msg + .contains("Escaping shifted characters with `\\` is currently not supported")); +}