@@ -111,6 +111,221 @@ pub fn (mut c Checker) autocomplete_for_fn_call_expr(node ast.CallExpr) {
111111 exit (0 )
112112}
113113
114+ fn (mut c Checker) ident_hover (node_ ast.Expr) {
115+ if c.pref.linfo.method != .hover {
116+ return
117+ }
118+ if ! c.vls_is_the_node (node_.pos ()) {
119+ return
120+ }
121+ mut node := unsafe { node_ }
122+ mut declaration := ''
123+ mut doc := ''
124+ match mut node {
125+ ast.CallExpr {
126+ if ! c.vls_is_the_node (node.name_pos) {
127+ return
128+ }
129+ f := c.get_fn_from_call_expr (node) or { return }
130+ fn_name := f.name.all_after_last ('.' )
131+ mut params := []string {cap: f.params.len}
132+ for i, param in f.params {
133+ if f.is_method && i == 0 {
134+ continue
135+ }
136+ params << '${param.name} ${c.table.type_to_str(param.typ)} '
137+ }
138+ ret_str := if f.return_type != ast.no_type && f.return_type != ast.void_type {
139+ ' ' + c.table.type_to_str (f.return_type)
140+ } else {
141+ ''
142+ }
143+ declaration = 'fn ${fn_name} (${params.join(', ')} )${ret_str} '
144+ receiver := if f.is_method {
145+ c.table.sym (f.receiver_type).name.all_after_last ('.' )
146+ } else {
147+ ''
148+ }
149+ if info := c.table.vls_info['fn_${f.mod} [${receiver} ]${fn_name} ' ] {
150+ doc = info.doc
151+ }
152+ }
153+ ast.Ident {
154+ for _, obj in c.table.global_scope.objects {
155+ if obj is ast.ConstField && obj.name == node.name {
156+ type_str := c.table.type_to_str (obj.typ)
157+ declaration = 'const ${node.name.all_after_last('.')} ${type_str} '
158+ if info := c.table.vls_info['const_${obj.name} ' ] {
159+ doc = info.doc
160+ }
161+ break
162+ } else if obj is ast.GlobalField && obj.name == node.name {
163+ type_str := c.table.type_to_str (obj.typ)
164+ declaration = '__global ${node.name.all_after_last('.')} ${type_str} '
165+ break
166+ }
167+ }
168+ if declaration == '' && ! isnil (c.fn_scope) {
169+ if obj := c.fn_scope.find_var (node.name) {
170+ type_str := c.table.type_to_str (obj.typ)
171+ declaration = '${node.name} ${type_str} '
172+ }
173+ }
174+ if declaration == '' {
175+ full_name := if node.mod != '' { '${node.mod} .${node.name} ' } else { node.name }
176+ idx := c.table.find_type_idx (full_name)
177+ if idx > 0 {
178+ sym := c.table.type_symbols[idx]
179+ declaration = c.vls_hover_type_declaration (sym)
180+ key := c.vls_hover_type_info_key (sym)
181+ if info := c.table.vls_info['${key} _${sym.name} ' ] {
182+ doc = info.doc
183+ }
184+ }
185+ }
186+ }
187+ ast.SelectorExpr {
188+ sym := c.table.sym (node.expr_type)
189+ if field := c.table.find_field_with_embeds (sym, node.field_name) {
190+ type_str := c.table.type_to_str (field.typ)
191+ declaration = '${node.field_name} ${type_str} '
192+ } else if method := c.table.find_method (sym, node.field_name) {
193+ fn_name := method.name.all_after_last ('.' )
194+ mut params := []string {cap: method.params.len}
195+ for i, param in method.params {
196+ if method.is_method && i == 0 {
197+ continue
198+ }
199+ params << '${param.name} ${c.table.type_to_str(param.typ)} '
200+ }
201+ ret_str := if method.return_type != ast.no_type
202+ && method.return_type != ast.void_type {
203+ ' ' + c.table.type_to_str (method.return_type)
204+ } else {
205+ ''
206+ }
207+ declaration = 'fn ${fn_name} (${params.join(', ')} )${ret_str} '
208+ receiver_name := sym.name.all_after_last ('.' )
209+ if info := c.table.vls_info['fn_${method.mod} [${receiver_name} ]${fn_name} ' ] {
210+ doc = info.doc
211+ }
212+ } else {
213+ return
214+ }
215+ }
216+ ast.StructInit {
217+ if c.vls_is_the_node (node.name_pos) {
218+ sym := c.table.sym (node.typ)
219+ declaration = c.vls_hover_type_declaration (sym)
220+ key := c.vls_hover_type_info_key (sym)
221+ if info := c.table.vls_info['${key} _${sym.name} ' ] {
222+ doc = info.doc
223+ }
224+ } else {
225+ for field in node.init_fields {
226+ if c.vls_is_the_node (field.name_pos) {
227+ sym := c.table.sym (node.typ)
228+ if struct_field := c.table.find_field_with_embeds (sym, field.name) {
229+ type_str := c.table.type_to_str (struct_field.typ)
230+ declaration = '${field.name} ${type_str} '
231+ }
232+ break
233+ }
234+ }
235+ }
236+ }
237+ ast.EnumVal {
238+ enum_name := if node.enum_name == '' && node.typ != ast.void_type && node.typ != 0 {
239+ c.table.sym (node.typ).name
240+ } else {
241+ node.enum_name
242+ }
243+ declaration = '${enum_name.all_after_last('.')} .${node.val} '
244+ }
245+ ast.TypeNode {
246+ typ_str := c.table.type_to_str (node.typ)
247+ idx := c.table.find_type_idx (typ_str)
248+ if idx > 0 {
249+ sym := c.table.type_symbols[idx]
250+ declaration = c.vls_hover_type_declaration (sym)
251+ key := c.vls_hover_type_info_key (sym)
252+ if info := c.table.vls_info['${key} _${sym.name} ' ] {
253+ doc = info.doc
254+ }
255+ }
256+ }
257+ ast.CastExpr {
258+ typ_str := if node.typname != '' {
259+ node.typname
260+ } else {
261+ c.table.type_to_str (node.typ)
262+ }
263+ idx := c.table.find_type_idx (typ_str)
264+ if idx > 0 {
265+ sym := c.table.type_symbols[idx]
266+ declaration = c.vls_hover_type_declaration (sym)
267+ key := c.vls_hover_type_info_key (sym)
268+ if info := c.table.vls_info['${key} _${sym.name} ' ] {
269+ doc = info.doc
270+ }
271+ }
272+ }
273+ else {}
274+ }
275+ if declaration == '' {
276+ exit (0 )
277+ }
278+ c.vls_write_hover (declaration, doc)
279+ exit (0 )
280+ }
281+
282+ fn (c &Checker) vls_hover_type_declaration (sym ast.TypeSymbol) string {
283+ name := sym.name.all_after_last ('.' )
284+ match sym.kind {
285+ .struct {
286+ return 'struct ${name} '
287+ }
288+ .enum {
289+ return 'enum ${name} '
290+ }
291+ .interface {
292+ return 'interface ${name} '
293+ }
294+ .alias {
295+ alias_info := sym.info as ast.Alias
296+ parent_str := c.table.type_to_str (alias_info.parent_type)
297+ return 'type ${name} = ${parent_str} '
298+ }
299+ .sum_type {
300+ sum_info := sym.info as ast.SumType
301+ variants := sum_info.variants.map (c.table.type_to_str (it )).join (' | ' )
302+ return 'type ${name} = ${variants} '
303+ }
304+ else {
305+ return name
306+ }
307+ }
308+ }
309+
310+ fn (c &Checker) vls_hover_type_info_key (sym ast.TypeSymbol) string {
311+ return match sym.kind {
312+ .alias { 'aliastype' }
313+ .sum_type { 'sumtype' }
314+ else { '${sym.kind} ' }
315+ }
316+ }
317+
318+ fn (c &Checker) vls_write_hover (declaration string , doc string ) {
319+ mut lines := ['```v' , declaration, '```' ]
320+ if doc.len > 0 {
321+ lines << ''
322+ lines << doc
323+ }
324+ value := lines.join ('\n ' ).replace ('\\ ' , '\\\\ ' ).replace ('"' , '\\ "' ).replace ('\n ' ,
325+ '\\ n' )
326+ println ('{"contents":{"kind":"markdown","value":"${value} "}}' )
327+ }
328+
114329fn (mut c Checker) name_pos_gotodef (name string ) ? token.Pos {
115330 idx := c.table.find_type_idx (name)
116331 if idx > 0 {
0 commit comments