1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{
config::InlayHintsConfig,
core::{
session::Session,
token::{get_range_from_span, TypedAstToken},
},
};
use std::sync::Arc;
use sway_core::{language::ty::TyDecl, type_system::TypeInfo, Engines};
use sway_types::Spanned;
use tower_lsp::lsp_types::{self, Range, Url};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InlayKind {
TypeHint,
}
#[derive(Debug)]
pub struct InlayHint {
pub range: Range,
pub kind: InlayKind,
pub label: String,
}
pub(crate) fn inlay_hints(
session: Arc<Session>,
uri: &Url,
range: &Range,
config: &InlayHintsConfig,
) -> Option<Vec<lsp_types::InlayHint>> {
if !config.type_hints {
return None;
}
let type_engine = session.type_engine.read();
let decl_engine = session.decl_engine.read();
let engines = Engines::new(&type_engine, &decl_engine);
let hints: Vec<lsp_types::InlayHint> = session
.token_map()
.tokens_for_file(uri)
.filter_map(|(_, token)| {
token.typed.as_ref().and_then(|t| match t {
TypedAstToken::TypedDeclaration(TyDecl::VariableDecl(var_decl)) => {
match var_decl.type_ascription.call_path_tree {
Some(_) => None,
None => {
let var_range = get_range_from_span(&var_decl.name.span());
if var_range.start >= range.start && var_range.end <= range.end {
Some(var_decl.clone())
} else {
None
}
}
}
}
_ => None,
})
})
.filter_map(|var| {
let type_info = type_engine.get(var.type_ascription.type_id);
match type_info {
TypeInfo::Unknown | TypeInfo::UnknownGeneric { .. } => None,
_ => Some(var),
}
})
.map(|var| {
let range = get_range_from_span(&var.name.span());
let kind = InlayKind::TypeHint;
let label = format!("{}", engines.help_out(var.type_ascription));
let inlay_hint = InlayHint { range, kind, label };
self::inlay_hint(config.render_colons, inlay_hint)
})
.collect();
Some(hints)
}
fn inlay_hint(render_colons: bool, inlay_hint: InlayHint) -> lsp_types::InlayHint {
lsp_types::InlayHint {
position: match inlay_hint.kind {
InlayKind::TypeHint => inlay_hint.range.end,
},
label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
_ => inlay_hint.label,
}),
kind: match inlay_hint.kind {
InlayKind::TypeHint => Some(lsp_types::InlayHintKind::TYPE),
},
tooltip: None,
padding_left: Some(match inlay_hint.kind {
InlayKind::TypeHint => !render_colons,
}),
padding_right: Some(match inlay_hint.kind {
InlayKind::TypeHint => false,
}),
text_edits: None,
data: None,
}
}