mod bibtex; mod build; mod chktex; mod latex; use std::sync::Arc; use dashmap::DashMap; use lsp_types::{DiagnosticSeverity, NumberOrString, Range, Url}; use regex::Regex; use crate::Workspace; use self::{ bibtex::collect_bibtex_diagnostics, build::collect_build_diagnostics, chktex::collect_chktex_diagnostics, latex::collect_latex_diagnostics, }; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Diagnostic { pub severity: DiagnosticSeverity, pub range: Range, pub code: DiagnosticCode, pub message: String, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] pub enum DiagnosticCode { Latex(LatexCode), Bibtex(BibtexCode), Chktex(String), Build(Arc), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum LatexCode { UnexpectedRCurly, RCurlyInserted, MismatchedEnvironment, } impl From for String { fn from(code: LatexCode) -> Self { match code { LatexCode::UnexpectedRCurly => "Unexpected \"}\"".to_string(), LatexCode::RCurlyInserted => "Missing \"}\" inserted".to_string(), LatexCode::MismatchedEnvironment => "Mismatched environment".to_string(), } } } impl From for NumberOrString { fn from(code: LatexCode) -> Self { match code { LatexCode::UnexpectedRCurly => NumberOrString::Number(1), LatexCode::RCurlyInserted => NumberOrString::Number(2), LatexCode::MismatchedEnvironment => NumberOrString::Number(3), } } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] #[allow(clippy::enum_variant_names)] pub enum BibtexCode { ExpectingLCurly, ExpectingKey, ExpectingRCurly, ExpectingEq, ExpectingFieldValue, } impl From for String { fn from(code: BibtexCode) -> Self { match code { BibtexCode::ExpectingLCurly => "Expecting a curly bracket: \"{\"".to_string(), BibtexCode::ExpectingKey => "Expecting a key".to_string(), BibtexCode::ExpectingRCurly => "Expecting a curly bracket: \"}\"".to_string(), BibtexCode::ExpectingEq => "Expecting an equality sign: \"=\"".to_string(), BibtexCode::ExpectingFieldValue => "Expecting a field value".to_string(), } } } impl From for NumberOrString { fn from(code: BibtexCode) -> Self { match code { BibtexCode::ExpectingLCurly => NumberOrString::Number(4), BibtexCode::ExpectingKey => NumberOrString::Number(5), BibtexCode::ExpectingRCurly => NumberOrString::Number(6), BibtexCode::ExpectingEq => NumberOrString::Number(7), BibtexCode::ExpectingFieldValue => NumberOrString::Number(8), } } } #[derive(Default, Clone)] pub struct DiagnosticManager { all_diagnostics: Arc, Vec>>, } impl DiagnosticManager { pub fn push_syntax(&self, workspace: &Workspace, uri: &Url) { collect_bibtex_diagnostics(&self.all_diagnostics, workspace, uri) .or_else(|| collect_latex_diagnostics(&self.all_diagnostics, workspace, uri)) .or_else(|| collect_build_diagnostics(&self.all_diagnostics, workspace, uri)); } pub fn push_chktex(&self, workspace: &Workspace, uri: &Url) { collect_chktex_diagnostics(&self.all_diagnostics, workspace, uri); } pub fn publish(&self, workspace: &Workspace, uri: &Url) -> Vec { let options = &workspace.environment.options.diagnostics; let mut results = Vec::new(); if let Some(diagnostics) = self.all_diagnostics.get(uri) { for diagnostic in diagnostics.iter() { if !options.allowed_patterns.is_empty() && !options .allowed_patterns .iter() .any(|pattern| pattern.0.is_match(&diagnostic.message)) { continue; } if options .ignored_patterns .iter() .any(|pattern| pattern.0.is_match(&diagnostic.message)) { continue; } let source = match diagnostic.code { DiagnosticCode::Latex(_) | DiagnosticCode::Bibtex(_) => "texlab", DiagnosticCode::Chktex(_) => "chktex", DiagnosticCode::Build(_) => "latex-build", }; let code = match diagnostic.code.clone() { DiagnosticCode::Latex(code) => Some(code.into()), DiagnosticCode::Bibtex(code) => Some(code.into()), DiagnosticCode::Chktex(code) => Some(NumberOrString::String(code)), DiagnosticCode::Build(_) => None, }; results.push(lsp_types::Diagnostic { range: diagnostic.range, code, severity: Some(diagnostic.severity), message: diagnostic.message.clone(), source: Some(source.to_string()), ..Default::default() }); } } results } } #[derive(Debug, Default)] pub struct DiagnosticFilter { pub allowed_patterns: Vec, pub ignored_patterns: Vec, }