Add documentation to hovers
This commit is contained in:
		
							parent
							
								
									6dccab8b12
								
							
						
					
					
						commit
						dcb4e76a40
					
				| @ -193,6 +193,33 @@ impl AnalysisState { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn set_documentation(&mut self, token_idx: usize, documentation: Option<String>) { | ||||||
|  |         if let Some(documentation) = documentation { | ||||||
|  |             if let Some(token) = self.map.get_mut(&token_idx) { | ||||||
|  |                 if let Some(hover) = &mut token.hover { | ||||||
|  |                     hover.documentation = Some(documentation); | ||||||
|  |                 } else { | ||||||
|  |                     token.hover = Some(Hover { | ||||||
|  |                         documentation: Some(documentation), | ||||||
|  |                         kind: None, | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 self.map.insert( | ||||||
|  |                     token_idx, | ||||||
|  |                     SemanticToken { | ||||||
|  |                         hover: Some(Hover { | ||||||
|  |                             documentation: Some(documentation), | ||||||
|  |                             kind: None, | ||||||
|  |                         }), | ||||||
|  |                         autocomplete: Vec::new(), | ||||||
|  |                         symbol: Default::default(), | ||||||
|  |                     }, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn set_symbol(&mut self, idx: usize, symbol: SymbolId) { |     pub fn set_symbol(&mut self, idx: usize, symbol: SymbolId) { | ||||||
|         self.symbol_to_token.insert(symbol, idx); |         self.symbol_to_token.insert(symbol, idx); | ||||||
|         if let Some(token) = self.map.get_mut(&idx) { |         if let Some(token) = self.map.get_mut(&idx) { | ||||||
| @ -246,8 +273,8 @@ pub struct AnalysisScope<'a> { | |||||||
|     tokens: &'a Vec<FullToken>, |     tokens: &'a Vec<FullToken>, | ||||||
|     variables: HashMap<String, SymbolId>, |     variables: HashMap<String, SymbolId>, | ||||||
|     types: HashMap<TypeKind, (SourceModuleId, SymbolId)>, |     types: HashMap<TypeKind, (SourceModuleId, SymbolId)>, | ||||||
|     functions: HashMap<String, (SourceModuleId, SymbolId)>, |     functions: HashMap<String, (SourceModuleId, SymbolId, Option<String>)>, | ||||||
|     associated_functions: HashMap<(TypeKind, String), (SourceModuleId, SymbolId)>, |     associated_functions: HashMap<(TypeKind, String), (SourceModuleId, SymbolId, Option<String>)>, | ||||||
|     map: &'a StateMap, |     map: &'a StateMap, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -646,9 +673,10 @@ pub fn analyze_context( | |||||||
|             if source_id != module.module_id { |             if source_id != module.module_id { | ||||||
|                 if let Some(state) = map.get(&source_id) { |                 if let Some(state) = map.get(&source_id) { | ||||||
|                     if let Some(symbol) = state.associated_functions.get(&(ty.clone(), function.name.clone())) { |                     if let Some(symbol) = state.associated_functions.get(&(ty.clone(), function.name.clone())) { | ||||||
|                         scope |                         scope.associated_functions.insert( | ||||||
|                             .associated_functions |                             (ty.clone(), function.name.clone()), | ||||||
|                             .insert((ty.clone(), function.name.clone()), (source_id, *symbol)); |                             (source_id, *symbol, function.documentation.clone()), | ||||||
|  |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 continue; |                 continue; | ||||||
| @ -664,9 +692,10 @@ pub fn analyze_context( | |||||||
|             .state |             .state | ||||||
|             .associated_functions |             .associated_functions | ||||||
|             .insert((ty.clone(), function.name.clone()), symbol); |             .insert((ty.clone(), function.name.clone()), symbol); | ||||||
|         scope |         scope.associated_functions.insert( | ||||||
|             .associated_functions |             (ty.clone(), function.name.clone()), | ||||||
|             .insert((ty.clone(), function.name.clone()), (module.module_id, symbol)); |             (module.module_id, symbol, function.documentation.clone()), | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (_, function) in &module.associated_functions { |     for (_, function) in &module.associated_functions { | ||||||
| @ -692,7 +721,10 @@ pub fn analyze_context( | |||||||
|             if source_id != module.module_id { |             if source_id != module.module_id { | ||||||
|                 if let Some(state) = map.get(&source_id) { |                 if let Some(state) = map.get(&source_id) { | ||||||
|                     if let Some(symbol) = state.functions.get(&function.name) { |                     if let Some(symbol) = state.functions.get(&function.name) { | ||||||
|                         scope.functions.insert(function.name.clone(), (source_id, *symbol)); |                         scope.functions.insert( | ||||||
|  |                             function.name.clone(), | ||||||
|  |                             (source_id, *symbol, function.documentation.clone()), | ||||||
|  |                         ); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 continue; |                 continue; | ||||||
| @ -702,7 +734,7 @@ pub fn analyze_context( | |||||||
|         scope.state.init_hover( |         scope.state.init_hover( | ||||||
|             &function.signature(), |             &function.signature(), | ||||||
|             Some(HoverKind::Type(function.return_type.clone())), |             Some(HoverKind::Type(function.return_type.clone())), | ||||||
|             None, |             function.documentation.clone(), | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         let idx = scope |         let idx = scope | ||||||
| @ -711,9 +743,10 @@ pub fn analyze_context( | |||||||
|         let function_symbol = scope.state.new_symbol(idx, SemanticKind::Function); |         let function_symbol = scope.state.new_symbol(idx, SemanticKind::Function); | ||||||
|         scope.state.set_symbol(idx, function_symbol); |         scope.state.set_symbol(idx, function_symbol); | ||||||
|         scope.state.functions.insert(function.name.clone(), function_symbol); |         scope.state.functions.insert(function.name.clone(), function_symbol); | ||||||
|         scope |         scope.functions.insert( | ||||||
|             .functions |             function.name.clone(), | ||||||
|             .insert(function.name.clone(), (module.module_id, function_symbol)); |             (module.module_id, function_symbol, function.documentation.clone()), | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for function in &module.functions { |     for function in &module.functions { | ||||||
| @ -777,10 +810,12 @@ pub fn analyze_context( | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             let symbol = if let Some((source_id, symbol_id)) = scope.functions.get(&import_name) { |             let symbol = if let Some((source_id, symbol_id, doc)) = scope.functions.get(&import_name) { | ||||||
|                 scope |                 let symbol_id = scope | ||||||
|                     .state |                     .state | ||||||
|                     .new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id)) |                     .new_symbol(import_idx, SemanticKind::Reference(*source_id, *symbol_id)); | ||||||
|  |                 scope.state.set_documentation(import_idx, doc.clone()); | ||||||
|  |                 symbol_id | ||||||
|             } else if let Some(module_source) = scope.map.values().find(|s| s.module_name == *module_name) { |             } else if let Some(module_source) = scope.map.values().find(|s| s.module_name == *module_name) { | ||||||
|                 if let Some((source_id, symbol_id)) = scope.types.get(&TypeKind::CustomType(CustomTypeKey( |                 if let Some((source_id, symbol_id)) = scope.types.get(&TypeKind::CustomType(CustomTypeKey( | ||||||
|                     import_name.clone(), |                     import_name.clone(), | ||||||
| @ -1070,10 +1105,12 @@ pub fn analyze_expr( | |||||||
|             let idx = scope |             let idx = scope | ||||||
|                 .token_idx(&meta, |t| matches!(t, Token::Identifier(_))) |                 .token_idx(&meta, |t| matches!(t, Token::Identifier(_))) | ||||||
|                 .unwrap_or(meta.range.end); |                 .unwrap_or(meta.range.end); | ||||||
|             let symbol = if let Some((module_id, symbol_id)) = scope.functions.get(name) { |             let symbol = if let Some((module_id, symbol_id, doc)) = scope.functions.get(name) { | ||||||
|                 scope |                 let symbol = scope | ||||||
|                     .state |                     .state | ||||||
|                     .new_symbol(idx, SemanticKind::Reference(*module_id, *symbol_id)) |                     .new_symbol(idx, SemanticKind::Reference(*module_id, *symbol_id)); | ||||||
|  |                 scope.state.set_documentation(idx, doc.clone()); | ||||||
|  |                 symbol | ||||||
|             } else { |             } else { | ||||||
|                 scope.state.new_symbol(idx, SemanticKind::Function) |                 scope.state.new_symbol(idx, SemanticKind::Function) | ||||||
|             }; |             }; | ||||||
| @ -1106,12 +1143,14 @@ pub fn analyze_expr( | |||||||
|             let fn_idx = scope |             let fn_idx = scope | ||||||
|                 .token_idx(&meta, |t| matches!(t, Token::Identifier(_))) |                 .token_idx(&meta, |t| matches!(t, Token::Identifier(_))) | ||||||
|                 .unwrap_or(meta.range.end); |                 .unwrap_or(meta.range.end); | ||||||
|             let fn_symbol = if let Some((module_id, symbol_id)) = |             let fn_symbol = if let Some((module_id, symbol_id, doc)) = | ||||||
|                 scope.associated_functions.get(&(invoked_ty.clone(), name.clone())) |                 scope.associated_functions.get(&(invoked_ty.clone(), name.clone())) | ||||||
|             { |             { | ||||||
|                 scope |                 let symbol = scope | ||||||
|                     .state |                     .state | ||||||
|                     .new_symbol(fn_idx, SemanticKind::Reference(*module_id, *symbol_id)) |                     .new_symbol(fn_idx, SemanticKind::Reference(*module_id, *symbol_id)); | ||||||
|  |                 scope.state.set_documentation(fn_idx, doc.clone()); | ||||||
|  |                 symbol | ||||||
|             } else { |             } else { | ||||||
|                 scope.state.new_symbol(fn_idx, SemanticKind::Function) |                 scope.state.new_symbol(fn_idx, SemanticKind::Function) | ||||||
|             }; |             }; | ||||||
|  | |||||||
| @ -12,12 +12,12 @@ use tower_lsp::lsp_types::{ | |||||||
|     self, CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, |     self, CompletionItem, CompletionItemKind, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, | ||||||
|     DiagnosticSeverity, DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, |     DiagnosticSeverity, DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, | ||||||
|     DocumentFilter, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams, |     DocumentFilter, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams, | ||||||
|     HoverProviderCapability, InitializeParams, InitializeResult, InitializedParams, Location, MarkupContent, |     HoverProviderCapability, InitializeParams, InitializeResult, InitializedParams, Location, MarkedString, | ||||||
|     MarkupKind, MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken, SemanticTokensLegend, |     MarkupContent, MarkupKind, MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken, | ||||||
|     SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, SemanticTokensServerCapabilities, |     SemanticTokensLegend, SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, | ||||||
|     ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability, |     SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions, | ||||||
|     TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit, Url, WorkspaceEdit, |     TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit, | ||||||
|     WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, |     Url, WorkspaceEdit, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, | ||||||
| }; | }; | ||||||
| use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc}; | use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc}; | ||||||
| 
 | 
 | ||||||
| @ -199,7 +199,7 @@ impl LanguageServer for Backend { | |||||||
|             None |             None | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let (range, ty) = if let Some((idx, token)) = token { |         let (range, ty, documentation) = if let Some((idx, token)) = token { | ||||||
|             if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) { |             if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) { | ||||||
|                 let start = token.position; |                 let start = token.position; | ||||||
|                 let end = token.position.add(token.token.len() as u32); |                 let end = token.position.add(token.token.len() as u32); | ||||||
| @ -216,7 +216,9 @@ impl LanguageServer for Backend { | |||||||
|                 if let Some(hover) = analysis.hover.clone() { |                 if let Some(hover) = analysis.hover.clone() { | ||||||
|                     if let Some(kind) = hover.kind { |                     if let Some(kind) = hover.kind { | ||||||
|                         match kind { |                         match kind { | ||||||
|                             analysis::HoverKind::Type(type_kind) => (Some(range), format!("{}", type_kind)), |                             analysis::HoverKind::Type(type_kind) => { | ||||||
|  |                                 (Some(range), format!("{}", type_kind), hover.documentation) | ||||||
|  |                             } | ||||||
|                             analysis::HoverKind::Function(name, function_params, return_type) => ( |                             analysis::HoverKind::Function(name, function_params, return_type) => ( | ||||||
|                                 Some(range), |                                 Some(range), | ||||||
|                                 format!( |                                 format!( | ||||||
| @ -229,25 +231,30 @@ impl LanguageServer for Backend { | |||||||
|                                         .join(", "), |                                         .join(", "), | ||||||
|                                     return_type |                                     return_type | ||||||
|                                 ), |                                 ), | ||||||
|  |                                 hover.documentation, | ||||||
|                             ), |                             ), | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         (Some(range), String::from("No type")) |                         (Some(range), String::from("No type"), hover.documentation) | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     (Some(range), String::from("No hover")) |                     (Some(range), String::from("No hover"), None) | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 (None, String::from("no type")) |                 (None, String::from("no type"), None) | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             (None, String::from("no token")) |             (None, String::from("no token"), None) | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let contents = HoverContents::Markup(MarkupContent { |         let contents = if let Some(doc) = documentation { | ||||||
|             kind: MarkupKind::Markdown, |             HoverContents::Array(vec![MarkedString::String(doc), MarkedString::String(format!("`{ty}`"))]) | ||||||
|             value: format!("`{ty}`"), |         } else { | ||||||
|         }); |             HoverContents::Markup(MarkupContent { | ||||||
|  |                 kind: MarkupKind::Markdown, | ||||||
|  |                 value: format!("`{ty}`"), | ||||||
|  |             }) | ||||||
|  |         }; | ||||||
| 
 | 
 | ||||||
|         Ok(Some(Hover { contents, range })) |         Ok(Some(Hover { contents, range })) | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user