diff --git a/crates/els/README.md b/crates/els/README.md index 2811a4018..1491ee601 100644 --- a/crates/els/README.md +++ b/crates/els/README.md @@ -13,6 +13,7 @@ ELS is a language server for the [Erg](https://github.com/erg-lang/erg) programm - [x] Diagnostics - [x] Hover - [x] Go to definition +- [x] Go to type definition - [x] Go to implementation - [x] Find references - [x] Renaming @@ -28,9 +29,11 @@ ELS is a language server for the [Erg](https://github.com/erg-lang/erg) programm - [x] Signature help - [x] Workspace symbol - [x] Document symbol +- [x] Document highlight - [x] Call hierarchy - [x] Folding range - [x] Folding imports +- [x] Selection range ## Installation diff --git a/crates/els/channels.rs b/crates/els/channels.rs index 422c76da6..851423012 100644 --- a/crates/els/channels.rs +++ b/crates/els/channels.rs @@ -6,17 +6,19 @@ use erg_compiler::erg_parser::parse::Parsable; use lsp_types::request::{ CallHierarchyIncomingCalls, CallHierarchyOutgoingCalls, CallHierarchyPrepare, CodeActionRequest, CodeActionResolveRequest, CodeLensRequest, Completion, - DocumentSymbolRequest, ExecuteCommand, FoldingRangeRequest, GotoDefinition, GotoImplementation, - GotoImplementationParams, HoverRequest, InlayHintRequest, InlayHintResolveRequest, References, - ResolveCompletionItem, SemanticTokensFullRequest, SignatureHelpRequest, WillRenameFiles, - WorkspaceSymbol, + DocumentHighlightRequest, DocumentSymbolRequest, ExecuteCommand, FoldingRangeRequest, + GotoDefinition, GotoImplementation, GotoImplementationParams, GotoTypeDefinition, + GotoTypeDefinitionParams, HoverRequest, InlayHintRequest, InlayHintResolveRequest, References, + ResolveCompletionItem, SelectionRangeRequest, SemanticTokensFullRequest, SignatureHelpRequest, + WillRenameFiles, WorkspaceSymbol, }; use lsp_types::{ CallHierarchyIncomingCallsParams, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, CodeAction, CodeActionParams, CodeLensParams, CompletionItem, CompletionParams, - DocumentSymbolParams, ExecuteCommandParams, FoldingRangeParams, GotoDefinitionParams, - HoverParams, InlayHint, InlayHintParams, ReferenceParams, RenameFilesParams, - SemanticTokensParams, SignatureHelpParams, WorkspaceSymbolParams, + DocumentHighlightParams, DocumentSymbolParams, ExecuteCommandParams, FoldingRangeParams, + GotoDefinitionParams, HoverParams, InlayHint, InlayHintParams, ReferenceParams, + RenameFilesParams, SelectionRangeParams, SemanticTokensParams, SignatureHelpParams, + WorkspaceSymbolParams, }; use crate::server::Server; @@ -38,6 +40,7 @@ pub struct SendChannels { completion: mpsc::Sender>, resolve_completion: mpsc::Sender>, goto_definition: mpsc::Sender>, + goto_type_definition: mpsc::Sender>, goto_implementation: mpsc::Sender>, semantic_tokens_full: mpsc::Sender>, inlay_hint: mpsc::Sender>, @@ -56,6 +59,8 @@ pub struct SendChannels { call_hierarchy_incoming: mpsc::Sender>, call_hierarchy_outgoing: mpsc::Sender>, folding_range: mpsc::Sender>, + selection_range: mpsc::Sender>, + document_highlight: mpsc::Sender>, pub(crate) health_check: mpsc::Sender>, } @@ -64,6 +69,7 @@ impl SendChannels { let (tx_completion, rx_completion) = mpsc::channel(); let (tx_resolve_completion, rx_resolve_completion) = mpsc::channel(); let (tx_goto_definition, rx_goto_definition) = mpsc::channel(); + let (tx_goto_type_definition, rx_goto_type_definition) = mpsc::channel(); let (tx_goto_implementation, rx_goto_implementation) = mpsc::channel(); let (tx_semantic_tokens_full, rx_semantic_tokens_full) = mpsc::channel(); let (tx_inlay_hint, rx_inlay_hint) = mpsc::channel(); @@ -82,12 +88,15 @@ impl SendChannels { let (tx_call_hierarchy_incoming, rx_call_hierarchy_incoming) = mpsc::channel(); let (tx_call_hierarchy_outgoing, rx_call_hierarchy_outgoing) = mpsc::channel(); let (tx_folding_range, rx_folding_range) = mpsc::channel(); + let (tx_selection_range, rx_selection_range) = mpsc::channel(); + let (tx_document_highlight, rx_document_highlight) = mpsc::channel(); let (tx_health_check, rx_health_check) = mpsc::channel(); ( Self { completion: tx_completion, resolve_completion: tx_resolve_completion, goto_definition: tx_goto_definition, + goto_type_definition: tx_goto_type_definition, goto_implementation: tx_goto_implementation, semantic_tokens_full: tx_semantic_tokens_full, inlay_hint: tx_inlay_hint, @@ -106,12 +115,15 @@ impl SendChannels { call_hierarchy_incoming: tx_call_hierarchy_incoming, call_hierarchy_outgoing: tx_call_hierarchy_outgoing, folding_range: tx_folding_range, + selection_range: tx_selection_range, + document_highlight: tx_document_highlight, health_check: tx_health_check, }, ReceiveChannels { completion: rx_completion, resolve_completion: rx_resolve_completion, goto_definition: rx_goto_definition, + goto_type_definition: rx_goto_type_definition, goto_implementation: rx_goto_implementation, semantic_tokens_full: rx_semantic_tokens_full, inlay_hint: rx_inlay_hint, @@ -130,6 +142,8 @@ impl SendChannels { call_hierarchy_incoming: rx_call_hierarchy_incoming, call_hierarchy_outgoing: rx_call_hierarchy_outgoing, folding_range: rx_folding_range, + selection_range: rx_selection_range, + document_highlight: rx_document_highlight, health_check: rx_health_check, }, ) @@ -139,6 +153,8 @@ impl SendChannels { let _ = self.completion.send(WorkerMessage::Kill); let _ = self.resolve_completion.send(WorkerMessage::Kill); let _ = self.goto_definition.send(WorkerMessage::Kill); + let _ = self.goto_type_definition.send(WorkerMessage::Kill); + let _ = self.goto_implementation.send(WorkerMessage::Kill); let _ = self.semantic_tokens_full.send(WorkerMessage::Kill); let _ = self.inlay_hint.send(WorkerMessage::Kill); let _ = self.inlay_hint_resolve.send(WorkerMessage::Kill); @@ -156,6 +172,8 @@ impl SendChannels { let _ = self.call_hierarchy_incoming.send(WorkerMessage::Kill); let _ = self.call_hierarchy_outgoing.send(WorkerMessage::Kill); let _ = self.folding_range.send(WorkerMessage::Kill); + let _ = self.selection_range.send(WorkerMessage::Kill); + let _ = self.document_highlight.send(WorkerMessage::Kill); let _ = self.health_check.send(WorkerMessage::Kill); } } @@ -165,6 +183,7 @@ pub struct ReceiveChannels { pub(crate) completion: mpsc::Receiver>, pub(crate) resolve_completion: mpsc::Receiver>, pub(crate) goto_definition: mpsc::Receiver>, + pub(crate) goto_type_definition: mpsc::Receiver>, pub(crate) goto_implementation: mpsc::Receiver>, pub(crate) semantic_tokens_full: mpsc::Receiver>, pub(crate) inlay_hint: mpsc::Receiver>, @@ -185,6 +204,8 @@ pub struct ReceiveChannels { pub(crate) call_hierarchy_outgoing: mpsc::Receiver>, pub(crate) folding_range: mpsc::Receiver>, + pub(crate) selection_range: mpsc::Receiver>, + pub(crate) document_highlight: mpsc::Receiver>, pub(crate) health_check: mpsc::Receiver>, } @@ -222,6 +243,11 @@ macro_rules! impl_sendable { impl_sendable!(Completion, CompletionParams, completion); impl_sendable!(ResolveCompletionItem, CompletionItem, resolve_completion); impl_sendable!(GotoDefinition, GotoDefinitionParams, goto_definition); +impl_sendable!( + GotoTypeDefinition, + GotoTypeDefinitionParams, + goto_type_definition +); impl_sendable!( GotoImplementation, GotoImplementationParams, @@ -260,3 +286,9 @@ impl_sendable!( call_hierarchy_outgoing ); impl_sendable!(FoldingRangeRequest, FoldingRangeParams, folding_range); +impl_sendable!(SelectionRangeRequest, SelectionRangeParams, selection_range); +impl_sendable!( + DocumentHighlightRequest, + DocumentHighlightParams, + document_highlight +); diff --git a/crates/els/doc_highlight.rs b/crates/els/doc_highlight.rs new file mode 100644 index 000000000..bb11456ff --- /dev/null +++ b/crates/els/doc_highlight.rs @@ -0,0 +1,47 @@ +use erg_compiler::artifact::BuildRunnable; +use erg_compiler::erg_parser::parse::Parsable; + +use lsp_types::{DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams, Position}; + +use crate::_log; +use crate::server::{ELSResult, RedirectableStdout, Server}; +use crate::util::{loc_to_range, NormalizedUrl}; + +impl Server { + pub(crate) fn handle_document_highlight( + &mut self, + params: DocumentHighlightParams, + ) -> ELSResult>> { + _log!(self, "document highlight requested: {params:?}"); + let uri = NormalizedUrl::new(params.text_document_position_params.text_document.uri); + let mut res = vec![]; + res.extend( + self.get_document_highlight(&uri, params.text_document_position_params.position), + ); + Ok(Some(res)) + } + + fn get_document_highlight(&self, uri: &NormalizedUrl, pos: Position) -> Vec { + let mut res = vec![]; + let Some(visitor) = self.get_visitor(uri) else { + return res; + }; + if let Some(tok) = self.file_cache.get_symbol(uri, pos) { + if let Some(vi) = visitor.get_info(&tok) { + if let Some(range) = loc_to_range(vi.def_loc.loc) { + res.push(DocumentHighlight { + range, + kind: Some(DocumentHighlightKind::TEXT), + }); + } + for reference in self.get_refs_from_abs_loc(&vi.def_loc) { + res.push(DocumentHighlight { + range: reference.range, + kind: Some(DocumentHighlightKind::TEXT), + }); + } + } + } + res + } +} diff --git a/crates/els/hir_visitor.rs b/crates/els/hir_visitor.rs index c19a136b9..dd16c0c03 100644 --- a/crates/els/hir_visitor.rs +++ b/crates/els/hir_visitor.rs @@ -1,4 +1,5 @@ use erg_common::consts::ERG_MODE; +use erg_common::error::Location; use erg_common::shared::MappedRwLockReadGuard; use erg_common::traits::Locational; use erg_common::Str; @@ -820,4 +821,173 @@ impl<'a> HIRVisitor<'a> { self.get_expr_info(&tasc.expr, token) .or_else(|| self.get_expr_info(&tasc.spec.expr, token)) } + + pub fn get_parent(&self, expr_loc: Location) -> Option<&Expr> { + for chunk in self.hir.module.iter() { + if let Some(parent) = self.get_parent_expr(chunk, expr_loc) { + return Some(parent); + } + } + None + } + + #[allow(clippy::only_used_in_recursion)] + fn get_parent_expr<'p>(&self, maybe_parent: &'p Expr, expr_loc: Location) -> Option<&'p Expr> { + let loc = maybe_parent.loc(); + #[allow(clippy::double_comparisons)] + if loc < expr_loc || loc > expr_loc { + return None; + } + match maybe_parent { + Expr::BinOp(bin) => (bin.lhs.loc() == expr_loc || bin.rhs.loc() == expr_loc) + .then_some(maybe_parent) + .or_else(|| { + self.get_parent_expr(&bin.lhs, expr_loc) + .or_else(|| self.get_parent_expr(&bin.rhs, expr_loc)) + }), + Expr::UnaryOp(unary) => (unary.expr.loc() == expr_loc) + .then_some(maybe_parent) + .or_else(|| self.get_parent_expr(&unary.expr, expr_loc)), + Expr::Accessor(Accessor::Attr(attr)) => (attr.obj.loc() == expr_loc + || attr.ident.loc() == expr_loc) + .then_some(maybe_parent) + .or_else(|| self.get_parent_expr(&attr.obj, expr_loc)), + Expr::Call(call) => { + if call.obj.loc() == expr_loc || call.args.iter().any(|arg| arg.loc() == expr_loc) { + return Some(maybe_parent); + } + if let Some(expr) = self.get_parent_expr(&call.obj, expr_loc) { + return Some(expr); + } + for arg in call.args.pos_args.iter() { + if let Some(parent) = self.get_parent_expr(&arg.expr, expr_loc) { + return Some(parent); + } + } + if let Some(var) = &call.args.var_args { + if let Some(parent) = self.get_parent_expr(&var.expr, expr_loc) { + return Some(parent); + } + } + for arg in call.args.kw_args.iter() { + if let Some(parent) = self.get_parent_expr(&arg.expr, expr_loc) { + return Some(parent); + } + } + if let Some(kw_var) = &call.args.kw_var { + if let Some(parent) = self.get_parent_expr(&kw_var.expr, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Def(def) => { + if def.body.block.iter().any(|chunk| chunk.loc() == expr_loc) { + return Some(maybe_parent); + } + for chunk in def.body.block.iter() { + if let Some(parent) = self.get_parent_expr(chunk, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Lambda(lambda) => { + if lambda.body.iter().any(|chunk| chunk.loc() == expr_loc) { + return Some(maybe_parent); + } + for chunk in lambda.body.iter() { + if let Some(parent) = self.get_parent_expr(chunk, expr_loc) { + return Some(parent); + } + } + None + } + Expr::TypeAsc(type_asc) => { + if type_asc.expr.loc() == expr_loc { + return Some(maybe_parent); + } + if let Some(parent) = self.get_parent_expr(&type_asc.expr, expr_loc) { + return Some(parent); + } + None + } + Expr::ClassDef(class_def) => { + if class_def.all_methods().any(|chunk| chunk.loc() == expr_loc) { + return Some(maybe_parent); + } + for chunk in class_def.all_methods() { + if let Some(parent) = self.get_parent_expr(chunk, expr_loc) { + return Some(parent); + } + } + None + } + Expr::List(List::Normal(list)) => { + if list.elems.iter().any(|elem| elem.loc() == expr_loc) { + return Some(maybe_parent); + } + for elem in list.elems.pos_args.iter() { + if let Some(parent) = self.get_parent_expr(&elem.expr, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Set(Set::Normal(set)) => { + if set.elems.iter().any(|elem| elem.loc() == expr_loc) { + return Some(maybe_parent); + } + for elem in set.elems.pos_args.iter() { + if let Some(parent) = self.get_parent_expr(&elem.expr, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Tuple(Tuple::Normal(tuple)) => { + if tuple.elems.iter().any(|elem| elem.loc() == expr_loc) { + return Some(maybe_parent); + } + for elem in tuple.elems.pos_args.iter() { + if let Some(parent) = self.get_parent_expr(&elem.expr, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Dict(Dict::Normal(dict)) => { + if dict + .kvs + .iter() + .any(|kv| kv.key.loc() == expr_loc || kv.value.loc() == expr_loc) + { + return Some(maybe_parent); + } + for kv in dict.kvs.iter() { + if let Some(parent) = self.get_parent_expr(&kv.key, expr_loc) { + return Some(parent); + } + if let Some(parent) = self.get_parent_expr(&kv.value, expr_loc) { + return Some(parent); + } + } + None + } + Expr::Record(record) => { + if record.attrs.iter().any(|field| field.loc() == expr_loc) { + return Some(maybe_parent); + } + for field in record.attrs.iter() { + for chunk in field.body.block.iter() { + if let Some(parent) = self.get_parent_expr(chunk, expr_loc) { + return Some(parent); + } + } + } + None + } + _ => None, + } + } } diff --git a/crates/els/lib.rs b/crates/els/lib.rs index 26498e80d..9b45deaef 100644 --- a/crates/els/lib.rs +++ b/crates/els/lib.rs @@ -7,6 +7,7 @@ mod completion; mod definition; mod diagnostics; mod diff; +mod doc_highlight; mod file_cache; mod folding_range; mod hir_visitor; @@ -17,10 +18,12 @@ mod message; mod references; mod rename; mod scheduler; +mod selection_range; mod semantic; mod server; mod sig_help; mod symbol; +mod type_definition; mod util; pub use server::*; pub use util::*; diff --git a/crates/els/main.rs b/crates/els/main.rs index e11b6e5d7..262013c04 100644 --- a/crates/els/main.rs +++ b/crates/els/main.rs @@ -7,6 +7,7 @@ mod completion; mod definition; mod diagnostics; mod diff; +mod doc_highlight; mod file_cache; mod folding_range; mod hir_visitor; @@ -17,10 +18,12 @@ mod message; mod references; mod rename; mod scheduler; +mod selection_range; mod semantic; mod server; mod sig_help; mod symbol; +mod type_definition; mod util; use erg_common::config::ErgConfig; diff --git a/crates/els/selection_range.rs b/crates/els/selection_range.rs new file mode 100644 index 000000000..71a423475 --- /dev/null +++ b/crates/els/selection_range.rs @@ -0,0 +1,64 @@ +use erg_common::traits::Locational; + +use erg_compiler::artifact::BuildRunnable; +use erg_compiler::erg_parser::parse::Parsable; + +use lsp_types::{Position, SelectionRange, SelectionRangeParams}; + +use crate::_log; +use crate::server::{ELSResult, RedirectableStdout, Server}; +use crate::util::{loc_to_range, NormalizedUrl}; + +impl Server { + pub(crate) fn handle_selection_range( + &mut self, + params: SelectionRangeParams, + ) -> ELSResult>> { + _log!(self, "selection range requested: {params:?}"); + let uri = NormalizedUrl::new(params.text_document.uri); + let mut res = vec![]; + res.extend(self.get_selection_ranges(&uri, params.positions)); + Ok(Some(res)) + } + + fn get_selection_ranges( + &self, + uri: &NormalizedUrl, + poss: Vec, + ) -> Vec { + let mut res = vec![]; + let Some(visitor) = self.get_visitor(uri) else { + return res; + }; + for pos in poss { + let Some(token) = self.file_cache.get_token(uri, pos) else { + continue; + }; + let Some(range) = loc_to_range(token.loc()) else { + continue; + }; + let mut selection_range = SelectionRange { + range, + parent: None, + }; + let mut parent_range = &mut selection_range.parent; + let mut opt_expr = visitor.get_min_expr(pos); + while let Some(expr) = opt_expr { + let Some(parent) = visitor.get_parent(expr.loc()) else { + break; + }; + let Some(range) = loc_to_range(parent.loc()) else { + break; + }; + *parent_range = Some(Box::new(SelectionRange { + range, + parent: None, + })); + parent_range = &mut parent_range.as_mut().unwrap().parent; + opt_expr = Some(parent); + } + res.push(selection_range); + } + res + } +} diff --git a/crates/els/server.rs b/crates/els/server.rs index 6c7e5cd09..e19797b96 100644 --- a/crates/els/server.rs +++ b/crates/els/server.rs @@ -37,9 +37,10 @@ use molc::{FakeClient, LangServer}; use lsp_types::request::{ CallHierarchyIncomingCalls, CallHierarchyOutgoingCalls, CallHierarchyPrepare, CodeActionRequest, CodeActionResolveRequest, CodeLensRequest, Completion, - DocumentSymbolRequest, ExecuteCommand, FoldingRangeRequest, GotoDefinition, GotoImplementation, - HoverRequest, InlayHintRequest, InlayHintResolveRequest, References, Rename, Request, - ResolveCompletionItem, SemanticTokensFullRequest, SignatureHelpRequest, WillRenameFiles, + DocumentHighlightRequest, DocumentSymbolRequest, ExecuteCommand, FoldingRangeRequest, + GotoDefinition, GotoImplementation, GotoTypeDefinition, HoverRequest, InlayHintRequest, + InlayHintResolveRequest, References, Rename, Request, ResolveCompletionItem, + SelectionRangeRequest, SemanticTokensFullRequest, SignatureHelpRequest, WillRenameFiles, WorkspaceSymbol, }; use lsp_types::{ @@ -49,10 +50,11 @@ use lsp_types::{ ExecuteCommandOptions, FoldingRangeProviderCapability, HoverProviderCapability, ImplementationProviderCapability, InitializeParams, InitializeResult, InlayHintOptions, InlayHintServerCapabilities, NumberOrString, OneOf, Position, ProgressParams, - ProgressParamsValue, SemanticTokenType, SemanticTokensFullOptions, SemanticTokensLegend, - SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, - SignatureHelpOptions, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams, - WorkDoneProgressEnd, WorkDoneProgressOptions, + ProgressParamsValue, SelectionRangeProviderCapability, SemanticTokenType, + SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, + SemanticTokensServerCapabilities, ServerCapabilities, SignatureHelpOptions, + TypeDefinitionProviderCapability, WorkDoneProgress, WorkDoneProgressBegin, + WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressOptions, }; use serde::{Deserialize, Serialize}; @@ -454,6 +456,8 @@ impl Server { capabilities.rename_provider = Some(OneOf::Left(true)); capabilities.references_provider = Some(OneOf::Left(true)); capabilities.definition_provider = Some(OneOf::Left(true)); + capabilities.type_definition_provider = + Some(TypeDefinitionProviderCapability::Simple(true)); capabilities.implementation_provider = Some(ImplementationProviderCapability::Simple(true)); capabilities.hover_provider = self .disabled_features @@ -533,6 +537,9 @@ impl Server { capabilities.document_symbol_provider = Some(OneOf::Left(true)); capabilities.call_hierarchy_provider = Some(CallHierarchyServerCapability::Simple(true)); capabilities.folding_range_provider = Some(FoldingRangeProviderCapability::Simple(true)); + capabilities.selection_range_provider = + Some(SelectionRangeProviderCapability::Simple(true)); + capabilities.document_highlight_provider = Some(OneOf::Left(true)); capabilities } @@ -563,6 +570,10 @@ impl Server { receivers.goto_definition, Self::handle_goto_definition, ); + self.start_service::( + receivers.goto_type_definition, + Self::handle_goto_type_definition, + ); self.start_service::( receivers.goto_implementation, Self::handle_goto_implementation, @@ -620,6 +631,14 @@ impl Server { receivers.folding_range, Self::handle_folding_range, ); + self.start_service::( + receivers.selection_range, + Self::handle_selection_range, + ); + self.start_service::( + receivers.document_highlight, + Self::handle_document_highlight, + ); self.start_client_health_checker(receivers.health_check); } @@ -847,6 +866,7 @@ impl Server { Completion::METHOD => self.parse_send::(id, msg), ResolveCompletionItem::METHOD => self.parse_send::(id, msg), GotoDefinition::METHOD => self.parse_send::(id, msg), + GotoTypeDefinition::METHOD => self.parse_send::(id, msg), GotoImplementation::METHOD => self.parse_send::(id, msg), HoverRequest::METHOD => self.parse_send::(id, msg), References::METHOD => self.parse_send::(id, msg), @@ -873,6 +893,10 @@ impl Server { } CallHierarchyPrepare::METHOD => self.parse_send::(id, msg), FoldingRangeRequest::METHOD => self.parse_send::(id, msg), + SelectionRangeRequest::METHOD => self.parse_send::(id, msg), + DocumentHighlightRequest::METHOD => { + self.parse_send::(id, msg) + } other => self.send_error(Some(id), -32600, format!("{other} is not supported")), } } diff --git a/crates/els/type_definition.rs b/crates/els/type_definition.rs new file mode 100644 index 000000000..9e428e682 --- /dev/null +++ b/crates/els/type_definition.rs @@ -0,0 +1,40 @@ +use std::path::Path; + +use erg_common::shared::MappedRwLockReadGuard; +use erg_compiler::artifact::BuildRunnable; +use erg_compiler::erg_parser::parse::Parsable; + +use lsp_types::request::{GotoTypeDefinitionParams, GotoTypeDefinitionResponse}; +use lsp_types::{GotoDefinitionResponse, Position, Url}; + +use crate::server::{ELSResult, RedirectableStdout, Server}; +use crate::util::{self, NormalizedUrl}; + +impl Server { + pub(crate) fn handle_goto_type_definition( + &mut self, + params: GotoTypeDefinitionParams, + ) -> ELSResult> { + self.send_log(format!("type definition requested: {params:?}"))?; + let uri = NormalizedUrl::new(params.text_document_position_params.text_document.uri); + let pos = params.text_document_position_params.position; + Ok(self.get_type_def(&uri, pos)) + } + + fn get_type_def(&self, uri: &NormalizedUrl, pos: Position) -> Option { + let visitor = self.get_visitor(uri)?; + let tok = self.file_cache.get_symbol(uri, pos)?; + let typ = &visitor.get_info(&tok)?.t; + let path = typ.namespace(); + let module = self + .shared + .get_module(Path::new(&path[..])) + .map(|ent| MappedRwLockReadGuard::map(ent, |ent| &ent.module)) + .or_else(|| self.get_mod_ctx(uri))?; + let (_, typ_info) = module.context.get_type_info(typ)?; + let path = typ_info.def_loc.module.as_ref()?; + let def_uri = Url::from_file_path(path).ok()?; + let loc = lsp_types::Location::new(def_uri, util::loc_to_range(typ_info.def_loc.loc)?); + Some(GotoDefinitionResponse::Scalar(loc)) + } +} diff --git a/crates/erg_compiler/hir.rs b/crates/erg_compiler/hir.rs index a245625d7..c646954b5 100644 --- a/crates/erg_compiler/hir.rs +++ b/crates/erg_compiler/hir.rs @@ -416,6 +416,7 @@ impl Args { .map(|pos| &pos.expr) .chain(self.var_args.iter().map(|var| &var.expr)) .chain(self.kw_args.iter().map(|kw| &kw.expr)) + .chain(self.kw_var.iter().map(|kw| &kw.expr)) } }