Skip to content

Commit

Permalink
Do not rely on workspace/didChangeWatchedFiles
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Sep 27, 2019
1 parent d491492 commit f326c93
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 88 deletions.
18 changes: 12 additions & 6 deletions crates/jsonrpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,31 @@ where
let response = server.handle_request(request).await;
let json = serde_json::to_string(&response).unwrap();
output.send(json).await.unwrap();
server.after_message().await;
});
}
Ok(Message::Notification(notification)) => {
self.server.handle_notification(notification);
self.after_message();
}
Ok(Message::Response(response)) => {
self.client.handle(response).await;
self.after_message();
}
Err(why) => {
let response = Response::error(why, None);
let json = serde_json::to_string(&response).unwrap();
self.output.send(json).await.unwrap();
self.after_message();
}
}

let server = Arc::clone(&self.server);
tokio::spawn(async move {
server.after_message().await;
});
};
}
}

fn after_message(&self) {
let server = Arc::clone(&self.server);
tokio::spawn(async move {
server.after_message().await;
});
}
}
3 changes: 0 additions & 3 deletions src/action.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::workspace::Uri;
use lsp_types::ProgressToken;
use std::mem;
use std::path::PathBuf;
use std::sync::Mutex;

#[derive(Debug, PartialEq, Eq, Clone)]
Expand All @@ -12,12 +11,10 @@ pub enum LintReason {

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Action {
RegisterCapabilities,
DetectRoot(Uri),
DetectChildren,
PublishDiagnostics,
RunLinter(Uri, LintReason),
ParseLog { tex_uri: Uri, log_path: PathBuf },
Build(Uri),
CancelBuild(ProgressToken),
}
Expand Down
45 changes: 42 additions & 3 deletions src/diagnostics/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ use path_clean::PathClean;
use regex::{Match, Regex};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::path::PathBuf;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::str;
use std::time::SystemTime;

#[derive(Debug, PartialEq, Eq, Clone)]
struct LogFile {
path: PathBuf,
modified: SystemTime,
}

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

impl BuildDiagnosticsProvider {
Expand All @@ -21,15 +31,44 @@ impl BuildDiagnosticsProvider {
}
}

pub fn update(&mut self, uri: &Uri, log: &str) {
pub fn update(&mut self, tex_uri: &Uri) -> io::Result<bool> {
if tex_uri.scheme() != "file" {
return Ok(false);
}

let log_path = tex_uri.to_file_path().unwrap().with_extension("log");
let modified = fs::metadata(&log_path)?.modified()?;

for log_file in &mut self.log_files {
if log_file.path == log_path {
return if modified > log_file.modified {
log_file.modified = modified;
self.update_diagnostics(tex_uri, &log_path)
} else {
Ok(false)
};
}
}

self.update_diagnostics(tex_uri, &log_path)?;
self.log_files.push(LogFile {
path: log_path,
modified,
});
Ok(true)
}

fn update_diagnostics(&mut self, tex_uri: &Uri, log_path: &Path) -> io::Result<bool> {
let log = fs::read_to_string(log_path)?;
self.diagnostics_by_uri.clear();
for error in parse_build_log(uri, log) {
for error in parse_build_log(tex_uri, &log) {
let diagnostics = self
.diagnostics_by_uri
.entry(error.uri.clone())
.or_insert_with(Vec::new);
diagnostics.push(error.into());
}
Ok(true)
}
}

Expand Down
112 changes: 36 additions & 76 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {

#[jsonrpc_method("initialized", kind = "notification")]
pub fn initialized(&self, _params: InitializedParams) {
self.action_manager.push(Action::RegisterCapabilities);
self.action_manager.push(Action::DetectChildren);
self.action_manager.push(Action::PublishDiagnostics);
}
Expand All @@ -150,37 +149,6 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
#[jsonrpc_method("$/cancelRequest", kind = "notification")]
pub fn cancel_request(&self, _params: CancelParams) {}

#[jsonrpc_method("workspace/didChangeWatchedFiles", kind = "notification")]
pub fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) {
let workspace = self.workspace_manager.get();
for change in params.changes {
if change.uri.scheme() != "file" {
continue;
}

let file_path = change.uri.to_file_path().unwrap();
match file_path.extension().unwrap().to_str().unwrap() {
"log" => {
let tex_path = file_path.with_extension("tex");
let tex_uri = Uri::from_file_path(tex_path).unwrap();
if workspace.find(&tex_uri).is_some() {
self.action_manager.push(Action::ParseLog {
tex_uri,
log_path: file_path,
});
}
}
"aux" => {
drop(self.workspace_manager.load(&file_path));
}
extension => {
warn!("Unknown file extension in file watcher: {}", extension);
}
}
}
self.action_manager.push(Action::PublishDiagnostics);
}

#[jsonrpc_method("textDocument/didOpen", kind = "notification")]
pub fn did_open(&self, params: DidOpenTextDocumentParams) {
let uri = params.text_document.uri.clone();
Expand Down Expand Up @@ -470,57 +438,55 @@ impl<C: LspClient + Send + Sync + 'static> LatexLspServer<C> {
}
}

async fn register_capabilities(&self) {
if self
.client_capabilities
.get()
.and_then(|cap| cap.workspace.as_ref())
.and_then(|cap| cap.did_change_watched_files.as_ref())
.and_then(|cap| cap.dynamic_registration)
.unwrap_or(false)
{
let options = DidChangeWatchedFilesRegistrationOptions {
watchers: vec![
FileSystemWatcher {
kind: Some(WatchKind::Create | WatchKind::Change),
glob_pattern: "**/*.log".into(),
},
FileSystemWatcher {
kind: Some(WatchKind::Create | WatchKind::Change),
glob_pattern: "**/*.aux".into(),
},
],
};
fn update_document(&self, document: &Document) -> std::result::Result<(), LoadError> {
if document.uri.scheme() != "file" {
return Ok(());
}

if let Err(why) = self
.client
.register_capability(RegistrationParams {
registrations: vec![Registration {
id: "file-watcher".into(),
method: "workspace/didChangeWatchedFiles".into(),
register_options: Some(serde_json::to_value(options).unwrap()),
}],
})
.await
{
warn!(
"Client does not support dynamic capability registration: {}",
why.message
);
let path = document.uri.to_file_path().unwrap();
let data = fs::metadata(&path).map_err(LoadError::IO)?;
if data.modified().map_err(LoadError::IO)? > document.modified {
self.workspace_manager.load(&path)
} else {
Ok(())
}
}

async fn update_build_diagnostics(&self) {
let workspace = self.workspace_manager.get();
let mut diagnostics_manager = self.diagnostics_manager.lock().await;
for document in &workspace.documents {
if document.uri.scheme() != "file" {
continue;
}

if let SyntaxTree::Latex(tree) = &document.tree {
if tree.is_standalone {
match diagnostics_manager.build.update(&document.uri) {
Ok(true) => self.action_manager.push(Action::PublishDiagnostics),
Ok(false) => (),
Err(_) => warn!("Unable to read log file: {}", document.uri.as_str()),
}
}
}
}
}
}

impl<C: LspClient + Send + Sync + 'static> jsonrpc::Middleware for LatexLspServer<C> {
#[boxed]
async fn before_message(&self) {}
async fn before_message(&self) {
let workspace = self.workspace_manager.get();
for document in &workspace.documents {
drop(self.update_document(document));
}
}

#[boxed]
async fn after_message(&self) {
self.update_build_diagnostics().await;
for action in self.action_manager.take() {
match action {
Action::RegisterCapabilities => self.register_capabilities().await,
Action::DetectRoot(uri) => {
if uri.scheme() == "file" {
let mut path = uri.to_file_path().unwrap();
Expand Down Expand Up @@ -597,12 +563,6 @@ impl<C: LspClient + Send + Sync + 'static> jsonrpc::Middleware for LatexLspServe
}
}
}
Action::ParseLog { tex_uri, log_path } => {
if let Ok(log) = fs::read_to_string(&log_path) {
let mut diagnostics_manager = self.diagnostics_manager.lock().await;
diagnostics_manager.build.update(&tex_uri, &log);
}
}
Action::Build(uri) => {
let config: BuildOptions = self.configuration("latex.build").await;
if config.on_save() {
Expand Down

0 comments on commit f326c93

Please sign in to comment.