use cairo_lang_filesystem::ids::{FileId, SpanInFile};
use cairo_lang_syntax::node::ast::TerminalIdentifier;
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
use cairo_language_common::CommonGroup;
use itertools::Itertools;
use lsp_types::{DocumentHighlight, DocumentHighlightParams};
use crate::lang::db::{AnalysisDatabase, LsSyntaxGroup};
use crate::lang::defs::SymbolSearch;
use crate::lang::lsp::{LsProtoGroup, ToCairo, ToLsp};
use crate::lang::usages::search_scope::SearchScope;
pub fn highlight(
params: DocumentHighlightParams,
db: &AnalysisDatabase,
) -> Option<Vec<DocumentHighlight>> {
let file = db.file_for_url(¶ms.text_document_position_params.text_document.uri)?;
let position = params.text_document_position_params.position.to_cairo();
let identifier = db.find_identifier_at_position(file, position)?.as_syntax_node();
let default = vec![identifier];
let highlights = db
.get_node_resultants(identifier)
.unwrap_or(&default)
.iter()
.filter_map(|node| highlights(db, node, file))
.flatten()
.unique()
.map(|range| DocumentHighlight { range, kind: None })
.collect();
Some(highlights)
}
fn highlights<'db>(
db: &'db AnalysisDatabase,
syntax_node: &SyntaxNode<'db>,
file: FileId<'db>,
) -> Option<Vec<lsp_types::Range>> {
let identifier =
syntax_node.ancestors_with_self(db).find_map(|node| TerminalIdentifier::cast(db, node))?;
let symbol_search = SymbolSearch::find_definition(db, &identifier)?;
let highlights = symbol_search
.usages(db)
.include_declaration(true)
.in_scope(SearchScope::file_with_subfiles(db, file))
.originating_locations(db)
.filter(|found| found.file_id == file)
.filter_map(|SpanInFile { file_id, span }: SpanInFile<'_>| {
span.position_in_file(db, file_id).as_ref().map(ToLsp::to_lsp)
})
.collect();
Some(highlights)
}