use base_db::{deps, Document, Workspace}; use line_index::LineCol; use multimap::MultiMap; use rowan::{TextLen, TextRange, TextSize}; use rustc_hash::FxHashMap; use syntax::BuildError; use url::Url; use crate::types::Diagnostic; pub fn update( workspace: &Workspace, log_document: &Document, results: &mut FxHashMap>, ) -> Option<()> { let mut errors = MultiMap::default(); let data = log_document.data.as_log()?; let parents = deps::parents(workspace, log_document); let root_document = parents.iter().next()?; let base_path = root_document .path .as_deref() .and_then(|path| path.parent())?; for error in &data.errors { let full_path = base_path.join(&error.relative_path); let Ok(full_path_uri) = Url::from_file_path(&full_path) else { continue; }; let tex_document = workspace.lookup(&full_path_uri).unwrap_or(root_document); let range = find_range_of_hint(tex_document, error).unwrap_or_else(|| { let line = error.line.unwrap_or(0); let offset = tex_document .line_index .offset(LineCol { line, col: 0 }) .unwrap_or(TextSize::from(0)); TextRange::empty(offset) }); let diagnostic = Diagnostic::Build(range, error.clone()); errors.insert(tex_document.uri.clone(), diagnostic); } results.insert(log_document.uri.clone(), errors); Some(()) } fn find_range_of_hint(document: &Document, error: &BuildError) -> Option { let line = error.line?; let hint = error.hint.as_deref()?; let line_index = &document.line_index; let line_start = line_index.offset(LineCol { line, col: 0 })?; let line_end = line_index .offset(LineCol { line: line + 1, col: 0, }) .unwrap_or_else(|| document.text.text_len()); let line_text = &document.text[line_start.into()..line_end.into()]; let hint_start = line_start + TextSize::try_from(line_text.find(hint)?).unwrap(); let hint_end = hint_start + hint.text_len(); Some(TextRange::new(hint_start, hint_end)) }