diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | cli/Cargo.toml | 1 | ||||
-rw-r--r-- | cli/file_watcher.rs | 44 | ||||
-rw-r--r-- | cli/tools/repl.rs | 10 |
4 files changed, 33 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock index 98ae0b03e..350702abc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -431,6 +431,7 @@ dependencies = [ "notify", "os_pipe", "percent-encoding", + "pin-project 1.0.4", "regex", "ring", "rustyline", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 863051a11..08e562632 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -59,6 +59,7 @@ log = { version = "0.4.13", features = ["serde"] } lspower = "0.3.0" notify = "5.0.0-pre.4" percent-encoding = "2.1.0" +pin-project = "1.0.4" regex = "1.4.3" ring = "0.16.19" rustyline = { version = "7.1.0", default-features = false } diff --git a/cli/file_watcher.rs b/cli/file_watcher.rs index d9681af7f..7bc4dd7b7 100644 --- a/cli/file_watcher.rs +++ b/cli/file_watcher.rs @@ -1,10 +1,10 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. use crate::colors; -use core::task::{Context, Poll}; use deno_core::error::AnyError; +use deno_core::futures::ready; use deno_core::futures::stream::{Stream, StreamExt}; -use deno_core::futures::{Future, FutureExt}; +use deno_core::futures::Future; use notify::event::Event as NotifyEvent; use notify::event::EventKind; use notify::Config; @@ -12,27 +12,35 @@ use notify::Error as NotifyError; use notify::RecommendedWatcher; use notify::RecursiveMode; use notify::Watcher; +use pin_project::pin_project; use std::path::PathBuf; use std::pin::Pin; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::task::Context; +use std::task::Poll; use std::time::Duration; +use tokio::pin; use tokio::select; use tokio::time::sleep; +use tokio::time::Instant; +use tokio::time::Sleep; -const DEBOUNCE_INTERVAL_MS: Duration = Duration::from_millis(200); +const DEBOUNCE_INTERVAL: Duration = Duration::from_millis(200); type FileWatcherFuture<T> = Pin<Box<dyn Future<Output = T>>>; +#[pin_project(project = DebounceProjection)] struct Debounce { - sleep: Pin<Box<dyn Future<Output = ()>>>, + #[pin] + timer: Sleep, event_detected: Arc<AtomicBool>, } impl Debounce { fn new() -> Self { Self { - sleep: sleep(DEBOUNCE_INTERVAL_MS).boxed_local(), + timer: sleep(DEBOUNCE_INTERVAL), event_detected: Arc::new(AtomicBool::new(false)), } } @@ -41,24 +49,19 @@ impl Debounce { impl Stream for Debounce { type Item = (); - /// Note that this never returns `Poll::Ready(None)`, which means that file watcher will be alive - /// until the Deno process is terminated. + /// Note that this never returns `Poll::Ready(None)`, which means that the + /// file watcher will be alive until the Deno process is terminated. fn poll_next( self: Pin<&mut Self>, cx: &mut Context, ) -> Poll<Option<Self::Item>> { - let inner = self.get_mut(); - if inner.event_detected.load(Ordering::Relaxed) { - inner.event_detected.store(false, Ordering::Relaxed); + if self.event_detected.swap(false, Ordering::Relaxed) { Poll::Ready(Some(())) } else { - match inner.sleep.poll_unpin(cx) { - Poll::Ready(_) => { - inner.sleep = sleep(DEBOUNCE_INTERVAL_MS).boxed_local(); - Poll::Pending - } - Poll::Pending => Poll::Pending, - } + let mut timer = self.project().timer; + ready!(timer.as_mut().poll(cx)); + timer.reset(Instant::now() + DEBOUNCE_INTERVAL); + Poll::Pending } } } @@ -96,7 +99,8 @@ where F: Fn() -> Result<Vec<PathBuf>, AnyError>, G: Fn(Vec<PathBuf>) -> FileWatcherFuture<Result<(), AnyError>>, { - let mut debounce = Debounce::new(); + let debounce = Debounce::new(); + pin!(debounce); loop { let paths = target_resolver()?; @@ -169,7 +173,9 @@ where G: Fn(T) -> FileWatcherFuture<Result<(), AnyError>>, T: Clone, { - let mut debounce = Debounce::new(); + let debounce = Debounce::new(); + pin!(debounce); + // Store previous data. If module resolution fails at some point, the watcher will try to // continue watching files using these data. let mut paths = Vec::new(); diff --git a/cli/tools/repl.rs b/cli/tools/repl.rs index cf5c0e983..23b0afe2d 100644 --- a/cli/tools/repl.rs +++ b/cli/tools/repl.rs @@ -6,7 +6,6 @@ use crate::colors; use crate::media_type::MediaType; use crate::program_state::ProgramState; use deno_core::error::AnyError; -use deno_core::futures::FutureExt; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_runtime::inspector::InspectorSession; @@ -29,6 +28,7 @@ use std::sync::mpsc::SyncSender; use std::sync::Arc; use std::sync::Mutex; use swc_ecmascript::parser::token::{Token, Word}; +use tokio::pin; // Provides helpers to the editor like validation for multi-line edits, completion candidates for // tab completion. @@ -305,8 +305,10 @@ async fn read_line_and_poll( // Because an inspector websocket client may choose to connect at anytime when we have an // inspector server we need to keep polling the worker to pick up new connections. - let mut timeout = - tokio::time::sleep(tokio::time::Duration::from_millis(100)).boxed_local(); + // TODO(piscisaureus): the above comment is a red herring; figure out if/why + // the event loop isn't woken by a waker when a websocket client connects. + let timeout = tokio::time::sleep(tokio::time::Duration::from_millis(100)); + pin!(timeout); tokio::select! { result = &mut line => { @@ -315,7 +317,7 @@ async fn read_line_and_poll( _ = worker.run_event_loop(), if poll_worker => { poll_worker = false; } - _ = &mut timeout => { + _ = timeout => { poll_worker = true } } |