summaryrefslogtreecommitdiff
path: root/support/texlab/src/diagnostics/build_log.rs
blob: ede3a873a8027995f697231665abc1d0524981c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::{path::PathBuf, sync::Arc};

use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
use multimap::MultiMap;

use crate::{syntax::build_log::BuildErrorLevel, Uri, Workspace};

pub fn analyze_build_log_static(
    workspace: &dyn Workspace,
    diagnostics_by_uri: &mut MultiMap<Arc<Uri>, Diagnostic>,
    build_log_uri: &Uri,
) -> Option<()> {
    let build_log_document = workspace.get(build_log_uri)?;
    let parse = build_log_document.data.as_build_log()?;

    let root_document = workspace.documents().into_iter().find(|document| {
        if let Some(data) = document.data.as_latex() {
            !document.uri.as_str().ends_with(".aux")
                && data
                    .extras
                    .implicit_links
                    .log
                    .iter()
                    .any(|u| u.as_ref() == build_log_uri)
        } else {
            false
        }
    })?;

    let base_path = PathBuf::from(root_document.uri.path());

    for error in &parse.errors {
        let pos = Position::new(error.line.unwrap_or(0), 0);
        let severity = match error.level {
            BuildErrorLevel::Error => DiagnosticSeverity::Error,
            BuildErrorLevel::Warning => DiagnosticSeverity::Warning,
        };
        let range = Range::new(pos, pos);
        let diagnostic = Diagnostic {
            range,
            severity: Some(severity),
            code: None,
            code_description: None,
            source: Some("latex".into()),
            message: error.message.clone(),
            related_information: None,
            tags: None,
            data: None,
        };

        let full_path = base_path.join(&error.relative_path);

        let uri = if full_path.starts_with(&base_path) {
            error
                .relative_path
                .to_str()
                .and_then(|path| root_document.uri.join(path).map(Into::into).ok())
                .map(Arc::new)
                .unwrap_or_else(|| Arc::clone(&root_document.uri))
        } else {
            Arc::clone(&root_document.uri)
        };

        diagnostics_by_uri.insert(uri, diagnostic);
    }
    Some(())
}