mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
feat(els): module hover link
This commit is contained in:
parent
17b3fbc5c0
commit
af3b6ec3d7
5 changed files with 110 additions and 13 deletions
|
@ -30,6 +30,7 @@ ELS is a language server for the [Erg](https://github.com/erg-lang/erg) programm
|
|||
- [x] Workspace symbol
|
||||
- [x] Document symbol
|
||||
- [x] Document highlight
|
||||
- [x] Document link
|
||||
- [x] Call hierarchy
|
||||
- [x] Folding range
|
||||
- [x] Folding imports
|
||||
|
|
|
@ -4,10 +4,14 @@ use erg_common::trim_eliminate_top_indent;
|
|||
use erg_compiler::artifact::BuildRunnable;
|
||||
use erg_compiler::erg_parser::parse::Parsable;
|
||||
use erg_compiler::erg_parser::token::{Token, TokenCategory, TokenKind};
|
||||
use erg_compiler::hir::Expr;
|
||||
use erg_compiler::ty::HasType;
|
||||
use erg_compiler::varinfo::{AbsLocation, VarInfo};
|
||||
|
||||
use lsp_types::{Hover, HoverContents, HoverParams, MarkedString, Url};
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::_log;
|
||||
use crate::server::{ELSResult, RedirectableStdout, Server};
|
||||
use crate::util::{self, NormalizedUrl};
|
||||
|
||||
|
@ -175,6 +179,48 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(visitor) = self.get_visitor(&uri) {
|
||||
let url = match visitor.get_min_expr(pos) {
|
||||
Some(Expr::Def(def)) => def
|
||||
.sig
|
||||
.ref_t()
|
||||
.module_path()
|
||||
.and_then(|path| Url::from_file_path(path).ok()),
|
||||
Some(Expr::Call(call)) => {
|
||||
call.call_signature_t().return_t().and_then(|ret_t| {
|
||||
ret_t
|
||||
.module_path()
|
||||
.and_then(|path| Url::from_file_path(path).ok())
|
||||
})
|
||||
}
|
||||
Some(expr) => expr
|
||||
.ref_t()
|
||||
.module_path()
|
||||
.or_else(|| {
|
||||
expr.ref_t()
|
||||
.inner_ts()
|
||||
.into_iter()
|
||||
.find_map(|t| t.module_path())
|
||||
})
|
||||
.and_then(|path| Url::from_file_path(path).ok()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(url) = url {
|
||||
let path = url.to_file_path().unwrap().with_extension("");
|
||||
let name = if path.ends_with("__init__") || path.ends_with("__init__.d") {
|
||||
path.parent()
|
||||
.unwrap()
|
||||
.file_stem()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
} else {
|
||||
path.file_stem().unwrap().to_string_lossy()
|
||||
};
|
||||
contents.push(MarkedString::from_markdown(format!(
|
||||
"Go to [{name}]({url})",
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.send_log("lex error")?;
|
||||
}
|
||||
|
|
|
@ -87,11 +87,16 @@ pub enum DefaultFeatures {
|
|||
Diagnostics,
|
||||
FindReferences,
|
||||
GotoDefinition,
|
||||
GotoTypeDefinition,
|
||||
Hover,
|
||||
InlayHint,
|
||||
Rename,
|
||||
SemanticTokens,
|
||||
SignatureHelp,
|
||||
DocumentHighlight,
|
||||
DocumentLink,
|
||||
FoldingRange,
|
||||
SelectionRange,
|
||||
/* ELS specific features */
|
||||
SmartCompletion,
|
||||
DeepCompletion,
|
||||
|
@ -116,9 +121,20 @@ impl From<&str> for DefaultFeatures {
|
|||
"gotodefinition" | "gotoDefinition" | "goto-definition" => {
|
||||
DefaultFeatures::GotoDefinition
|
||||
}
|
||||
"gototypedefinition" | "gotoTypeDefinition" | "goto-type-definition" => {
|
||||
DefaultFeatures::GotoTypeDefinition
|
||||
}
|
||||
"signaturehelp" | "signatureHelp" | "signature-help" | "code-signature" => {
|
||||
DefaultFeatures::SignatureHelp
|
||||
}
|
||||
"documenthighlight" | "documentHighlight" | "document-highlight" => {
|
||||
DefaultFeatures::DocumentHighlight
|
||||
}
|
||||
"documentlink" | "documentLink" | "document-link" => DefaultFeatures::DocumentLink,
|
||||
"foldingrange" | "foldingRange" | "folding-range" => DefaultFeatures::FoldingRange,
|
||||
"selectionrange" | "selectionRange" | "selection-range" => {
|
||||
DefaultFeatures::SelectionRange
|
||||
}
|
||||
"smartcompletion" | "smartCompletion" | "smart-completion" => {
|
||||
DefaultFeatures::SmartCompletion
|
||||
}
|
||||
|
@ -452,7 +468,14 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
let mut comp_options = CompletionOptions::default();
|
||||
comp_options.trigger_characters = Some(TRIGGER_CHARS.map(String::from).to_vec());
|
||||
comp_options.resolve_provider = Some(true);
|
||||
capabilities.completion_provider = Some(comp_options);
|
||||
capabilities.completion_provider = if self
|
||||
.disabled_features
|
||||
.contains(&DefaultFeatures::Completion)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(comp_options)
|
||||
};
|
||||
capabilities.rename_provider = Some(OneOf::Left(true));
|
||||
capabilities.references_provider = Some(OneOf::Left(true));
|
||||
capabilities.definition_provider = Some(OneOf::Left(true));
|
||||
|
@ -530,20 +553,40 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|||
work_done_progress: None,
|
||||
},
|
||||
});
|
||||
capabilities.code_lens_provider = Some(CodeLensOptions {
|
||||
resolve_provider: Some(false),
|
||||
});
|
||||
capabilities.code_lens_provider =
|
||||
if self.disabled_features.contains(&DefaultFeatures::CodeLens) {
|
||||
None
|
||||
} else {
|
||||
Some(CodeLensOptions {
|
||||
resolve_provider: Some(false),
|
||||
})
|
||||
};
|
||||
capabilities.workspace_symbol_provider = Some(OneOf::Left(true));
|
||||
capabilities.document_symbol_provider = Some(OneOf::Left(true));
|
||||
capabilities.document_link_provider = Some(DocumentLinkOptions {
|
||||
resolve_provider: Some(false),
|
||||
work_done_progress_options: Default::default(),
|
||||
});
|
||||
capabilities.document_link_provider = if self
|
||||
.disabled_features
|
||||
.contains(&DefaultFeatures::DocumentLink)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(DocumentLinkOptions {
|
||||
resolve_provider: Some(false),
|
||||
work_done_progress_options: Default::default(),
|
||||
})
|
||||
};
|
||||
capabilities.call_hierarchy_provider = Some(CallHierarchyServerCapability::Simple(true));
|
||||
capabilities.folding_range_provider = Some(FoldingRangeProviderCapability::Simple(true));
|
||||
capabilities.folding_range_provider = Some(FoldingRangeProviderCapability::Simple(
|
||||
self.disabled_features
|
||||
.contains(&DefaultFeatures::FoldingRange)
|
||||
.not(),
|
||||
));
|
||||
capabilities.selection_range_provider =
|
||||
Some(SelectionRangeProviderCapability::Simple(true));
|
||||
capabilities.document_highlight_provider = Some(OneOf::Left(true));
|
||||
capabilities.document_highlight_provider = Some(OneOf::Left(
|
||||
self.disabled_features
|
||||
.contains(&DefaultFeatures::DocumentHighlight)
|
||||
.not(),
|
||||
));
|
||||
capabilities
|
||||
}
|
||||
|
||||
|
|
|
@ -1517,10 +1517,16 @@ impl Call {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn call_signature_t(&self) -> &Type {
|
||||
if let Some(attr) = self.attr_name.as_ref() {
|
||||
attr.ref_t()
|
||||
} else {
|
||||
self.obj.ref_t()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self) -> bool {
|
||||
self.signature_t()
|
||||
.map(|t| t.self_t().is_some())
|
||||
.unwrap_or(false)
|
||||
self.call_signature_t().self_t().is_some()
|
||||
}
|
||||
|
||||
pub fn additional_operation(&self) -> Option<OperationKind> {
|
||||
|
|
|
@ -1891,6 +1891,7 @@ impl HasType for Type {
|
|||
)
|
||||
.chain(sub.var_params.as_deref().map(|pt| pt.typ().clone()))
|
||||
.chain(sub.non_default_params.iter().map(|pt| pt.typ().clone()))
|
||||
.chain(sub.kw_var_params.as_deref().map(|pt| pt.typ().clone()))
|
||||
.chain([*sub.return_t.clone()])
|
||||
.collect(),
|
||||
Self::Callable { param_ts, .. } => param_ts.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue