dev: move preview actor (#378)

This commit is contained in:
Myriad-Dreamin 2024-07-08 12:11:12 +08:00 committed by GitHub
parent 8852109b10
commit ad79b29fd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 101 additions and 76 deletions

View file

@ -3,6 +3,7 @@
pub mod editor;
pub mod export;
pub mod format;
pub mod preview;
pub mod typ_client;
pub mod typ_server;
pub mod user_action;

View file

@ -0,0 +1,93 @@
use std::{collections::HashMap, sync::Arc};
use lsp_types::notification::Notification;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use sync_lsp::{internal_error, LspClient, LspResult};
use tokio::sync::{mpsc, oneshot};
use typst_preview::{ControlPlaneMessage, Previewer};
use super::typ_client::CompileHandler;
pub struct PreviewTab {
/// Task ID
pub task_id: String,
/// Previewer
pub previewer: Previewer,
/// Static server killer
pub ss_killer: oneshot::Sender<()>,
/// Static server handle
pub ss_handle: tokio::task::JoinHandle<()>,
/// Control plane message sender
pub ctl_tx: mpsc::UnboundedSender<ControlPlaneMessage>,
/// Compile handler
pub compile_handler: Arc<CompileHandler>,
}
pub enum PreviewRequest {
Started(PreviewTab),
Kill(String, oneshot::Sender<LspResult<JsonValue>>),
Scroll(String, ControlPlaneMessage),
}
pub struct PreviewActor {
pub client: LspClient,
pub tabs: HashMap<String, PreviewTab>,
pub preview_rx: mpsc::UnboundedReceiver<PreviewRequest>,
}
impl PreviewActor {
pub async fn run(mut self) {
while let Some(req) = self.preview_rx.recv().await {
match req {
PreviewRequest::Started(tab) => {
self.tabs.insert(tab.task_id.clone(), tab);
}
PreviewRequest::Kill(task_id, tx) => {
log::info!("PreviewTask({task_id}): killing");
let Some(mut tab) = self.tabs.remove(&task_id) else {
let _ = tx.send(Err(internal_error("task not found")));
continue;
};
let client = self.client.clone();
self.client.handle.spawn(async move {
tab.previewer.stop().await;
let _ = tab.ss_killer.send(());
// Wait for previewer to stop
log::info!("PreviewTask({task_id}): wait for previewer to stop");
tab.previewer.join().await;
log::info!("PreviewTask({task_id}): wait for static server to stop");
let _ = tab.ss_handle.await;
log::info!("PreviewTask({task_id}): killed");
// Unregister preview
tab.compile_handler.unregister_preview(&tab.task_id);
// Send response
let _ = tx.send(Ok(JsonValue::Null));
// Send global notification
client.send_notification::<DisposePreview>(DisposePreview { task_id });
});
}
PreviewRequest::Scroll(task_id, req) => {
self.scroll(task_id, req).await;
}
}
}
}
async fn scroll(&mut self, task_id: String, req: ControlPlaneMessage) -> Option<()> {
self.tabs.get(&task_id)?.ctl_tx.send(req).ok()
}
}
#[derive(Serialize, Deserialize)]
struct DisposePreview {
task_id: String,
}
impl Notification for DisposePreview {
type Params = Self;
const METHOD: &'static str = "tinymist/preview/dispose";
}

View file

@ -23,7 +23,11 @@ use typst_ts_core::config::{compiler::EntryOpts, CompileOpts};
use super::*;
use crate::{compile_init::CompileOnceArgs, LspUniverse};
use actor::{typ_client::CompileHandler, typ_server::CompileServerActor};
use actor::{
preview::{PreviewActor, PreviewRequest, PreviewTab},
typ_client::CompileHandler,
typ_server::CompileServerActor,
};
#[derive(Debug, Clone, clap::Parser)]
pub struct PreviewCliArgs {
@ -51,60 +55,8 @@ pub struct PreviewCliArgs {
pub dont_open_in_browser: bool,
}
pub struct PreviewActor {
client: TypedLspClient<PreviewState>,
tabs: HashMap<String, PreviewTab>,
preview_rx: mpsc::UnboundedReceiver<PreviewRequest>,
}
impl PreviewActor {
pub async fn run(mut self) {
while let Some(req) = self.preview_rx.recv().await {
match req {
PreviewRequest::Started(tab) => {
self.tabs.insert(tab.task_id.clone(), tab);
}
PreviewRequest::Kill(task_id, tx) => {
log::info!("PreviewTask({task_id}): killing");
let Some(mut tab) = self.tabs.remove(&task_id) else {
let _ = tx.send(Err(internal_error("task not found")));
continue;
};
let client = self.client.clone();
self.client.handle.spawn(async move {
tab.previewer.stop().await;
let _ = tab.ss_killer.send(());
// Wait for previewer to stop
log::info!("PreviewTask({task_id}): wait for previewer to stop");
tab.previewer.join().await;
log::info!("PreviewTask({task_id}): wait for static server to stop");
let _ = tab.ss_handle.await;
log::info!("PreviewTask({task_id}): killed");
// Unregister preview
tab.compile_handler.unregister_preview(&tab.task_id);
// Send response
let _ = tx.send(Ok(JsonValue::Null));
// Send global notification
client.send_notification::<DisposePreview>(DisposePreview { task_id });
});
}
PreviewRequest::Scroll(task_id, req) => {
self.scroll(task_id, req).await;
}
}
}
}
async fn scroll(&mut self, task_id: String, req: ControlPlaneMessage) -> Option<()> {
self.tabs.get(&task_id)?.ctl_tx.send(req).ok()
}
}
pub struct PreviewState {
client: TypedLspClient<PreviewState>,
pub client: TypedLspClient<PreviewState>,
preview_tx: mpsc::UnboundedSender<PreviewRequest>,
}
@ -115,7 +67,7 @@ impl PreviewState {
client.handle.spawn(
PreviewActor {
client: client.clone(),
client: client.clone().to_untyped(),
tabs: HashMap::default(),
preview_rx,
}
@ -126,27 +78,6 @@ impl PreviewState {
}
}
pub struct PreviewTab {
/// Task ID
pub task_id: String,
/// Previewer
pub previewer: Previewer,
/// Static server killer
pub ss_killer: oneshot::Sender<()>,
/// Static server handle
pub ss_handle: tokio::task::JoinHandle<()>,
/// Control plane message sender
pub ctl_tx: mpsc::UnboundedSender<ControlPlaneMessage>,
/// Compile handler
pub compile_handler: Arc<CompileHandler>,
}
enum PreviewRequest {
Started(PreviewTab),
Kill(String, oneshot::Sender<LspResult<JsonValue>>),
Scroll(String, ControlPlaneMessage),
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct StartPreviewResponse {