@@ -55,15 +55,35 @@ function local_binding_hover_info(fi::FileInfo, uri::URI, definitions::JS.Syntax
5555 return String (take! (io))
5656end
5757
58+ function type_hover_for_binding (
59+ fi:: FileInfo , mod:: Module , postprocessor:: LSPostProcessor ,
60+ ctx3:: JL.VariableAnalysisContext , inferrable_tree:: JS.SyntaxTree ,
61+ inferrable_binding:: JS.SyntaxTree
62+ )
63+ range = jsobj_to_range (inferrable_binding, fi)
64+ fallback_hover = Hover (;
65+ contents = MarkupContent (; kind = MarkupKind. Markdown, value = " `[Unknown type]`" ),
66+ range)
67+ inferred_tree = @something infer_toplevel_tree (ctx3, inferrable_tree, mod) return fallback_hover
68+ typ = @something get_type_for_range (inferred_tree, JS. byte_range (inferrable_binding)) return fallback_hover
69+ typstr = postprocessor (string (typ):: String )
70+ contents = MarkupContent (;
71+ kind = MarkupKind. Markdown,
72+ value = " ```julia\n $typstr \n ```" )
73+ return Hover (; contents, range)
74+ end
75+
5876function handle_HoverRequest (
59- server:: Server , msg:: HoverRequest , cancel_flag:: CancelFlag )
77+ server:: Server , msg:: HoverRequest , cancel_flag:: CancelFlag
78+ )
6079 state = server. state
6180 uri = msg. params. textDocument. uri
6281 pos = adjust_position (state, uri, msg. params. position)
6382
83+ fallback_response = HoverResponse (; id = msg. id, result = null)
6484 result = get_file_info (state, uri, cancel_flag)
6585 if isnothing (result)
66- return send (server, HoverResponse (; id = msg . id, result = null) )
86+ return send (server, fallback_response )
6787 elseif result isa ResponseError
6888 return send (server, HoverResponse (; id = msg. id, result = nothing , error = result))
6989 end
@@ -73,15 +93,20 @@ function handle_HoverRequest(
7393 offset = xy_to_offset (fi, pos)
7494 (; mod, analyzer, postprocessor) = get_context_info (state, uri, pos)
7595
76- local_hover = local_binding_hover (state, fi, uri, st0_top, offset, mod)
77- isnothing (local_hover) || return send (server, HoverResponse (;
78- id = msg. id,
79- result = local_hover))
96+ inferrable_binding = select_inferrable_binding (st0_top, offset, mod)
97+ if ! isnothing (inferrable_binding)
98+ (; ctx3, st3, binding) = inferrable_binding
99+ if is_from_user_ast (binding)
100+ binfo = JL. get_binding (ctx3, binding):: JL.BindingInfo
101+ if binfo. kind === :local || binfo. kind === :argument
102+ result = type_hover_for_binding (fi, mod, postprocessor, ctx3, st3, binding)
103+ return send (server, HoverResponse (; id = msg. id, result))
104+ end
105+ end
106+ end
80107
81108 node = @something select_target_identifier (st0_top, offset) begin
82- tok = @something token_at_offset (fi, pos) begin
83- return send (server, HoverResponse (; id = msg. id, result = null))
84- end
109+ tok = @something token_at_offset (fi, pos) return send (server, fallback_response)
85110 byterng = JS. byte_range (tok)
86111 tokstr = String (fi. parsed_stream. textbuf[byterng])
87112 if haskey (KEYWORD_DOCS, tokstr)
@@ -90,43 +115,43 @@ function handle_HoverRequest(
90115 start = offset_to_xy (fi, first (byterng)),
91116 var"end" = offset_to_xy (fi, last (byterng)+ 1 ))
92117 range, _ = unadjust_range (state, uri, range)
93- return send (server, HoverResponse (;
94- id = msg. id,
95- result = Hover (; contents, range)))
118+ result = Hover (; contents, range)
119+ return send (server, HoverResponse (; id = msg. id, result))
96120 end
97- return send (server, HoverResponse (; id = msg . id, result = null) )
121+ return send (server, fallback_response )
98122 end
99123
100- parentmod = mod
101- identifier_node = node
102-
103124 # TODO replace this AST hack with a proper abstract interpretation to resolve binding information
104- if JS. kind (node) === JS. K " ." && JS. numchildren (node) ≥ 2
105- dotprefix = node[1 ]
125+ identifier_node = node
126+ if JS. kind (identifier_node) === JS. K " ." && JS. numchildren (identifier_node) ≥ 2
127+ dotprefix = identifier_node[1 ]
106128 dotprefixtyp = resolve_type (analyzer, mod, dotprefix)
107129 if dotprefixtyp isa Core. Const
108130 dotprefixval = dotprefixtyp. val
109131 if dotprefixval isa Module
110- parentmod = dotprefixval
111- identifier_node = node [2 ]
132+ mod = dotprefixval
133+ identifier_node = identifier_node [2 ]
112134 # EST wraps the RHS of dot expressions in `K"inert"`
113135 if JS. kind (identifier_node) === JS. K " inert" && JS. numchildren (identifier_node) ≥ 1
114136 identifier_node = identifier_node[1 ]
115137 end
116138 end
117139 end
118140 end
119- if ! JS. is_identifier (identifier_node)
120- return send (server, HoverResponse (; id = msg. id, result = null))
141+
142+ JS. is_identifier (identifier_node) || return send (server, fallback_response)
143+ identifier = try
144+ JL. est_to_expr (identifier_node)
145+ catch
146+ return send (server, fallback_response)
121147 end
122- identifier = Symbol (identifier_node. name_val)
123- documentation = @invokelatest (Base. Docs. doc (DocsBinding (parentmod, identifier))):: Markdown.MD
148+ identifier isa Symbol || return send (server, fallback_response)
149+
150+ documentation = @invokelatest (Base. Docs. doc (DocsBinding (mod, identifier))):: Markdown.MD
124151 value = postprocessor (documentation)
125152 contents = MarkupContent (; kind = MarkupKind. Markdown, value)
126153 range, _ = unadjust_range (state, uri, jsobj_to_range (node, fi))
127- return send (server, HoverResponse (;
128- id = msg. id,
129- result = Hover (; contents, range)))
154+ return send (server, HoverResponse (; id = msg. id, result = Hover (; contents, range)))
130155end
131156
132157@eval function DocsBinding (parentmod:: Module , identifier:: Symbol )
0 commit comments