diff --git a/examples/associated_functions.reid b/examples/associated_functions.reid index 9bf7b6c..f399626 100644 --- a/examples/associated_functions.reid +++ b/examples/associated_functions.reid @@ -8,9 +8,8 @@ struct Otus { } impl Otus { - /// Some test documentation - /// Here - /// qwe + /// Some test documentation here. + /// On a second line fn test(&self) -> u32 { *self.field } diff --git a/reid-lsp/src/analysis.rs b/reid-lsp/src/analysis.rs index 55a5e7e..ba5ec30 100644 --- a/reid-lsp/src/analysis.rs +++ b/reid-lsp/src/analysis.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, hash::Hash, path::PathBuf}; use reid::{ ast::{ + ReturnType, lexer::{FullToken, Token}, token_stream::TokenRange, }, @@ -84,7 +85,7 @@ impl StaticAnalysis { #[derive(Debug, Clone)] pub struct SemanticToken { - pub ty: Option, + pub hover: Option, pub autocomplete: Vec, pub symbol: Option, } @@ -103,6 +104,18 @@ pub enum AutocompleteKind { Function(Vec, TypeKind), } +#[derive(Debug, Clone)] +pub struct Hover { + pub documentation: Option, + pub kind: Option, +} + +#[derive(Debug, Clone)] +pub enum HoverKind { + Type(TypeKind), + Function(String, Vec, TypeKind), +} + impl ToString for AutocompleteKind { fn to_string(&self) -> String { match self { @@ -149,12 +162,15 @@ impl AnalysisState { } impl AnalysisState { - pub fn init_types(&mut self, meta: &mir::Metadata, ty: Option) { + pub fn init_hover(&mut self, meta: &mir::Metadata, kind: Option, documentation: Option) { for token in meta.range.start..=meta.range.end { self.map.insert( token, SemanticToken { - ty: ty.clone(), + hover: Some(Hover { + documentation: documentation.clone(), + kind: kind.clone(), + }), autocomplete: Vec::new(), symbol: Default::default(), }, @@ -169,7 +185,7 @@ impl AnalysisState { self.map.insert( token_idx, SemanticToken { - ty: None, + hover: None, autocomplete: autocomplete.clone(), symbol: Default::default(), }, @@ -185,7 +201,7 @@ impl AnalysisState { self.map.insert( idx, SemanticToken { - ty: None, + hover: None, autocomplete: Vec::new(), symbol: Some(symbol), }, @@ -533,7 +549,7 @@ pub fn analyze_context( .token_idx(&field.2, |t| matches!(t, Token::Identifier(_))) .unwrap_or(field.2.range.end); - scope.state.init_types( + scope.state.init_hover( &Metadata { source_module_id: field.2.source_module_id, range: TokenRange { @@ -542,7 +558,8 @@ pub fn analyze_context( }, position: None, }, - Some(field.1.clone()), + Some(HoverKind::Type(field.1.clone())), + None, ); let field_symbol = scope.state.new_symbol(field_idx, SemanticKind::Property); @@ -584,7 +601,7 @@ pub fn analyze_context( scope.state.new_symbol(field_ty_idx, SemanticKind::Type) }; - scope.state.init_types( + scope.state.init_hover( &Metadata { source_module_id: field.2.source_module_id, range: TokenRange { @@ -593,7 +610,8 @@ pub fn analyze_context( }, position: None, }, - Some(field.1.clone()), + Some(HoverKind::Type(field.1.clone())), + None, ); scope.state.set_symbol(field_ty_idx, field_ty_symbol); } @@ -604,7 +622,9 @@ pub fn analyze_context( for binop in &module.binop_defs { if binop.meta.source_module_id == module.module_id { for param in [&binop.lhs, &binop.rhs] { - scope.state.init_types(¶m.meta, Some(param.ty.clone())); + scope + .state + .init_hover(¶m.meta, Some(HoverKind::Type(param.ty.clone())), None); let idx = scope .token_idx(¶m.meta, |t| matches!(t, Token::Identifier(_))) .unwrap_or(param.meta.range.end); @@ -679,9 +699,11 @@ pub fn analyze_context( } } - scope - .state - .init_types(&function.signature(), Some(function.return_type.clone())); + scope.state.init_hover( + &function.signature(), + Some(HoverKind::Type(function.return_type.clone())), + None, + ); let idx = scope .token_idx(&function.signature(), |t| matches!(t, Token::Identifier(_))) @@ -713,7 +735,7 @@ pub fn analyze_context( } for import in &module.imports { - scope.state.init_types(&import.1, None); + scope.state.init_hover(&import.1, None, None); if let Some((module_name, _)) = import.0.get(0) { let module_idx = scope .token_idx(&import.1, |t| matches!(t, Token::Identifier(_))) @@ -793,7 +815,9 @@ pub fn analyze_function_parameters( scope: &mut AnalysisScope, ) { for param in &function.parameters { - scope.state.init_types(¶m.meta, Some(param.ty.clone())); + scope + .state + .init_hover(¶m.meta, Some(HoverKind::Type(param.ty.clone())), None); if param.meta.source_module_id == module.module_id { let param_var_idx = scope @@ -832,12 +856,14 @@ pub fn analyze_block( for statement in &block.statements { match &statement.0 { mir::StmtKind::Let(named_variable_ref, _, expression) => { - scope.state.init_types( + scope.state.init_hover( &named_variable_ref.2, expression .return_type(&TypeRefs::unknown(), source_module.module_id) .ok() - .map(|(_, ty)| ty), + .map(|(_, ty)| ty) + .map(|t| HoverKind::Type(t)), + None, ); let idx = scope .token_idx(&named_variable_ref.2, |t| matches!(t, Token::Identifier(_))) @@ -888,16 +914,19 @@ pub fn analyze_expr( expr: &mir::Expression, scope: &mut AnalysisScope, ) { - scope.state.init_types( + scope.state.init_hover( &expr.1, expr.return_type(&TypeRefs::unknown(), source_module.module_id) .ok() - .map(|(_, t)| t), + .map(|(_, t)| HoverKind::Type(t)), + None, ); match &expr.0 { mir::ExprKind::Variable(var_ref) => { - scope.state.init_types(&var_ref.2, Some(var_ref.0.clone())); + scope + .state + .init_hover(&var_ref.2, Some(HoverKind::Type(var_ref.0.clone())), None); let idx = scope .token_idx(&var_ref.2, |t| matches!(t, Token::Identifier(_))) diff --git a/reid-lsp/src/main.rs b/reid-lsp/src/main.rs index 609ee94..5609ca5 100644 --- a/reid-lsp/src/main.rs +++ b/reid-lsp/src/main.rs @@ -213,10 +213,29 @@ impl LanguageServer for Backend { character: (end.0 as i32 - 1).max(0) as u32, }, }; - if let Some(ty) = analysis.ty.clone() { - (Some(range), format!("{}", ty)) + if let Some(hover) = analysis.hover.clone() { + if let Some(kind) = hover.kind { + match kind { + analysis::HoverKind::Type(type_kind) => (Some(range), format!("{}", type_kind)), + analysis::HoverKind::Function(name, function_params, return_type) => ( + Some(range), + format!( + "{}({}) -> {}", + name, + function_params + .iter() + .map(|p| format!("{}: {}", p.name, p.ty)) + .collect::>() + .join(", "), + return_type + ), + ), + } + } else { + (Some(range), String::from("No type")) + } } else { - (Some(range), String::from("None type")) + (Some(range), String::from("No hover")) } } else { (None, String::from("no type"))