mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
183 lines
6.7 KiB
Rust
183 lines
6.7 KiB
Rust
use erg_common::traits::Locational;
|
|
|
|
use erg_compiler::artifact::BuildRunnable;
|
|
use erg_compiler::erg_parser::ast::DefKind;
|
|
use erg_compiler::erg_parser::parse::Parsable;
|
|
use erg_compiler::hir::Expr;
|
|
use erg_compiler::ty::{HasType, Type};
|
|
use erg_compiler::varinfo::VarInfo;
|
|
use lsp_types::{
|
|
DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse, SymbolInformation, SymbolKind,
|
|
WorkspaceSymbolParams,
|
|
};
|
|
|
|
use crate::_log;
|
|
use crate::server::{ELSResult, RedirectableStdout, Server};
|
|
use crate::util::{abs_loc_to_lsp_loc, loc_to_range, NormalizedUrl};
|
|
|
|
pub(crate) fn symbol_kind(vi: &VarInfo) -> SymbolKind {
|
|
match &vi.t {
|
|
Type::Subr(subr) if subr.self_t().is_some() => SymbolKind::METHOD,
|
|
Type::Quantified(quant) if quant.self_t().is_some() => SymbolKind::METHOD,
|
|
Type::Subr(_) | Type::Quantified(_) => SymbolKind::FUNCTION,
|
|
Type::ClassType => SymbolKind::CLASS,
|
|
Type::TraitType => SymbolKind::INTERFACE,
|
|
t if matches!(&t.qual_name()[..], "Module" | "PyModule" | "GenericModule") => {
|
|
SymbolKind::MODULE
|
|
}
|
|
_ if vi.muty.is_const() => SymbolKind::CONSTANT,
|
|
_ => SymbolKind::VARIABLE,
|
|
}
|
|
}
|
|
|
|
impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
|
pub(crate) fn handle_workspace_symbol(
|
|
&mut self,
|
|
params: WorkspaceSymbolParams,
|
|
) -> ELSResult<Option<Vec<SymbolInformation>>> {
|
|
_log!(self, "workspace symbol requested: {params:?}");
|
|
let mut res = vec![];
|
|
for context in self.get_workspace_ctxs() {
|
|
for (name, vi) in context.local_dir() {
|
|
if name.inspect().starts_with(['%']) {
|
|
continue;
|
|
}
|
|
if vi
|
|
.alias_of
|
|
.as_ref()
|
|
.is_some_and(|alias| &alias.name == name.inspect())
|
|
{
|
|
continue;
|
|
}
|
|
let Some(location) = abs_loc_to_lsp_loc(&vi.def_loc) else {
|
|
continue;
|
|
};
|
|
#[allow(deprecated)]
|
|
let info = SymbolInformation {
|
|
name: name.to_string(),
|
|
location,
|
|
kind: symbol_kind(vi),
|
|
container_name: None,
|
|
tags: None,
|
|
deprecated: None,
|
|
};
|
|
res.push(info);
|
|
}
|
|
}
|
|
Ok(Some(res))
|
|
}
|
|
|
|
pub(crate) fn handle_document_symbol(
|
|
&mut self,
|
|
params: DocumentSymbolParams,
|
|
) -> ELSResult<Option<DocumentSymbolResponse>> {
|
|
_log!(self, "document symbol requested: {params:?}");
|
|
let uri = NormalizedUrl::new(params.text_document.uri);
|
|
if let Some(hir) = self.get_hir(&uri) {
|
|
let mut res = vec![];
|
|
for chunk in hir.module.iter() {
|
|
let symbol = self.symbol(chunk);
|
|
res.extend(symbol);
|
|
}
|
|
return Ok(Some(DocumentSymbolResponse::Nested(res)));
|
|
}
|
|
Ok(None)
|
|
}
|
|
|
|
fn symbol(&self, chunk: &Expr) -> Option<DocumentSymbol> {
|
|
match chunk {
|
|
Expr::Def(def) => {
|
|
if def.sig.is_glob() || def.sig.inspect().starts_with(['%']) {
|
|
return None;
|
|
}
|
|
let range = loc_to_range(def.loc())?;
|
|
let selection_range = loc_to_range(def.sig.loc())?;
|
|
#[allow(deprecated)]
|
|
Some(DocumentSymbol {
|
|
name: def.sig.name().to_string(),
|
|
detail: Some(def.sig.ident().ref_t().to_string()),
|
|
kind: symbol_kind(&def.sig.ident().vi),
|
|
tags: None,
|
|
deprecated: None,
|
|
range,
|
|
selection_range,
|
|
children: Some(self.child_symbols(chunk)),
|
|
})
|
|
}
|
|
Expr::ClassDef(def) => {
|
|
let range = loc_to_range(def.loc())?;
|
|
let selection_range = loc_to_range(def.sig.loc())?;
|
|
#[allow(deprecated)]
|
|
Some(DocumentSymbol {
|
|
name: def.sig.name().to_string(),
|
|
detail: Some(def.sig.ident().ref_t().to_string()),
|
|
kind: symbol_kind(&def.sig.ident().vi),
|
|
tags: None,
|
|
deprecated: None,
|
|
range,
|
|
selection_range,
|
|
children: Some(self.child_symbols(chunk)),
|
|
})
|
|
}
|
|
Expr::PatchDef(def) => {
|
|
let range = loc_to_range(def.loc())?;
|
|
let selection_range = loc_to_range(def.sig.loc())?;
|
|
#[allow(deprecated)]
|
|
Some(DocumentSymbol {
|
|
name: def.sig.name().to_string(),
|
|
detail: Some(def.sig.ident().ref_t().to_string()),
|
|
kind: symbol_kind(&def.sig.ident().vi),
|
|
tags: None,
|
|
deprecated: None,
|
|
range,
|
|
selection_range,
|
|
children: Some(self.child_symbols(chunk)),
|
|
})
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn child_symbols(&self, chunk: &Expr) -> Vec<DocumentSymbol> {
|
|
match chunk {
|
|
Expr::Def(def) => match def.def_kind() {
|
|
DefKind::Class | DefKind::Trait => {
|
|
if let Some(base) = def.get_base() {
|
|
let mut res = vec![];
|
|
for member in base.attrs.iter() {
|
|
let symbol = self.symbol(&Expr::Def(member.clone()));
|
|
res.extend(symbol);
|
|
}
|
|
res
|
|
} else {
|
|
vec![]
|
|
}
|
|
}
|
|
_ => vec![],
|
|
},
|
|
Expr::ClassDef(def) => {
|
|
let mut res = vec![];
|
|
if let Some(Expr::Record(rec)) = def.require_or_sup.as_deref() {
|
|
for member in rec.attrs.iter() {
|
|
let symbol = self.symbol(&Expr::Def(member.clone()));
|
|
res.extend(symbol);
|
|
}
|
|
}
|
|
for method in def.all_methods() {
|
|
let symbol = self.symbol(method);
|
|
res.extend(symbol);
|
|
}
|
|
res
|
|
}
|
|
Expr::PatchDef(def) => {
|
|
let mut res = vec![];
|
|
for method in def.methods.iter() {
|
|
let symbol = self.symbol(method);
|
|
res.extend(symbol);
|
|
}
|
|
res
|
|
}
|
|
_ => vec![],
|
|
}
|
|
}
|
|
}
|