Various hover improvements (#5617)

* Show more info on hover for variables

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Move hover impls to lsp module

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Make hover work on names inside calls, fix doc line breaking, trim docs in tool tips

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Test the new hovers; fix signature syntax

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Hover tips for kwargs

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-03-04 22:53:31 +13:00
committed by GitHub
parent 6e57a80c13
commit df278c7e6a
200 changed files with 7888 additions and 4459 deletions

View File

@ -60,7 +60,7 @@ async fn test_updating_kcl_lsp_files() {
}
);
assert_eq!(server.code_map.len(), 10);
assert_eq!(server.code_map.len(), 11);
// Run open file.
server
@ -75,7 +75,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 11);
assert_eq!(server.code_map.len(), 12);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -91,7 +91,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 11);
assert_eq!(server.code_map.len(), 12);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -110,7 +110,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -136,7 +136,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -157,7 +157,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -177,7 +177,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 13);
assert_eq!(server.code_map.len(), 14);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -198,7 +198,7 @@ async fn test_updating_kcl_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -232,7 +232,7 @@ async fn test_updating_kcl_lsp_files() {
);
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -268,7 +268,7 @@ async fn test_updating_kcl_lsp_files() {
name: "my-project2".to_string()
}
);
assert_eq!(server.code_map.len(), 10);
assert_eq!(server.code_map.len(), 11);
// Just make sure that one of the current files read from disk is accurate.
assert_eq!(
server
@ -313,7 +313,7 @@ async fn test_updating_copilot_lsp_files() {
}
);
assert_eq!(server.code_map.len(), 10);
assert_eq!(server.code_map.len(), 11);
// Run open file.
server
@ -328,7 +328,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 11);
assert_eq!(server.code_map.len(), 12);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -344,7 +344,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 11);
assert_eq!(server.code_map.len(), 12);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -363,7 +363,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -389,7 +389,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -410,7 +410,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -430,7 +430,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 13);
assert_eq!(server.code_map.len(), 14);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -451,7 +451,7 @@ async fn test_updating_copilot_lsp_files() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -485,7 +485,7 @@ async fn test_updating_copilot_lsp_files() {
);
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -516,7 +516,7 @@ async fn test_updating_copilot_lsp_files() {
);
// Check the code map.
assert_eq!(server.code_map.len(), 12);
assert_eq!(server.code_map.len(), 13);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -552,7 +552,7 @@ async fn test_updating_copilot_lsp_files() {
name: "my-project2".to_string()
}
);
assert_eq!(server.code_map.len(), 10);
assert_eq!(server.code_map.len(), 11);
}
#[tokio::test(flavor = "multi_thread")]
@ -588,7 +588,7 @@ async fn test_kcl_lsp_create_zip() {
}
);
assert_eq!(server.code_map.len(), 10);
assert_eq!(server.code_map.len(), 11);
// Run open file.
server
@ -603,7 +603,7 @@ async fn test_kcl_lsp_create_zip() {
.await;
// Check the code map.
assert_eq!(server.code_map.len(), 11);
assert_eq!(server.code_map.len(), 12);
assert_eq!(
server.code_map.get("file:///test.kcl").unwrap().clone(),
"test".as_bytes()
@ -627,7 +627,7 @@ async fn test_kcl_lsp_create_zip() {
files.insert(file.name().to_string(), file.size());
}
assert_eq!(files.len(), 11);
assert_eq!(files.len(), 12);
let util_path = format!("{}/util.rs", string_path).replace("file://", "");
assert!(files.contains_key(&util_path));
assert_eq!(files.get("/test.kcl"), Some(&4));
@ -873,7 +873,7 @@ x = b"#
#[tokio::test(flavor = "multi_thread")]
async fn test_kcl_lsp_on_hover() {
let server = kcl_lsp_server(false).await.unwrap();
let server = kcl_lsp_server(true).await.unwrap();
// Send open file.
server
@ -882,12 +882,27 @@ async fn test_kcl_lsp_on_hover() {
uri: "file:///test.kcl".try_into().unwrap(),
language_id: "kcl".to_string(),
version: 1,
text: "startSketchOn()".to_string(),
text: r#"startSketchOn(XY)
foo = 42
foo
fn bar(x: string): string {
return x
}
bar("an arg")
startSketchOn(XY)
|> startProfileAt([0, 0], %)
|> line(end = [10, 0])
|> line(end = [0, 10])
"#
.to_string(),
},
})
.await;
// Send hover request.
// Std lib call
let hover = server
.hover(tower_lsp::lsp_types::HoverParams {
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
@ -901,12 +916,99 @@ async fn test_kcl_lsp_on_hover() {
.await
.unwrap();
// Check the hover.
match hover.unwrap().contents {
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
value.contains("startSketchOn");
value.contains("-> SketchSurface");
value.contains("Start a new 2-dimensional sketch on a specific");
assert!(value.contains("startSketchOn"));
assert!(value.contains(": SketchSurface"));
assert!(value.contains("Start a new 2-dimensional sketch on a specific"));
}
_ => unreachable!(),
}
// Variable use
let hover = server
.hover(tower_lsp::lsp_types::HoverParams {
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
uri: "file:///test.kcl".try_into().unwrap(),
},
position: tower_lsp::lsp_types::Position { line: 2, character: 1 },
},
work_done_progress_params: Default::default(),
})
.await
.unwrap();
match hover.unwrap().contents {
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
assert!(value.contains("foo: number = 42"));
}
_ => unreachable!(),
}
// User-defined function call.
let hover = server
.hover(tower_lsp::lsp_types::HoverParams {
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
uri: "file:///test.kcl".try_into().unwrap(),
},
position: tower_lsp::lsp_types::Position { line: 8, character: 1 },
},
work_done_progress_params: Default::default(),
})
.await
.unwrap();
match hover.unwrap().contents {
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
assert!(value.contains("bar(x: string): string"));
}
_ => unreachable!(),
}
// Variable inside a function
let hover = server
.hover(tower_lsp::lsp_types::HoverParams {
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
uri: "file:///test.kcl".try_into().unwrap(),
},
position: tower_lsp::lsp_types::Position { line: 5, character: 9 },
},
work_done_progress_params: Default::default(),
})
.await
.unwrap();
match hover.unwrap().contents {
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
assert!(value.contains("x: string"));
}
_ => unreachable!(),
}
// std function KwArg
let hover = server
.hover(tower_lsp::lsp_types::HoverParams {
text_document_position_params: tower_lsp::lsp_types::TextDocumentPositionParams {
text_document: tower_lsp::lsp_types::TextDocumentIdentifier {
uri: "file:///test.kcl".try_into().unwrap(),
},
position: tower_lsp::lsp_types::Position {
line: 12,
character: 11,
},
},
work_done_progress_params: Default::default(),
})
.await
.unwrap();
match hover.unwrap().contents {
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent { value, .. }) => {
assert!(value.contains("end?: [number]"));
assert!(value.contains("How far away (along the X and Y axes) should this line go?"));
}
_ => unreachable!(),
}