blob: 2ea041ecf74c31354128200145b7e8721602543b [file] [log] [blame] [edit]
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::sync::atomic::{AtomicUsize, Ordering};
use lsp_data::{ProgressParams, PublishDiagnosticsParams, Progress, ShowMessageParams, MessageType};
use server::{Output, Notification};
use ls_types::notification::{PublishDiagnostics, ShowMessage};
/// Trait for communication of build progress back to the client.
pub trait ProgressNotifier: Send {
fn notify_begin_progress(&self);
fn notify_progress(&self, update: ProgressUpdate);
fn notify_end_progress(&self);
}
/// Kinds of progress updates
pub enum ProgressUpdate {
Message(String),
Percentage(f64),
}
/// Trait for communication of diagnostics (i.e. build results) back to the rest of
/// the RLS (and on to the client).
// This trait only really exists to work around the object safety rules (Output
// is not object-safe).
pub trait DiagnosticsNotifier: Send {
fn notify_begin_diagnostics(&self);
fn notify_publish_diagnostics(&self, PublishDiagnosticsParams);
fn notify_error_diagnostics(&self, msg: String);
fn notify_end_diagnostics(&self);
}
/// Generate a new progress params with a unique ID and the given title.
fn new_progress_params(title: String) -> ProgressParams {
// counter to generate unique ID for each chain-of-progress notifications.
lazy_static! {
static ref PROGRESS_ID_COUNTER: AtomicUsize = {
AtomicUsize::new(0)
};
}
ProgressParams {
id: format!("progress_{}", PROGRESS_ID_COUNTER.fetch_add(1, Ordering::SeqCst)),
title: Some(title),
message: None,
percentage: None,
done: None,
}
}
/// Notifier of progress for the build (window/progress notifications).
/// the same instance is used for the entirety of one single build.
pub struct BuildProgressNotifier<O: Output> {
out: O,
// these params are used as a template and are cloned for each
// message that is actually notified.
progress_params: ProgressParams,
}
impl<O: Output> BuildProgressNotifier<O> {
pub fn new(out: O) -> BuildProgressNotifier<O> {
BuildProgressNotifier {
out,
progress_params: new_progress_params("Building".into()),
}
}
}
impl<O: Output> ProgressNotifier for BuildProgressNotifier<O> {
fn notify_begin_progress(&self) {
let params = self.progress_params.clone();
self.out.notify(Notification::<Progress>::new(params));
}
fn notify_progress(&self, update: ProgressUpdate) {
let mut params = self.progress_params.clone();
match update {
ProgressUpdate::Message(s) => params.message = Some(s),
ProgressUpdate::Percentage(p) => params.percentage = Some(p),
}
self.out.notify(Notification::<Progress>::new(params));
}
fn notify_end_progress(&self) {
let mut params = self.progress_params.clone();
params.done = Some(true);
self.out.notify(Notification::<Progress>::new(params));
}
}
/// Notifier of diagnostics after the build has completed.
pub struct BuildDiagnosticsNotifier<O: Output> {
out: O,
// these params are used as a template and are cloned for each
// message that is actually notified.
progress_params: ProgressParams,
}
impl<O: Output> BuildDiagnosticsNotifier<O> {
pub fn new(out: O) -> BuildDiagnosticsNotifier<O> {
BuildDiagnosticsNotifier {
out,
// We emit diagnostics then index, since emitting diagnostics is really
// quick and always has a message, "indexing" is usually a more useful
// title.
progress_params: new_progress_params("Indexing".into()),
}
}
}
impl<O: Output> DiagnosticsNotifier for BuildDiagnosticsNotifier<O> {
fn notify_begin_diagnostics(&self) {
let params = self.progress_params.clone();
self.out.notify(Notification::<Progress>::new(params));
}
fn notify_publish_diagnostics(&self, params: PublishDiagnosticsParams) {
self.out.notify(Notification::<PublishDiagnostics>::new(params));
}
fn notify_error_diagnostics(&self, message: String) {
self.out.notify(Notification::<ShowMessage>::new(ShowMessageParams {
typ: MessageType::Error,
message: message.to_owned(),
}));
}
fn notify_end_diagnostics(&self) {
let mut params = self.progress_params.clone();
params.done = Some(true);
self.out.notify(Notification::<Progress>::new(params));
}
}