Abstract over channel

This commit is contained in:
Aleksey Kladov 2020-06-25 08:39:33 +02:00
parent 69e6924dd5
commit dab8808e82
3 changed files with 43 additions and 30 deletions

View file

@ -52,17 +52,19 @@ pub struct FlycheckHandle {
// XXX: drop order is significant // XXX: drop order is significant
cmd_send: Sender<CheckCommand>, cmd_send: Sender<CheckCommand>,
handle: jod_thread::JoinHandle<()>, handle: jod_thread::JoinHandle<()>,
pub task_recv: Receiver<CheckTask>,
} }
impl FlycheckHandle { impl FlycheckHandle {
pub fn spawn(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckHandle { pub fn spawn(
let (task_send, task_recv) = unbounded::<CheckTask>(); config: FlycheckConfig,
workspace_root: PathBuf,
sender: Box<dyn Fn(CheckTask) + Send>,
) -> FlycheckHandle {
let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
let handle = jod_thread::spawn(move || { let handle = jod_thread::spawn(move || {
FlycheckActor::new(config, workspace_root).run(&task_send, &cmd_recv); FlycheckActor::new(config, workspace_root, sender).run(&cmd_recv);
}); });
FlycheckHandle { task_recv, cmd_send, handle } FlycheckHandle { cmd_send, handle }
} }
/// Schedule a re-start of the cargo check worker. /// Schedule a re-start of the cargo check worker.
@ -96,6 +98,7 @@ pub enum CheckCommand {
} }
struct FlycheckActor { struct FlycheckActor {
sender: Box<dyn Fn(CheckTask) + Send>,
config: FlycheckConfig, config: FlycheckConfig,
workspace_root: PathBuf, workspace_root: PathBuf,
last_update_req: Option<Instant>, last_update_req: Option<Instant>,
@ -110,8 +113,13 @@ struct FlycheckActor {
} }
impl FlycheckActor { impl FlycheckActor {
fn new(config: FlycheckConfig, workspace_root: PathBuf) -> FlycheckActor { fn new(
config: FlycheckConfig,
workspace_root: PathBuf,
sender: Box<dyn Fn(CheckTask) + Send>,
) -> FlycheckActor {
FlycheckActor { FlycheckActor {
sender,
config, config,
workspace_root, workspace_root,
last_update_req: None, last_update_req: None,
@ -120,9 +128,9 @@ impl FlycheckActor {
} }
} }
fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) { fn run(&mut self, cmd_recv: &Receiver<CheckCommand>) {
// If we rerun the thread, we need to discard the previous check results first // If we rerun the thread, we need to discard the previous check results first
self.clean_previous_results(task_send); self.clean_previous_results();
loop { loop {
select! { select! {
@ -134,7 +142,7 @@ impl FlycheckActor {
}, },
}, },
recv(self.message_recv) -> msg => match msg { recv(self.message_recv) -> msg => match msg {
Ok(msg) => self.handle_message(msg, task_send), Ok(msg) => self.handle_message(msg),
Err(RecvError) => { Err(RecvError) => {
// Watcher finished, replace it with a never channel to // Watcher finished, replace it with a never channel to
// avoid busy-waiting. // avoid busy-waiting.
@ -146,15 +154,15 @@ impl FlycheckActor {
if self.should_recheck() { if self.should_recheck() {
self.last_update_req = None; self.last_update_req = None;
task_send.send(CheckTask::ClearDiagnostics).unwrap(); self.send(CheckTask::ClearDiagnostics);
self.restart_check_process(); self.restart_check_process();
} }
} }
} }
fn clean_previous_results(&self, task_send: &Sender<CheckTask>) { fn clean_previous_results(&self) {
task_send.send(CheckTask::ClearDiagnostics).unwrap(); self.send(CheckTask::ClearDiagnostics);
task_send.send(CheckTask::Status(Status::End)).unwrap(); self.send(CheckTask::Status(Status::End));
} }
fn should_recheck(&mut self) -> bool { fn should_recheck(&mut self) -> bool {
@ -173,27 +181,25 @@ impl FlycheckActor {
} }
} }
fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) { fn handle_message(&self, msg: CheckEvent) {
match msg { match msg {
CheckEvent::Begin => { CheckEvent::Begin => {
task_send.send(CheckTask::Status(Status::Being)).unwrap(); self.send(CheckTask::Status(Status::Being));
} }
CheckEvent::End => { CheckEvent::End => {
task_send.send(CheckTask::Status(Status::End)).unwrap(); self.send(CheckTask::Status(Status::End));
} }
CheckEvent::Msg(Message::CompilerArtifact(msg)) => { CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap(); self.send(CheckTask::Status(Status::Progress(msg.target.name)));
} }
CheckEvent::Msg(Message::CompilerMessage(msg)) => { CheckEvent::Msg(Message::CompilerMessage(msg)) => {
task_send self.send(CheckTask::AddDiagnostic {
.send(CheckTask::AddDiagnostic {
workspace_root: self.workspace_root.clone(), workspace_root: self.workspace_root.clone(),
diagnostic: msg.message, diagnostic: msg.message,
}) });
.unwrap();
} }
CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {} CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
@ -271,6 +277,10 @@ impl FlycheckActor {
let _ = message_send.send(CheckEvent::End); let _ = message_send.send(CheckEvent::End);
})) }))
} }
fn send(&self, check_task: CheckTask) {
(self.sender)(check_task)
}
} }
enum CheckEvent { enum CheckEvent {

View file

@ -9,7 +9,7 @@ use crossbeam_channel::{unbounded, Receiver};
use lsp_types::Url; use lsp_types::Url;
use parking_lot::RwLock; use parking_lot::RwLock;
use ra_db::{CrateId, SourceRoot, VfsPath}; use ra_db::{CrateId, SourceRoot, VfsPath};
use ra_flycheck::{FlycheckConfig, FlycheckHandle}; use ra_flycheck::{CheckTask, FlycheckConfig, FlycheckHandle};
use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId}; use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId};
use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
use stdx::format_to; use stdx::format_to;
@ -30,12 +30,15 @@ use rustc_hash::{FxHashMap, FxHashSet};
fn create_flycheck( fn create_flycheck(
workspaces: &[ProjectWorkspace], workspaces: &[ProjectWorkspace],
config: &FlycheckConfig, config: &FlycheckConfig,
) -> Option<FlycheckHandle> { ) -> Option<(FlycheckHandle, Receiver<CheckTask>)> {
// FIXME: Figure out the multi-workspace situation // FIXME: Figure out the multi-workspace situation
workspaces.iter().find_map(move |w| match w { workspaces.iter().find_map(move |w| match w {
ProjectWorkspace::Cargo { cargo, .. } => { ProjectWorkspace::Cargo { cargo, .. } => {
let (sender, receiver) = unbounded();
let sender = Box::new(move |msg| sender.send(msg).unwrap());
let cargo_project_root = cargo.workspace_root().to_path_buf(); let cargo_project_root = cargo.workspace_root().to_path_buf();
Some(FlycheckHandle::spawn(config.clone(), cargo_project_root.into())) let flycheck = FlycheckHandle::spawn(config.clone(), cargo_project_root.into(), sender);
Some((flycheck, receiver))
} }
ProjectWorkspace::Json { .. } => { ProjectWorkspace::Json { .. } => {
log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
@ -66,7 +69,7 @@ pub(crate) struct GlobalState {
pub(crate) analysis_host: AnalysisHost, pub(crate) analysis_host: AnalysisHost,
pub(crate) loader: Box<dyn vfs::loader::Handle>, pub(crate) loader: Box<dyn vfs::loader::Handle>,
pub(crate) task_receiver: Receiver<vfs::loader::Message>, pub(crate) task_receiver: Receiver<vfs::loader::Message>,
pub(crate) flycheck: Option<FlycheckHandle>, pub(crate) flycheck: Option<(FlycheckHandle, Receiver<CheckTask>)>,
pub(crate) diagnostics: DiagnosticCollection, pub(crate) diagnostics: DiagnosticCollection,
pub(crate) mem_docs: FxHashSet<VfsPath>, pub(crate) mem_docs: FxHashSet<VfsPath>,
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,

View file

@ -136,7 +136,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
Ok(task) => Event::Vfs(task), Ok(task) => Event::Vfs(task),
Err(RecvError) => return Err("vfs died".into()), Err(RecvError) => return Err("vfs died".into()),
}, },
recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.task_recv)) -> task => match task { recv(global_state.flycheck.as_ref().map_or(&never(), |it| &it.1)) -> task => match task {
Ok(task) => Event::CheckWatcher(task), Ok(task) => Event::CheckWatcher(task),
Err(RecvError) => return Err("check watcher died".into()), Err(RecvError) => return Err("check watcher died".into()),
}, },
@ -290,7 +290,7 @@ fn loop_turn(
if became_ready { if became_ready {
if let Some(flycheck) = &global_state.flycheck { if let Some(flycheck) = &global_state.flycheck {
flycheck.update(); flycheck.0.update();
} }
} }
@ -486,7 +486,7 @@ fn on_notification(
let not = match notification_cast::<lsp_types::notification::DidSaveTextDocument>(not) { let not = match notification_cast::<lsp_types::notification::DidSaveTextDocument>(not) {
Ok(_params) => { Ok(_params) => {
if let Some(flycheck) = &global_state.flycheck { if let Some(flycheck) = &global_state.flycheck {
flycheck.update(); flycheck.0.update();
} }
return Ok(()); return Ok(());
} }