Skip to content

Commit 69c39df

Browse files
committed
hover: add test
1 parent c9cec15 commit 69c39df

3 files changed

Lines changed: 138 additions & 3 deletions

File tree

crates/emmylua_ls/src/handlers/hover/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ mod hover_builder;
33
mod hover_humanize;
44
mod keyword_hover;
55
mod std_hover;
6+
mod test;
67

78
pub use build_hover::build_hover_content_for_completion;
89
use build_hover::build_semantic_info_hover;
10+
use emmylua_code_analysis::{EmmyLuaAnalysis, FileId};
911
use emmylua_parser::LuaAstNode;
1012
pub use hover_builder::HoverBuilder;
1113
use keyword_hover::{hover_keyword, is_keyword};
1214
use lsp_types::{
1315
ClientCapabilities, Hover, HoverContents, HoverParams, HoverProviderCapability, MarkupContent,
14-
ServerCapabilities,
16+
Position, ServerCapabilities,
1517
};
1618
use rowan::TokenAtOffset;
1719
use tokio_util::sync::CancellationToken;
@@ -29,8 +31,11 @@ pub async fn on_hover(
2931
let position = params.text_document_position_params.position;
3032
let analysis = context.analysis.read().await;
3133
let file_id = analysis.get_file_id(&uri)?;
32-
let semantic_model = analysis.compilation.get_semantic_model(file_id)?;
34+
hover(&analysis, file_id, position)
35+
}
3336

37+
pub fn hover(analysis: &EmmyLuaAnalysis, file_id: FileId, position: Position) -> Option<Hover> {
38+
let semantic_model = analysis.compilation.get_semantic_model(file_id)?;
3439
if !semantic_model.get_emmyrc().hover.enable {
3540
return None;
3641
}
@@ -52,7 +57,6 @@ pub async fn on_hover(
5257
return None;
5358
}
5459
};
55-
5660
match token {
5761
keywords if is_keyword(keywords.clone()) => {
5862
let document = semantic_model.get_document();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#[cfg(test)]
2+
mod tests {
3+
4+
use crate::handlers::hover::test::{HoverVirtualWorkspace, VirtualHoverResult};
5+
#[test]
6+
fn test_1() {
7+
let mut ws = HoverVirtualWorkspace::new();
8+
assert!(ws.check_hover(
9+
r#"
10+
---@class <??>A
11+
---@field a number
12+
---@field b string
13+
---@field c boolean
14+
"#,
15+
VirtualHoverResult {
16+
value: "\n```lua\n(class) A {\n a: number,\n b: string,\n c: boolean,\n}\n```\n\n\n".to_string(),
17+
},
18+
));
19+
}
20+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use emmylua_code_analysis::{EmmyLuaAnalysis, FileId, VirtualUrlGenerator};
2+
use lsp_types::{Hover, HoverContents, MarkupContent, Position};
3+
4+
mod hover_test;
5+
use super::hover;
6+
7+
/// A virtual workspace for testing.
8+
#[allow(unused)]
9+
#[derive(Debug)]
10+
struct HoverVirtualWorkspace {
11+
pub virtual_url_generator: VirtualUrlGenerator,
12+
pub analysis: EmmyLuaAnalysis,
13+
id_counter: u32,
14+
}
15+
16+
#[derive(Debug)]
17+
struct VirtualHoverResult {
18+
pub value: String,
19+
}
20+
21+
#[allow(unused)]
22+
impl HoverVirtualWorkspace {
23+
pub fn new() -> Self {
24+
let gen = VirtualUrlGenerator::new();
25+
let mut analysis = EmmyLuaAnalysis::new();
26+
let base = &gen.base;
27+
analysis.add_main_workspace(base.clone());
28+
HoverVirtualWorkspace {
29+
virtual_url_generator: gen,
30+
analysis,
31+
id_counter: 0,
32+
}
33+
}
34+
35+
pub fn new_with_init_std_lib() -> Self {
36+
let gen = VirtualUrlGenerator::new();
37+
let mut analysis = EmmyLuaAnalysis::new();
38+
analysis.init_std_lib(false);
39+
let base = &gen.base;
40+
analysis.add_main_workspace(base.clone());
41+
HoverVirtualWorkspace {
42+
virtual_url_generator: gen,
43+
analysis,
44+
id_counter: 0,
45+
}
46+
}
47+
48+
pub fn def(&mut self, content: &str) -> FileId {
49+
let id = self.id_counter;
50+
self.id_counter += 1;
51+
self.def_file(&format!("virtual_{}.lua", id), content)
52+
}
53+
54+
pub fn def_file(&mut self, file_name: &str, content: &str) -> FileId {
55+
let uri = self.virtual_url_generator.new_uri(file_name);
56+
let file_id = self
57+
.analysis
58+
.update_file_by_uri(&uri, Some(content.to_string()))
59+
.unwrap();
60+
file_id
61+
}
62+
63+
/// 处理文件内容
64+
fn handle_file_content(content: &str) -> Option<(String, Position)> {
65+
let mut content = content.to_string();
66+
let cursor_pos = content.find("<??>");
67+
if let Some(cursor_pos) = cursor_pos {
68+
// 确保只有一个 <??> 标记
69+
if content.matches("<??>").count() > 1 {
70+
return None;
71+
}
72+
73+
let mut line = 0;
74+
let mut column = 0;
75+
for (i, c) in content.chars().take(cursor_pos).enumerate() {
76+
if c == '\n' {
77+
line += 1;
78+
column = 0;
79+
} else {
80+
column += 1;
81+
}
82+
}
83+
84+
content = content.replace("<??>", "");
85+
86+
return Some((content, Position::new(line as u32, column as u32)));
87+
}
88+
None
89+
}
90+
91+
pub fn check_hover(&mut self, block_str: &str, expect: VirtualHoverResult) -> bool {
92+
let content = Self::handle_file_content(block_str);
93+
let Some((content, position)) = content else {
94+
return false;
95+
};
96+
let file_id = self.def(&content);
97+
let result = hover(&self.analysis, file_id, position);
98+
let Some(result) = result else {
99+
return false;
100+
};
101+
let Hover { contents, range } = result;
102+
let HoverContents::Markup(MarkupContent { kind, value }) = contents else {
103+
return false;
104+
};
105+
if value != expect.value {
106+
return false;
107+
}
108+
109+
true
110+
}
111+
}

0 commit comments

Comments
 (0)