shebang hover (#2290)
* add a test Signed-off-by: Jess Frazelle <github@jessfraz.com> * plugoin Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -167,6 +167,7 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
if (pos === null) return null
|
||||
const dom = document.createElement('div')
|
||||
dom.classList.add('documentation')
|
||||
dom.style.zIndex = '99999999'
|
||||
if (this.allowHTMLContent) dom.innerHTML = formatContents(contents)
|
||||
else dom.textContent = formatContents(contents)
|
||||
return { pos, end, create: (view) => ({ dom }), above: true }
|
||||
|
@ -36,6 +36,28 @@ pub struct Program {
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn get_hover_value_for_position(&self, pos: usize, code: &str) -> Option<Hover> {
|
||||
// Check if we are in the non code meta.
|
||||
if let Some(meta) = self.get_non_code_meta_for_position(pos) {
|
||||
for node in &meta.start {
|
||||
if node.contains(pos) {
|
||||
// We only care about the shebang.
|
||||
if let NonCodeValue::Shebang { value: _ } = &node.value {
|
||||
let source_range: SourceRange = node.into();
|
||||
return Some(Hover::Comment {
|
||||
value: r#"The `#!` at the start of a script, known as a shebang, specifies the path to the interpreter that should execute the script. This line is not necessary for your `kcl` to run in the modeling-app. You can safely delete it. If you wish to learn more about what you _can_ do with a shebang, read this doc: [zoo.dev/docs/faq/shebang](https://zoo.dev/docs/faq/shebang)."#.to_string(),
|
||||
range: source_range.to_lsp_range(code),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let value = self.get_value_for_position(pos)?;
|
||||
|
||||
value.get_hover_value_for_position(pos, code)
|
||||
}
|
||||
|
||||
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
||||
let indentation = options.get_indentation(indentation_level);
|
||||
let result = self
|
||||
@ -814,6 +836,18 @@ pub struct NonCodeNode {
|
||||
pub value: NonCodeValue,
|
||||
}
|
||||
|
||||
impl From<NonCodeNode> for SourceRange {
|
||||
fn from(value: NonCodeNode) -> Self {
|
||||
Self([value.start, value.end])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NonCodeNode> for SourceRange {
|
||||
fn from(value: &NonCodeNode) -> Self {
|
||||
Self([value.start, value.end])
|
||||
}
|
||||
}
|
||||
|
||||
impl NonCodeNode {
|
||||
pub fn contains(&self, pos: usize) -> bool {
|
||||
self.start <= pos && pos <= self.end
|
||||
@ -2987,6 +3021,10 @@ pub enum Hover {
|
||||
parameter_index: u32,
|
||||
range: LspRange,
|
||||
},
|
||||
Comment {
|
||||
value: String,
|
||||
range: LspRange,
|
||||
},
|
||||
}
|
||||
|
||||
/// Format options.
|
||||
|
@ -795,11 +795,7 @@ impl LanguageServer for Backend {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(value) = ast.get_value_for_position(pos) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(hover) = value.get_hover_value_for_position(pos, current_code) else {
|
||||
let Some(hover) = ast.get_hover_value_for_position(pos, current_code) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@ -836,6 +832,13 @@ impl LanguageServer for Backend {
|
||||
}))
|
||||
}
|
||||
crate::ast::types::Hover::Signature { .. } => Ok(None),
|
||||
crate::ast::types::Hover::Comment { value, range } => Ok(Some(Hover {
|
||||
contents: HoverContents::Markup(MarkupContent {
|
||||
kind: MarkupKind::Markdown,
|
||||
value,
|
||||
}),
|
||||
range: Some(range),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@ -944,6 +947,9 @@ impl LanguageServer for Backend {
|
||||
|
||||
Ok(Some(signature.clone()))
|
||||
}
|
||||
crate::ast::types::Hover::Comment { value: _, range: _ } => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,6 +884,53 @@ async fn test_kcl_lsp_on_hover() {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_kcl_lsp_on_hover_shebang() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
||||
// Send open file.
|
||||
server
|
||||
.did_open(tower_lsp::lsp_types::DidOpenTextDocumentParams {
|
||||
text_document: tower_lsp::lsp_types::TextDocumentItem {
|
||||
uri: "file:///test.kcl".try_into().unwrap(),
|
||||
language_id: "kcl".to_string(),
|
||||
version: 1,
|
||||
text: r#"#!/usr/bin/env zoo kcl view
|
||||
startSketchOn()"#
|
||||
.to_string(),
|
||||
},
|
||||
})
|
||||
.await;
|
||||
server.wait_on_handle().await;
|
||||
|
||||
// Send hover request.
|
||||
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: 0, character: 2 },
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Check the hover.
|
||||
if let Some(hover) = hover {
|
||||
assert_eq!(
|
||||
hover.contents,
|
||||
tower_lsp::lsp_types::HoverContents::Markup(tower_lsp::lsp_types::MarkupContent {
|
||||
kind: tower_lsp::lsp_types::MarkupKind::Markdown,
|
||||
value: "The `#!` at the start of a script, known as a shebang, specifies the path to the interpreter that should execute the script. This line is not necessary for your `kcl` to run in the modeling-app. You can safely delete it. If you wish to learn more about what you _can_ do with a shebang, read this doc: [zoo.dev/docs/faq/shebang](https://zoo.dev/docs/faq/shebang).".to_string()
|
||||
})
|
||||
);
|
||||
} else {
|
||||
panic!("Expected hover");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_kcl_lsp_signature_help() {
|
||||
let server = kcl_lsp_server(false).await.unwrap();
|
||||
|
Reference in New Issue
Block a user