Skip to content

Commit 4b88fbe

Browse files
committed
Add option to increase verbosity of types rendered in hovers
Fix EmmyLua/VSCode-EmmyLua#250
1 parent 5c6f4e1 commit 4b88fbe

File tree

6 files changed

+229
-56
lines changed

6 files changed

+229
-56
lines changed

crates/emmylua_code_analysis/src/config/configs/hover.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@ pub struct EmmyrcHover {
88
#[serde(default = "default_true")]
99
#[schemars(extend("x-vscode-setting" = true))]
1010
pub enable: bool,
11+
12+
/// Increase verbosity of types shown in hovers.
13+
///
14+
/// Enabling this option will increase maximum nesting of displayed types,
15+
/// add alias expansions on top level, increase number of shown members.
16+
#[serde(default)]
17+
#[schemars(extend("x-vscode-setting" = true))]
18+
pub verbose: bool,
1119
}
1220

1321
impl Default for EmmyrcHover {
1422
fn default() -> Self {
1523
Self {
1624
enable: default_true(),
25+
verbose: false,
1726
}
1827
}
1928
}

crates/emmylua_code_analysis/src/db_index/type/humanize_type.rs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use std::collections::HashSet;
2-
31
use itertools::Itertools;
2+
use std::collections::HashSet;
43

54
use crate::{
65
DbIndex, GenericTpl, LuaAliasCallType, LuaFunctionType, LuaGenericType, LuaInstanceType,
@@ -13,6 +12,7 @@ use super::{LuaAliasCallKind, LuaMultiLineUnion};
1312
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1413
pub enum RenderLevel {
1514
Documentation,
15+
Verbose,
1616
Detailed,
1717
Simple,
1818
Normal,
@@ -24,6 +24,7 @@ impl RenderLevel {
2424
pub fn next_level(self) -> RenderLevel {
2525
match self {
2626
RenderLevel::Documentation => RenderLevel::Simple,
27+
RenderLevel::Verbose => RenderLevel::Detailed,
2728
RenderLevel::Detailed => RenderLevel::Simple,
2829
RenderLevel::Simple => RenderLevel::Normal,
2930
RenderLevel::Normal => RenderLevel::Brief,
@@ -74,7 +75,7 @@ pub fn humanize_type(db: &DbIndex, ty: &LuaType, level: RenderLevel) -> String {
7475
LuaType::Ref(id) => {
7576
if let Some(type_decl) = db.get_type_index().get_type_decl(id) {
7677
let name = type_decl.get_full_name().to_string();
77-
humanize_simple_type(db, id, &name, level).unwrap_or(name)
78+
humanize_simple_type(db, id, &name, level)
7879
} else {
7980
id.get_name().to_string()
8081
}
@@ -114,10 +115,7 @@ fn humanize_def_type(db: &DbIndex, id: &LuaTypeDeclId, level: RenderLevel) -> St
114115
let full_name = type_decl.get_full_name();
115116
let generic = match db.get_type_index().get_generic_params(id) {
116117
Some(generic) => generic,
117-
None => {
118-
return humanize_simple_type(db, id, &full_name, level)
119-
.unwrap_or(full_name.to_string());
120-
}
118+
None => return humanize_simple_type(db, id, &full_name, level),
121119
};
122120

123121
let generic_names = generic
@@ -133,15 +131,20 @@ fn humanize_simple_type(
133131
id: &LuaTypeDeclId,
134132
name: &str,
135133
level: RenderLevel,
136-
) -> Option<String> {
137-
if !matches!(level, RenderLevel::Detailed | RenderLevel::Documentation) {
138-
return Some(name.to_string());
134+
) -> String {
135+
if !matches!(
136+
level,
137+
RenderLevel::Detailed | RenderLevel::Verbose | RenderLevel::Documentation
138+
) {
139+
return name.to_string();
139140
}
140141
let max_display_count = 12;
141142

142143
let member_owner = LuaMemberOwner::Type(id.clone());
143144
let member_index = db.get_member_index();
144-
let members = member_index.get_sorted_members(&member_owner)?;
145+
let members = member_index
146+
.get_sorted_members(&member_owner)
147+
.unwrap_or_default();
145148
let mut member_vec = Vec::new();
146149
let mut function_vec = Vec::new();
147150
for member in members {
@@ -159,7 +162,23 @@ fn humanize_simple_type(
159162
}
160163

161164
if member_vec.is_empty() && function_vec.is_empty() {
162-
return Some(name.to_string());
165+
if matches!(level, RenderLevel::Detailed | RenderLevel::Verbose) {
166+
'expand: {
167+
let Some(type_decl) = db.get_type_index().get_type_decl(id) else {
168+
break 'expand;
169+
};
170+
let Some(origin) = type_decl.get_alias_ref() else {
171+
break 'expand;
172+
};
173+
return format!(
174+
"{} {}",
175+
name,
176+
humanize_type(db, &origin, level.next_level())
177+
);
178+
}
179+
}
180+
181+
return name.to_string();
163182
}
164183
let all_count = member_vec.len() + function_vec.len();
165184

@@ -171,7 +190,8 @@ fn humanize_simple_type(
171190
typ,
172191
humanize_type(db, typ, level.next_level()),
173192
level,
174-
);
193+
)
194+
.replace("\n", "\n ");
175195

176196
member_strings.push_str(&format!(" {},\n", member_string));
177197
count += 1;
@@ -186,7 +206,8 @@ fn humanize_simple_type(
186206
&LuaType::Function,
187207
"function".to_string(),
188208
level,
189-
);
209+
)
210+
.replace("\n", "\n ");
190211

191212
member_strings.push_str(&format!(" {},\n", member_string));
192213
count += 1;
@@ -198,7 +219,7 @@ fn humanize_simple_type(
198219
if count >= max_display_count {
199220
member_strings.push_str(&format!(" ...(+{})\n", all_count - max_display_count));
200221
}
201-
Some(format!("{} {{\n{}}}", name, member_strings))
222+
format!("{} {{\n{}}}", name, member_strings)
202223
}
203224

204225
fn humanize_union_type(db: &DbIndex, union: &LuaUnionType, level: RenderLevel) -> String {
@@ -218,6 +239,7 @@ where
218239
let types = union.into_vec();
219240
let num = match level {
220241
RenderLevel::Documentation => 500,
242+
RenderLevel::Verbose => 10,
221243
RenderLevel::Detailed => 8,
222244
RenderLevel::Simple => 6,
223245
RenderLevel::Normal => 4,
@@ -264,6 +286,7 @@ fn humanize_multi_line_union_type(
264286
let members = multi_union.get_unions();
265287
let num = match level {
266288
RenderLevel::Documentation => 500,
289+
RenderLevel::Verbose => 15,
267290
RenderLevel::Detailed => 10,
268291
RenderLevel::Simple => 8,
269292
RenderLevel::Normal => 4,
@@ -304,6 +327,7 @@ fn humanize_tuple_type(db: &DbIndex, tuple: &LuaTupleType, level: RenderLevel) -
304327
let types = tuple.get_types();
305328
let num = match level {
306329
RenderLevel::Documentation => 500,
330+
RenderLevel::Verbose => 15,
307331
RenderLevel::Detailed => 10,
308332
RenderLevel::Simple => 8,
309333
RenderLevel::Normal => 4,
@@ -398,6 +422,7 @@ fn humanize_doc_function_type(
398422
fn humanize_object_type(db: &DbIndex, object: &LuaObjectType, level: RenderLevel) -> String {
399423
let num = match level {
400424
RenderLevel::Documentation => 500,
425+
RenderLevel::Verbose => 15,
401426
RenderLevel::Detailed => 10,
402427
RenderLevel::Simple => 8,
403428
RenderLevel::Normal => 4,
@@ -457,6 +482,7 @@ fn humanize_intersect_type(
457482
) -> String {
458483
let num = match level {
459484
RenderLevel::Documentation => 500,
485+
RenderLevel::Verbose => 15,
460486
RenderLevel::Detailed => 10,
461487
RenderLevel::Simple => 8,
462488
RenderLevel::Normal => 4,
@@ -518,7 +544,8 @@ fn humanize_table_const_type_detail_and_simple(
518544
&type_cache.as_type(),
519545
humanize_type(db, &type_cache.as_type(), level.next_level()),
520546
level,
521-
);
547+
)
548+
.replace("\n", "\n ");
522549

523550
match level {
524551
RenderLevel::Detailed => {
@@ -575,6 +602,7 @@ fn humanize_table_generic_type(
575602
) -> String {
576603
let num = match level {
577604
RenderLevel::Documentation => 500,
605+
RenderLevel::Verbose => 15,
578606
RenderLevel::Detailed => 10,
579607
RenderLevel::Simple => 8,
580608
RenderLevel::Normal => 4,
@@ -622,6 +650,7 @@ fn humanize_variadic_type(db: &DbIndex, multi: &VariadicType, level: RenderLevel
622650
VariadicType::Multi(types) => {
623651
let max_num = match level {
624652
RenderLevel::Documentation => 500,
653+
RenderLevel::Verbose => 15,
625654
RenderLevel::Detailed => 10,
626655
RenderLevel::Simple => 8,
627656
RenderLevel::Normal => 4,

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

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ pub fn build_semantic_info_hover(
3030
semantic_info: SemanticInfo,
3131
range: TextRange,
3232
) -> Option<Hover> {
33+
let verbose = semantic_model.get_emmyrc().hover.verbose;
3334
let typ = semantic_info.clone().typ;
3435
if semantic_info.semantic_decl.is_none() {
35-
return build_hover_without_property(db, document, token, typ);
36+
return build_hover_without_property(db, document, token, typ, verbose);
3637
}
3738
let hover_builder = build_hover_content(
3839
compilation,
@@ -42,6 +43,7 @@ pub fn build_semantic_info_hover(
4243
semantic_info.semantic_decl.unwrap(),
4344
false,
4445
Some(token.clone()),
46+
verbose,
4547
);
4648
if let Some(hover_builder) = hover_builder {
4749
hover_builder.build_hover_result(document.to_lsp_range(range))
@@ -55,8 +57,15 @@ fn build_hover_without_property(
5557
document: &LuaDocument,
5658
token: LuaSyntaxToken,
5759
typ: LuaType,
60+
verbose: bool,
5861
) -> Option<Hover> {
59-
let hover = humanize_type(db, &typ, RenderLevel::Detailed);
62+
let render_level = if verbose {
63+
RenderLevel::Verbose
64+
} else {
65+
RenderLevel::Detailed
66+
};
67+
68+
let hover = humanize_type(db, &typ, render_level);
6069
Some(Hover {
6170
contents: HoverContents::Markup(MarkupContent {
6271
kind: lsp_types::MarkupKind::Markdown,
@@ -89,6 +98,7 @@ pub fn build_hover_content_for_completion<'a>(
8998
property_id,
9099
true,
91100
None,
101+
semantic_model.get_emmyrc().hover.verbose,
92102
)
93103
}
94104

@@ -100,19 +110,20 @@ fn build_hover_content<'a>(
100110
property_id: LuaSemanticDeclId,
101111
is_completion: bool,
102112
token: Option<LuaSyntaxToken>,
113+
verbose: bool,
103114
) -> Option<HoverBuilder<'a>> {
104115
let mut builder = HoverBuilder::new(compilation, semantic_model, token, is_completion);
105116
match property_id {
106117
LuaSemanticDeclId::LuaDecl(decl_id) => {
107118
let typ = typ?;
108-
build_decl_hover(&mut builder, db, typ, decl_id);
119+
build_decl_hover(&mut builder, db, typ, decl_id, verbose);
109120
}
110121
LuaSemanticDeclId::Member(member_id) => {
111122
let typ = typ?;
112-
build_member_hover(&mut builder, db, typ, member_id);
123+
build_member_hover(&mut builder, db, typ, member_id, verbose);
113124
}
114125
LuaSemanticDeclId::TypeDecl(type_decl_id) => {
115-
build_type_decl_hover(&mut builder, db, type_decl_id);
126+
build_type_decl_hover(&mut builder, db, type_decl_id, verbose);
116127
}
117128
_ => return None,
118129
}
@@ -124,6 +135,7 @@ fn build_decl_hover(
124135
db: &DbIndex,
125136
typ: LuaType,
126137
decl_id: LuaDeclId,
138+
verbose: bool,
127139
) -> Option<()> {
128140
let decl = db.get_decl_index().get_decl(&decl_id)?;
129141

@@ -151,7 +163,7 @@ fn build_decl_hover(
151163
semantic_decls.push((semantic_decl, typ.clone()));
152164
}
153165

154-
hover_function_type(builder, db, &semantic_decls);
166+
hover_function_type(builder, db, &semantic_decls, verbose);
155167

156168
if let Some((LuaSemanticDeclId::Member(member_id), _)) = semantic_decls
157169
.iter()
@@ -166,7 +178,7 @@ fn build_decl_hover(
166178
.add_signature_params_rets_description(builder.semantic_model.get_type(decl_id.into()));
167179
} else {
168180
if typ.is_const() {
169-
let const_value = hover_const_type(db, &typ);
181+
let const_value = hover_const_type(db, &typ, verbose);
170182
let prefix = if decl.is_local() {
171183
"local "
172184
} else {
@@ -177,7 +189,7 @@ fn build_decl_hover(
177189
let decl_hover_type =
178190
get_hover_type(builder, builder.semantic_model).unwrap_or(typ.clone());
179191
let type_humanize_text =
180-
hover_humanize_type(builder, &decl_hover_type, Some(RenderLevel::Detailed));
192+
hover_humanize_type(builder, &decl_hover_type, verbose, RenderLevel::Detailed);
181193
let prefix = if decl.is_local() {
182194
"local "
183195
} else {
@@ -209,6 +221,7 @@ fn build_member_hover(
209221
db: &DbIndex,
210222
typ: LuaType,
211223
member_id: LuaMemberId,
224+
verbose: bool,
212225
) -> Option<()> {
213226
let member = db.get_member_index().get_member(&member_id)?;
214227
let mut semantic_decls = find_member_origin_owners(
@@ -245,7 +258,7 @@ fn build_member_hover(
245258
semantic_decls.push((semantic_decl, typ.clone()));
246259
}
247260

248-
hover_function_type(builder, db, &semantic_decls);
261+
hover_function_type(builder, db, &semantic_decls, verbose);
249262

250263
builder.set_location_path(Some(&member));
251264

@@ -255,14 +268,14 @@ fn build_member_hover(
255268
);
256269
} else {
257270
if typ.is_const() {
258-
let const_value = hover_const_type(db, &typ);
271+
let const_value = hover_const_type(db, &typ, verbose);
259272
builder.set_type_description(format!("(field) {}: {}", member_name, const_value));
260273
builder.set_location_path(Some(&member));
261274
} else {
262275
let member_hover_type =
263276
get_hover_type(builder, builder.semantic_model).unwrap_or(typ.clone());
264277
let type_humanize_text =
265-
hover_humanize_type(builder, &member_hover_type, Some(RenderLevel::Simple));
278+
hover_humanize_type(builder, &member_hover_type, verbose, RenderLevel::Simple);
266279
builder
267280
.set_type_description(format!("(field) {}: {}", member_name, type_humanize_text));
268281
builder.set_location_path(Some(&member));
@@ -285,23 +298,27 @@ fn build_type_decl_hover(
285298
builder: &mut HoverBuilder,
286299
db: &DbIndex,
287300
type_decl_id: LuaTypeDeclId,
301+
verbose: bool,
288302
) -> Option<()> {
303+
let render_level = if verbose {
304+
RenderLevel::Verbose
305+
} else {
306+
RenderLevel::Detailed
307+
};
308+
289309
let type_decl = db.get_type_index().get_type_decl(&type_decl_id)?;
290310
let type_description = if type_decl.is_alias() {
291311
if let Some(origin) = type_decl.get_alias_origin(db, None) {
292-
let origin_type = humanize_type(db, &origin, RenderLevel::Detailed);
312+
let origin_type = humanize_type(db, &origin, render_level);
293313
format!("(alias) {} = {}", type_decl.get_name(), origin_type)
294314
} else {
295315
"".to_string()
296316
}
297317
} else if type_decl.is_enum() {
298-
format!("(enum) {}", type_decl.get_name())
318+
let humanize_text = humanize_type(db, &LuaType::Ref(type_decl_id.clone()), render_level);
319+
format!("(enum) {}", humanize_text)
299320
} else {
300-
let humanize_text = humanize_type(
301-
db,
302-
&LuaType::Def(type_decl_id.clone()),
303-
RenderLevel::Detailed,
304-
);
321+
let humanize_text = humanize_type(db, &LuaType::Ref(type_decl_id.clone()), render_level);
305322
format!("(class) {}", humanize_text)
306323
};
307324

0 commit comments

Comments
 (0)