feat(lsp): explain generated targets on hover
This commit is contained in:
+52
-1
@@ -442,7 +442,10 @@ fn hemplate_completion_items(
|
||||
items.push(completion_item(
|
||||
&format!("ui::{}", target.name),
|
||||
&format!("ui::{}", target.name),
|
||||
"Generated hemx target discovered by hemx-build in the open `.heml` document.",
|
||||
&format!(
|
||||
"Generated hemx {} target discovered by hemx-build in the open `.heml` document.",
|
||||
target.kind
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -502,6 +505,21 @@ fn completion_item(label: &str, insert_text: &str, detail: &str) -> serde_json::
|
||||
}
|
||||
|
||||
fn hemplate_hover(uri: &str, text: &str, position: Option<(usize, usize)>) -> serde_json::Value {
|
||||
if let Some((kind, name)) = position.and_then(|position| generated_target_at(text, position)) {
|
||||
if let Ok(targets) =
|
||||
hemx_build::generated_targets_for_heml_source(path_from_file_uri(uri), text)
|
||||
{
|
||||
if targets
|
||||
.iter()
|
||||
.any(|target| target.kind == kind && target.name == name)
|
||||
{
|
||||
return hover_markdown(&format!(
|
||||
"Generated hemx `{kind}` target `{name}`.\n\nRust symbol: `ui::{name}`.\n\nSource: hemx-build facts for the current `.heml` document."
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((owner, field)) = position.and_then(|position| dotted_name_at(text, position)) {
|
||||
if let Ok(Some(facts)) =
|
||||
hemx_build::template_context_facts_for_heml_source(path_from_file_uri(uri), text)
|
||||
@@ -584,6 +602,26 @@ fn line_prefix(text: &str, position: (usize, usize)) -> Option<String> {
|
||||
Some(line.chars().take(position.1).collect())
|
||||
}
|
||||
|
||||
fn generated_target_at(text: &str, position: (usize, usize)) -> Option<(String, String)> {
|
||||
let line = text.lines().nth(position.0)?;
|
||||
let cursor = position.1.min(line.len());
|
||||
[
|
||||
("root", "data-hemx-root=\""),
|
||||
("slot", "data-hemx-slot=\""),
|
||||
("form", "data-hemx-form=\""),
|
||||
("handle", "data-hemx-handle=\""),
|
||||
]
|
||||
.into_iter()
|
||||
.find_map(|(kind, prefix)| {
|
||||
line.match_indices(prefix).find_map(|(attribute_start, _)| {
|
||||
let value_start = attribute_start + prefix.len();
|
||||
let value_end = value_start + line[value_start..].find('"')?;
|
||||
(cursor >= value_start && cursor <= value_end)
|
||||
.then(|| (kind.to_owned(), line[value_start..value_end].to_owned()))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn dotted_name_at(text: &str, position: (usize, usize)) -> Option<(String, String)> {
|
||||
let line = text.lines().nth(position.0)?;
|
||||
let chars = line.chars().collect::<Vec<_>>();
|
||||
@@ -1083,6 +1121,19 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_reports_generated_target_kind_and_rust_symbol() {
|
||||
// req: diag/010
|
||||
let uri = "file:///tmp/workout.heml";
|
||||
let text = r#"<main data-hemx-root="workout"><section data-hemx-slot="progress_panel"></section></main>"#;
|
||||
let cursor = text.find("progress_panel").expect("fixture target") + 2;
|
||||
|
||||
let hover = hemplate_hover(uri, text, Some((0, cursor))).to_string();
|
||||
|
||||
assert!(hover.contains("`slot` target `progress_panel`"), "{hover}");
|
||||
assert!(hover.contains("`ui::progress_panel`"), "{hover}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_positions_use_lsp_utf16_columns() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user