@@ -4,16 +4,16 @@ use async_lsp::lsp_types::{
44 HoverContents , MarkupContent , MarkupKind , Position , Url ,
55} ;
66use itertools:: Itertools ;
7-
7+ use yara_x :: mods :: reflect :: Type ;
88use yara_x_parser:: cst:: { Immutable , Node , NodeOrToken , SyntaxKind , Utf8 } ;
99
1010use crate :: documents:: storage:: DocumentStorage ;
1111use crate :: utils:: cst_traversal:: {
12- find_declaration, pattern_from_ident, rule_containing_token ,
13- token_at_position,
12+ find_declaration, pattern_from_ident, prev_non_trivia_token ,
13+ rule_containing_token , token_at_position,
1414} ;
1515
16- use crate :: utils:: modules:: { get_struct , ty_to_string} ;
16+ use crate :: utils:: modules:: { get_type , ty_to_string} ;
1717
1818/// Builder for hover Markdown representation of a rule.
1919struct RuleHoverBuilder {
@@ -106,37 +106,71 @@ pub fn hover(
106106 }
107107 // Other identifiers.
108108 SyntaxKind :: IDENT => {
109- if let Some ( yara_x:: mods:: reflect:: Type :: Func ( func) ) =
110- get_struct ( & token)
111- {
112- let documentation = func
113- . signatures
114- . iter ( )
115- . filter_map ( |signature| {
116- signature. doc ( ) . map ( |doc| {
117- format ! (
118- "### `{}({}) -> {}`\n \n ***\n \n {}\n \n ***\n \n " ,
119- token. text( ) ,
120- signature
121- . args( )
122- . map( |( name, ty) | format!(
123- "{}: {}" ,
124- name,
125- ty_to_string( ty)
126- ) )
127- . join( ", " ) ,
128- ty_to_string( signature. ret_type( ) ) ,
129- doc
130- )
131- } )
132- } )
133- . join ( "\n " ) ;
134-
135- return Some ( HoverContents :: Markup ( MarkupContent {
136- kind : MarkupKind :: Markdown ,
137- value : documentation,
138- } ) ) ;
109+ let structure = prev_non_trivia_token ( & token)
110+ . filter ( |token| token. kind ( ) == SyntaxKind :: DOT )
111+ . and_then ( |token| prev_non_trivia_token ( & token) )
112+ . and_then ( |token| get_type ( & token) )
113+ . and_then ( |ty| {
114+ if let Type :: Struct ( s) = ty { Some ( s) } else { None }
115+ } ) ;
116+
117+ let field = structure
118+ . as_ref ( )
119+ . and_then ( |s| s. fields ( ) . find ( |f| f. name ( ) == token. text ( ) ) ) ;
120+
121+ if let Some ( field) = field {
122+ match field. ty ( ) {
123+ Type :: Func ( func) => {
124+ let documentation = func
125+ . signatures
126+ . iter ( )
127+ . filter_map ( |signature| {
128+ signature. doc ( ) . map ( |doc| {
129+ format ! (
130+ "### `{}({}) -> {}`\n \n ***\n \n {}\n \n ***\n \n " ,
131+ token. text( ) ,
132+ signature
133+ . args( )
134+ . map( |( arg_name, arg_ty) | format!(
135+ "{}: {}" ,
136+ arg_name,
137+ ty_to_string( arg_ty)
138+ ) )
139+ . join( ", " ) ,
140+ ty_to_string( signature. ret_type( ) ) ,
141+ doc
142+ )
143+ } )
144+ } )
145+ . join ( "\n " ) ;
146+
147+ if !documentation. is_empty ( ) {
148+ return Some ( HoverContents :: Markup (
149+ MarkupContent {
150+ kind : MarkupKind :: Markdown ,
151+ value : documentation,
152+ } ,
153+ ) ) ;
154+ }
155+ }
156+ ty => {
157+ let mut value = format ! (
158+ "### `{}: {}`" ,
159+ token. text( ) ,
160+ ty_to_string( & ty)
161+ ) ;
162+ if let Some ( d) = field. doc ( ) {
163+ value
164+ . push_str ( & format ! ( "\n \n ***\n \n {}\n \n ***" , d) ) ;
165+ }
166+ return Some ( HoverContents :: Markup ( MarkupContent {
167+ kind : MarkupKind :: Markdown ,
168+ value,
169+ } ) ) ;
170+ }
171+ }
139172 }
173+
140174 if let Some ( ( _, n) ) = find_declaration ( & token) {
141175 let text = n
142176 . children_with_tokens ( )
0 commit comments