diff --git a/crates/graphicle/src/codex_config.rs b/crates/graphicle/src/codex_config.rs index a8a8185..17d0e36 100644 --- a/crates/graphicle/src/codex_config.rs +++ b/crates/graphicle/src/codex_config.rs @@ -88,7 +88,9 @@ fn scan(line: &str, open: &mut Option<&'static str>, depth: &mut usize) { let mut i = 0; while i < bytes.len() { if let Some(delimiter) = *open { - if line[i..].starts_with(delimiter) { + // Bytes, not `line[i..]`: inside a string `i` steps one byte at + // a time and can stop inside a multi-byte character. + if bytes[i..].starts_with(delimiter.as_bytes()) { *open = None; i += 3; } else { @@ -545,6 +547,16 @@ model = "o4-mini" assert!(remove(CONFIG, "graphicle-app").is_none()); } + #[test] + fn tables_read_past_multi_line_strings_with_non_ascii_text() { + let text = "developer_instructions = \"\"\"\nAnswer in fran\u{e7}ais \u{2014} briefly.\n\"\"\"\nnotes = '''caf\u{e9}'''\n\n[mcp_servers.docs]\ncommand = \"npx\"\nargs = [\"docs-mcp\"]\n"; + let found = tables(text); + assert_eq!(found.len(), 1); + assert_eq!(found[0].name, "docs"); + assert_eq!(found[0].command.as_deref(), Some("npx")); + assert!(!inline_servers(text)); + } + #[test] fn removing_a_table_keeps_the_comments_of_the_next() { let text = "[mcp_servers.graphify]\ncommand = \"graphify\"\nargs = [\"--mcp\"]\n\n# Mine.\n[mcp_servers.mine]\ncommand = \"m\"\n";