diff --git a/crates/agent_ui/src/completion_provider.rs b/crates/agent_ui/src/completion_provider.rs index ca59796966ff4ea5a5ad71f38cf65793a7cb0f3e..094c55b71aa14fd943a88c816542377927e72793 100644 --- a/crates/agent_ui/src/completion_provider.rs +++ b/crates/agent_ui/src/completion_provider.rs @@ -1691,17 +1691,34 @@ impl MentionCompletion { offset_to_line: usize, supported_modes: &[PromptContextType], ) -> Option { - let last_mention_start = line.rfind('@')?; + // Find the rightmost '@' that has a word boundary before it and no whitespace immediately after + let mut last_mention_start = None; + for (idx, _) in line.rmatch_indices('@') { + // No whitespace immediately after '@' + if line[idx + 1..] + .chars() + .next() + .is_some_and(|c| c.is_whitespace()) + { + continue; + } - // No whitespace immediately after '@' - if line[last_mention_start + 1..] - .chars() - .next() - .is_some_and(|c| c.is_whitespace()) - { - return None; + // Must be a word boundary before '@' + if idx > 0 + && line[..idx] + .chars() + .last() + .is_some_and(|c| !c.is_whitespace()) + { + continue; + } + + last_mention_start = Some(idx); + break; } + let last_mention_start = last_mention_start?; + // Must be a word boundary before '@' if last_mention_start > 0 && line[..last_mention_start] @@ -2488,6 +2505,48 @@ mod tests { None, "Should not parse with a space after @ at the start of the line" ); + + assert_eq!( + MentionCompletion::try_parse( + "@fetch https://www.npmjs.com/package/@matterport/sdk", + 0, + &[PromptContextType::Fetch] + ), + Some(MentionCompletion { + source_range: 0..52, + mode: Some(PromptContextType::Fetch), + argument: Some("https://www.npmjs.com/package/@matterport/sdk".to_string()), + }), + "Should handle URLs with @ in the path" + ); + + assert_eq!( + MentionCompletion::try_parse( + "@fetch https://example.com/@org/@repo/file", + 0, + &[PromptContextType::Fetch] + ), + Some(MentionCompletion { + source_range: 0..42, + mode: Some(PromptContextType::Fetch), + argument: Some("https://example.com/@org/@repo/file".to_string()), + }), + "Should handle URLs with multiple @ characters" + ); + + assert_eq!( + MentionCompletion::try_parse( + "@fetch https://example.com/@", + 0, + &[PromptContextType::Fetch] + ), + Some(MentionCompletion { + source_range: 0..28, + mode: Some(PromptContextType::Fetch), + argument: Some("https://example.com/@".to_string()), + }), + "Should parse URL ending with @ (even if URL is incomplete)" + ); } #[gpui::test]