{"record":{"id":"570a25603457a31b","repo":"zed-industries/zed","slug":"unexpected-character-next","errorCode":null,"errorMessage":"unexpected character '{next:?}'","messagePattern":"unexpected character '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui/src/keymap/context.rs","lineNumber":253,"sourceCode":"    /// `StatusBar && mode == visible` -> A predicate that will match a context with the\n    ///                                   identifier `StatusBar` and the key `mode`\n    ///                                   with the value `visible`\n    ///\n    ///\n    /// There is also a special child `>` operator that will match a predicate that is\n    /// below another predicate:\n    ///\n    /// `StatusBar > mode == visible` -> A predicate that will match a context identifier `StatusBar`\n    ///                                  and a child context that has the key `mode` with the\n    ///                                  value `visible`\n    ///\n    /// This syntax supports `!=`, `||` and `&&` as logical operators.\n    /// You can also preface an operation or check with a `!` to negate it.\n    pub fn parse(source: &str) -> Result<Self> {\n        let source = skip_whitespace(source);\n        let (predicate, rest) = Self::parse_expr(source, 0)?;\n        if let Some(next) = rest.chars().next() {\n            anyhow::bail!(\"unexpected character '{next:?}'\");\n        } else {\n            Ok(predicate)\n        }\n    }\n\n    /// Find the deepest depth at which the predicate matches.\n    pub fn depth_of(&self, contexts: &[KeyContext]) -> Option<usize> {\n        for depth in (0..=contexts.len()).rev() {\n            let context_slice = &contexts[0..depth];\n            if self.eval_inner(context_slice, contexts) {\n                return Some(depth);\n            }\n        }\n        None\n    }\n\n    /// Eval a predicate against a set of contexts, arranged from lowest to highest.\n    #[allow(unused)]","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/gpui/src/keymap/context.rs#L235-L271","documentation":"KeyBindingContextPredicate::parse parses a complete context predicate expression and requires the entire source to be consumed. After parse_expr returns, any remaining character (whitespace is consumed by atoms and operators, so this is real syntax) means trailing text the grammar could not attach: typically an unbalanced ')' or a second predicate with no operator between them.","triggerScenarios":"Keymap context strings like 'mode == visual)' (stray close paren), 'normal (mode == visual)' (missing &&), or 'a b' (two identifiers not joined by an operator).","commonSituations":"Hand-edited keymap.json typos: an extra parenthesis left after editing; parentheses unbalanced across the expression; a fragment left behind after deleting an operator.","solutions":["Delete or fix the trailing text: usually an extra ')' or a predicate missing its '&&'/'||'/'>' operator","Rebalance parentheses across the whole expression","Check the editor log: the parse error is reported against the exact context string, which pinpoints the binding"],"exampleFix":"// before (keymap.json)\n\"context\": \"mode == visual)\"\n\n// after\n\"context\": \"mode == visual\"","handlingStrategy":"validation","validationCode":"// validate keymap context strings at load time\nfor binding in &keymap.bindings {\n    KeyBindingContextPredicate::parse(binding.context.as_str())\n        .with_context(|| format!(\"bad context in binding {binding:?}\"))?;\n}","typeGuard":"fn is_parseable_context(source: &str) -> bool {\n    KeyBindingContextPredicate::parse(source).is_ok()\n}","tryCatchPattern":null,"preventionTips":["Keep predicates small and deliberately parenthesized","Lint user keymap files on save with the real parser","Copy working examples from the default keymaps"],"tags":["gpui","keymap","parsing","keyboard-shortcuts","configuration"],"backgroundTag":"keymap-parse-error","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}