Skip to content

Commit

Permalink
Refactor ChkTeX module
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Apr 10, 2020
1 parent 9c8570a commit 2117d1c
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 2 deletions.
88 changes: 88 additions & 0 deletions src/diagnostics/latex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::{
protocol::{Diagnostic, DiagnosticSeverity, NumberOrString, Range, RangeExt, Uri},
workspace::Document,
};
use once_cell::sync::Lazy;
use regex::Regex;
use std::{collections::HashMap, process::Stdio};
use tokio::{prelude::*, process::Command};

#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct LatexDiagnosticsProvider {
diagnostics_by_uri: HashMap<Uri, Vec<Diagnostic>>,
}

impl LatexDiagnosticsProvider {
pub fn get(&self, document: &Document) -> Vec<Diagnostic> {
match self.diagnostics_by_uri.get(&document.uri) {
Some(diagnostics) => diagnostics.to_owned(),
None => Vec::new(),
}
}

pub async fn update(&mut self, uri: &Uri, text: &str) {
if uri.scheme() != "file" {
return;
}

self.diagnostics_by_uri
.insert(uri.clone(), lint(text).await.unwrap_or_default());
}
}

pub static LINE_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new("(\\d+):(\\d+):(\\d+):(\\w+):(\\w+):(.*)").unwrap());

async fn lint(text: &str) -> io::Result<Vec<Diagnostic>> {
let mut process: tokio::process::Child = Command::new("chktex")
.args(&["-I0", "-f%l:%c:%d:%k:%n:%m\n"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.kill_on_drop(true)
.spawn()?;

process
.stdin
.take()
.unwrap()
.write_all(text.as_bytes())
.await?;

let mut stdout = String::new();
process
.stdout
.take()
.unwrap()
.read_to_string(&mut stdout)
.await?;

let mut diagnostics = Vec::new();
for line in stdout.lines() {
if let Some(captures) = LINE_REGEX.captures(line) {
let line = captures[1].parse::<u64>().unwrap() - 1;
let character = captures[2].parse::<u64>().unwrap() - 1;
let digit = captures[3].parse::<u64>().unwrap();
let kind = &captures[4];
let code = &captures[5];
let message = captures[6].into();
let range = Range::new_simple(line, character, line, character + digit);
let severity = match kind {
"Message" => DiagnosticSeverity::Information,
"Warning" => DiagnosticSeverity::Warning,
_ => DiagnosticSeverity::Error,
};

diagnostics.push(Diagnostic {
source: Some("chktex".into()),
code: Some(NumberOrString::String(code.into())),
message,
severity: Some(severity),
range,
related_information: None,
tags: None,
})
}
}
Ok(diagnostics)
}
4 changes: 4 additions & 0 deletions src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
mod bibtex;
mod build;
mod latex;

pub use self::{
bibtex::{BibtexDiagnosticsProvider, BibtexError, BibtexErrorCode},
build::BuildDiagnosticsProvider,
latex::LatexDiagnosticsProvider,
};

use crate::{protocol::Diagnostic, workspace::Document};

#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct DiagnosticsManager {
pub bibtex: BibtexDiagnosticsProvider,
pub latex: LatexDiagnosticsProvider,
pub build: BuildDiagnosticsProvider,
}

impl DiagnosticsManager {
pub fn get(&self, doc: &Document) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
diagnostics.append(&mut self.bibtex.get(doc));
diagnostics.append(&mut self.latex.get(doc));
diagnostics.append(&mut self.build.get(doc));
diagnostics
}
Expand Down
54 changes: 52 additions & 2 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
self.action_manager
.push(Action::DetectRoot(uri.clone().into()))
.await;
self.action_manager
.push(Action::RunLinter(uri.into(), LintReason::Save))
.await;
self.action_manager.push(Action::PublishDiagnostics).await;
}

Expand All @@ -193,14 +196,28 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
.update(uri.into(), change.text, &options)
.await;
}
self.action_manager
.push(Action::RunLinter(
params.text_document.uri.clone().into(),
LintReason::Change,
))
.await;
self.action_manager.push(Action::PublishDiagnostics).await;
}

#[jsonrpc_method("textDocument/didSave", kind = "notification")]
pub async fn did_save(&self, params: DidSaveTextDocumentParams) {
self.action_manager
.push(Action::Build(params.text_document.uri.into()))
.push(Action::Build(params.text_document.uri.clone().into()))
.await;

self.action_manager
.push(Action::RunLinter(
params.text_document.uri.into(),
LintReason::Save,
))
.await;
self.action_manager.push(Action::PublishDiagnostics).await;
}

#[jsonrpc_method("textDocument/didClose", kind = "notification")]
Expand Down Expand Up @@ -566,11 +583,43 @@ impl<C: LspClient + Send + Sync + 'static> Middleware for LatexLspServer<C> {
self.build(BuildParams { text_document }).await.unwrap();
}
}
};
Action::RunLinter(uri, reason) => {
let options = self
.config_manager()
.get()
.await
.latex
.and_then(|opts| opts.lint)
.unwrap_or_default();
if options.on_save() {
let should_lint = match reason {
LintReason::Change => options.on_change(),
LintReason::Save => options.on_save() || options.on_change(),
};

if should_lint {
let snapshot = self.workspace.get().await;
if let Some(doc) = snapshot.find(&uri) {
if let DocumentContent::Latex(_) = &doc.content {
let mut diagnostics_manager =
self.diagnostics_manager.lock().await;
diagnostics_manager.latex.update(&uri, &doc.text).await;
}
}
}
}
}
}
}
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum LintReason {
Change,
Save,
}

#[derive(Debug, PartialEq, Clone)]
enum Action {
LoadDistribution,
Expand All @@ -579,6 +628,7 @@ enum Action {
DetectRoot(Uri),
PublishDiagnostics,
Build(Uri),
RunLinter(Uri, LintReason),
}

#[derive(Debug, Default)]
Expand Down

0 comments on commit 2117d1c

Please sign in to comment.