use crate::{
LanguageService,
binder::{IdxKind, SymbolKind, SymbolTable},
helpers::LineIndexExt,
};
use lspt::{CodeLens, CodeLensParams, Command, Location};
use serde::{Deserialize, Serialize};
impl LanguageService {
pub fn code_lens(&self, params: CodeLensParams) -> Option<Vec<CodeLens>> {
let document = self.get_document(¶ms.text_document.uri)?;
self.with_db(|db| {
let line_index = document.line_index(db);
let symbol_table = SymbolTable::of(db, document);
symbol_table
.symbols
.values()
.filter(|symbol| {
matches!(
symbol.kind,
SymbolKind::Func
| SymbolKind::Type
| SymbolKind::GlobalDef
| SymbolKind::MemoryDef
| SymbolKind::TableDef
| SymbolKind::TagDef
| SymbolKind::DataDef
| SymbolKind::ElemDef
)
})
.map(|symbol| CodeLens {
range: line_index.convert(symbol.key.text_range()),
command: None,
data: serde_json::to_value(CodeLensData {
uri: params.text_document.uri.clone(),
kind: symbol.idx_kind,
})
.ok(),
})
.collect()
})
}
pub fn code_lens_resolve(&self, params: CodeLens) -> CodeLens {
self.code_lens_resolve_impl(params.clone()).unwrap_or(params)
}
fn code_lens_resolve_impl(&self, params: CodeLens) -> Option<CodeLens> {
let data = serde_json::from_value::<CodeLensData>(params.data?).ok()?;
let document = self.get_document(&data.uri)?;
let line_index = document.line_index(self);
let symbol_table = SymbolTable::of(self, document);
let range = line_index.convert(params.range)?;
let def_symbol = symbol_table
.symbols
.values()
.find(|symbol| symbol.idx_kind == data.kind && symbol.key.text_range() == range)?;
let locations = symbol_table
.find_references_on_def(def_symbol, false)
.map(|symbol| {
let range = symbol_table
.def_poi
.get(&symbol.key)
.copied()
.unwrap_or_else(|| symbol.key.text_range());
Location {
uri: data.uri.clone(),
range: line_index.convert(range),
}
})
.collect::<Vec<_>>();
Some(CodeLens {
range: params.range,
command: Some(Command {
title: if locations.len() == 1 {
"1 reference".into()
} else {
format!("{} references", locations.len())
},
command: "wasmLanguageTools.showReferences".into(),
arguments: Some(vec![
serde_json::to_value(&data.uri).ok()?,
serde_json::to_value(params.range.start).ok()?,
serde_json::to_value(locations).ok()?,
]),
}),
data: None,
})
}
}
#[derive(Serialize, Deserialize)]
struct CodeLensData {
uri: String,
kind: IdxKind,
}