Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion crates/language/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3348,7 +3348,17 @@ impl BufferSnapshot {
pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer<'_>> {
let offset = position.to_offset(self);
self.syntax_layers_for_range(offset..offset, false)
.filter(|l| l.node().end_byte() > offset)
.filter(|l| {
if let Some(ranges) = l.included_sub_ranges {
ranges.iter().any(|range| {
let start = range.start.to_offset(self);
let end = range.end.to_offset(self);
start <= offset && offset < end
})
} else {
l.node().start_byte() <= offset && l.node().end_byte() > offset
}
})
.last()
}

Expand Down
60 changes: 52 additions & 8 deletions crates/language/src/buffer_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2627,7 +2627,7 @@ fn test_language_scope_at_with_combined_injections(cx: &mut App) {
buffer.set_language_registry(language_registry.clone());
buffer.set_language(
language_registry
.language_for_name("ERB")
.language_for_name("HTML+ERB")
Copy link
Contributor Author

@vitallium vitallium Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.now_or_never()
.unwrap()
.ok(),
Expand Down Expand Up @@ -2747,6 +2747,50 @@ fn test_language_at_for_markdown_code_block(cx: &mut App) {
});
}

#[gpui::test]
fn test_syntax_layer_at_for_injected_languages(cx: &mut App) {
init_settings(cx, |_| {});

cx.new(|cx| {
let text = r#"
```html+erb
<div>Hello</div>
<%= link_to "Some", "https://zed.dev" %>
```
"#
.unindent();

let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
language_registry.add(Arc::new(erb_lang()));
language_registry.add(Arc::new(html_lang()));
language_registry.add(Arc::new(ruby_lang()));

let mut buffer = Buffer::local(text, cx);
buffer.set_language_registry(language_registry.clone());
buffer.set_language(
language_registry
.language_for_name("HTML+ERB")
.now_or_never()
.unwrap()
.ok(),
cx,
);

let snapshot = buffer.snapshot();

// Test points in the code line
let html_point = Point::new(1, 4);
let language = snapshot.language_at(html_point).unwrap();
assert_eq!(language.name().as_ref(), "HTML");

let ruby_point = Point::new(2, 6);
let language = snapshot.language_at(ruby_point).unwrap();
assert_eq!(language.name().as_ref(), "Ruby");

buffer
});
}

#[gpui::test]
fn test_serialization(cx: &mut gpui::App) {
let mut now = Instant::now();
Expand Down Expand Up @@ -3636,7 +3680,7 @@ fn html_lang() -> Language {
fn erb_lang() -> Language {
Language::new(
LanguageConfig {
name: "ERB".into(),
name: "HTML+ERB".into(),
Copy link
Contributor Author

@vitallium vitallium Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matcher: LanguageMatcher {
path_suffixes: vec!["erb".to_string()],
..Default::default()
Expand All @@ -3654,15 +3698,15 @@ fn erb_lang() -> Language {
.with_injection_query(
r#"
(
(code) @injection.content
(#set! injection.language "ruby")
(#set! injection.combined)
(code) @content
(#set! "language" "ruby")
(#set! "combined")
Comment on lines +3701 to +3703
Copy link
Contributor Author

@vitallium vitallium Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)

(
(content) @injection.content
(#set! injection.language "html")
(#set! injection.combined)
(content) @content
(#set! "language" "html")
(#set! "combined")
Comment on lines +3707 to +3709
Copy link
Contributor Author

@vitallium vitallium Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)
"#,
)
Expand Down
12 changes: 9 additions & 3 deletions crates/language/src/syntax_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@ impl SyntaxSnapshot {
let changed_ranges;

let mut included_ranges = step.included_ranges;
let is_combined = matches!(step.mode, ParseMode::Combined { .. });

for range in &mut included_ranges {
range.start_byte -= step_start_byte;
range.end_byte -= step_start_byte;
Expand Down Expand Up @@ -749,16 +751,20 @@ impl SyntaxSnapshot {
);
}

let included_sub_ranges: Option<Vec<Range<Anchor>>> =
(included_ranges.len() > 1).then_some(
let included_sub_ranges: Option<Vec<Range<Anchor>>> = if is_combined {
Some(
included_ranges
.into_iter()
.filter(|r| r.start_byte < r.end_byte)
.map(|r| {
text.anchor_before(r.start_byte + step_start_byte)
..text.anchor_after(r.end_byte + step_start_byte)
})
.collect(),
);
)
} else {
None
};
Comment on lines +754 to +767
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure we always provide accurate metadata for combined injections.

SyntaxLayerContent::Parsed {
tree,
language,
Expand Down
Loading