|
1 | 1 | //! An active neovim session.
|
2 | 2 | use std::{
|
| 3 | + collections::VecDeque, |
3 | 4 | future::Future,
|
4 | 5 | sync::{
|
5 | 6 | atomic::{AtomicU64, Ordering},
|
@@ -44,6 +45,69 @@ type ResponseResult = Result<Result<Value, Value>, Arc<DecodeError>>;
|
44 | 45 |
|
45 | 46 | type Queue = Arc<Mutex<Vec<(u64, oneshot::Sender<ResponseResult>)>>>;
|
46 | 47 |
|
| 48 | +/// The current state of redraw notifications. Redraws must be dispatched |
| 49 | +/// sequentially in the order that they were received, as each redraw |
| 50 | +/// notification assumes it starts with the result from the previous redraw. See |
| 51 | +/// `:help ui-events` in Neovim for more info. |
| 52 | +struct RedrawQueue { |
| 53 | + /// Whether there's a future already active that's flushing redraw |
| 54 | + /// notifications |
| 55 | + is_active: bool, |
| 56 | + /// The queue of pending redraw notifications |
| 57 | + queue: VecDeque<Vec<Value>>, |
| 58 | +} |
| 59 | + |
| 60 | +impl RedrawQueue { |
| 61 | + fn new() -> Self { |
| 62 | + RedrawQueue { |
| 63 | + is_active: false, |
| 64 | + queue: VecDeque::<Vec<Value>>::new(), |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +async fn queue_redraw<H, W>( |
| 70 | + queue: &Arc<Mutex<RedrawQueue>>, |
| 71 | + handler: H, |
| 72 | + nvim: Neovim<H::Writer>, |
| 73 | + params: Vec<Value>, |
| 74 | +) |
| 75 | +where |
| 76 | + W: AsyncWrite + Send + Unpin + 'static, |
| 77 | + H: Handler<Writer = W> |
| 78 | +{ |
| 79 | + let mut guard = queue.lock().await; |
| 80 | + |
| 81 | + guard.queue.push_front(params); |
| 82 | + if guard.is_active { |
| 83 | + return; |
| 84 | + } |
| 85 | + guard.is_active = true; |
| 86 | + drop(guard); |
| 87 | + |
| 88 | + let queue = queue.clone(); |
| 89 | + let handler_c = handler.clone(); |
| 90 | + let neovim = nvim.clone(); |
| 91 | + handler.spawn(async move { |
| 92 | + loop { |
| 93 | + let redraw = { |
| 94 | + let mut guard = queue.lock().await; |
| 95 | + |
| 96 | + if let Some(redraw) = guard.queue.pop_back() { |
| 97 | + redraw |
| 98 | + } else { |
| 99 | + guard.is_active = false; |
| 100 | + return; |
| 101 | + } |
| 102 | + }; |
| 103 | + |
| 104 | + handler_c |
| 105 | + .handle_notify("redraw".into(), redraw, neovim.clone()) |
| 106 | + .await; |
| 107 | + } |
| 108 | + }); |
| 109 | +} |
| 110 | + |
47 | 111 | /// An active Neovim session.
|
48 | 112 | pub struct Neovim<W>
|
49 | 113 | where
|
@@ -190,6 +254,7 @@ where
|
190 | 254 | R: AsyncRead + Send + Unpin + 'static,
|
191 | 255 | {
|
192 | 256 | let mut rest: Vec<u8> = vec![];
|
| 257 | + let ui_queue = Arc::new(Mutex::new(RedrawQueue::new())); |
193 | 258 |
|
194 | 259 | loop {
|
195 | 260 | let msg = match model::decode(&mut reader, &mut rest).await {
|
@@ -251,9 +316,14 @@ where
|
251 | 316 | RpcMessage::RpcNotification { method, params } => {
|
252 | 317 | let handler_c = handler.clone();
|
253 | 318 | let neovim = neovim.clone();
|
254 |
| - handler.spawn(async move { |
255 |
| - handler_c.handle_notify(method, params, neovim).await |
256 |
| - }); |
| 319 | + |
| 320 | + if method == "redraw" { |
| 321 | + queue_redraw(&ui_queue, handler_c, neovim, params).await; |
| 322 | + } else { |
| 323 | + handler.spawn(async move { |
| 324 | + handler_c.handle_notify(method, params, neovim).await |
| 325 | + }); |
| 326 | + } |
257 | 327 | }
|
258 | 328 | };
|
259 | 329 | }
|
|
0 commit comments