Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 54 additions & 19 deletions crates/typst-preview/src/actor/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl RenderActorRequest {

pub struct RenderActor {
mailbox: broadcast::Receiver<RenderActorRequest>,
direct_mailbox: mpsc::UnboundedReceiver<RenderActorRequest>,
view: Arc<parking_lot::RwLock<Option<Arc<dyn CompileView>>>>,
renderer: IncrSvgDocServer,
editor_conn_sender: mpsc::UnboundedSender<EditorActorRequest>,
Expand All @@ -53,13 +54,15 @@ pub struct RenderActor {
impl RenderActor {
pub fn new(
mailbox: broadcast::Receiver<RenderActorRequest>,
direct_mailbox: mpsc::UnboundedReceiver<RenderActorRequest>,
view: Arc<parking_lot::RwLock<Option<Arc<dyn CompileView>>>>,
editor_conn_sender: mpsc::UnboundedSender<EditorActorRequest>,
svg_sender: mpsc::UnboundedSender<Vec<u8>>,
webview_sender: broadcast::Sender<WebviewActorRequest>,
) -> Self {
let mut res = Self {
mailbox,
direct_mailbox,
view,
renderer: IncrSvgDocServer::default(),
editor_conn_sender,
Expand All @@ -70,10 +73,11 @@ impl RenderActor {
res
}

async fn process_message(&mut self, msg: RenderActorRequest) -> bool {
async fn process_message(&mut self, msg: RenderActorRequest) -> (bool, bool) {
log::trace!("RenderActor: received message: {msg:?}");

let res = msg.is_full_render();
let is_full_render = msg.is_full_render();
let is_incremental_render = matches!(msg, RenderActorRequest::RenderIncremental);
match msg {
RenderActorRequest::EditorResolveSpanRange(span_range) => {
log::debug!("RenderActor: resolving EditorResolveSpanRange: {span_range:?}");
Expand All @@ -86,7 +90,7 @@ impl RenderActor {
Ok(spans) => spans,
Err(err) => {
log::info!("RenderActor: failed to resolve span: {err}");
return false;
return (false, false);
}
};

Expand Down Expand Up @@ -119,28 +123,50 @@ impl RenderActor {
RenderActorRequest::RenderFullLatest | RenderActorRequest::RenderIncremental => {}
}

res
(is_full_render, is_incremental_render)
}

pub async fn run(mut self) {
loop {
let mut has_full_render = false;
let mut has_incremental_render = false;
log::debug!("RenderActor: waiting for message");
match self.mailbox.recv().await {
Ok(msg) => {
has_full_render |= self.process_message(msg).await;
tokio::select! {
msg = self.mailbox.recv() => {
match msg {
Ok(msg) => {
let (full, incremental) = self.process_message(msg).await;
has_full_render |= full;
has_incremental_render |= incremental;
}
Err(broadcast::error::RecvError::Closed) => {
log::info!("RenderActor: no more messages");
break;
}
Err(broadcast::error::RecvError::Lagged(_)) => {
log::info!("RenderActor: lagged message. Some events are dropped");
}
}
}
Err(broadcast::error::RecvError::Closed) => {
log::info!("RenderActor: no more messages");
break;
Some(msg) = self.direct_mailbox.recv() => {
let (full, incremental) = self.process_message(msg).await;
has_full_render |= full;
has_incremental_render |= incremental;
}
Err(broadcast::error::RecvError::Lagged(_)) => {
log::info!("RenderActor: lagged message. Some events are dropped");
else => {
break;
}
}
// read the queue to empty
while let Ok(msg) = self.mailbox.try_recv() {
has_full_render |= self.process_message(msg).await;
let (full, incremental) = self.process_message(msg).await;
has_full_render |= full;
has_incremental_render |= incremental;
}
while let Ok(msg) = self.direct_mailbox.try_recv() {
let (full, incremental) = self.process_message(msg).await;
has_full_render |= full;
has_incremental_render |= incremental;
}
// if a full render is requested, we render the latest document
// otherwise, we render the incremental changes for only once
Expand All @@ -151,7 +177,7 @@ impl RenderActor {
continue;
};

let data = self.render(has_full_render, &document);
let data = self.render(has_full_render, has_incremental_render, &document);
let Ok(_) = self.svg_sender.send(data) else {
log::info!("RenderActor: svg_sender is dropped");
break;
Expand All @@ -160,13 +186,22 @@ impl RenderActor {
log::info!("RenderActor: exiting")
}

fn render(&mut self, has_full_render: bool, document: &TypstDocument) -> Vec<u8> {
if has_full_render {
if let Some(data) = self.render_full() {
data
fn render(
&mut self,
has_full_render: bool,
has_incremental_render: bool,
document: &TypstDocument,
) -> Vec<u8> {
if has_incremental_render {
let delta = self.render_delta(document);
if has_full_render {
self.render_full().unwrap_or(delta)
} else {
self.render_delta(document)
delta
}
} else if has_full_render {
self.render_full()
.unwrap_or_else(|| self.render_delta(document))
} else {
self.render_delta(document)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/typst-preview/src/actor/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct WebviewActor<'a, C> {

broadcast_sender: broadcast::Sender<WebviewActorRequest>,
editor_sender: mpsc::UnboundedSender<EditorActorRequest>,
render_sender: broadcast::Sender<RenderActorRequest>,
render_sender: mpsc::UnboundedSender<RenderActorRequest>,
}

pub struct Channels {
Expand All @@ -69,7 +69,7 @@ where
broadcast_sender: broadcast::Sender<WebviewActorRequest>,
mailbox: broadcast::Receiver<WebviewActorRequest>,
editor_sender: mpsc::UnboundedSender<EditorActorRequest>,
render_sender: broadcast::Sender<RenderActorRequest>,
render_sender: mpsc::UnboundedSender<RenderActorRequest>,
) -> Self {
Self {
webview_websocket_conn: websocket_conn,
Expand Down
4 changes: 3 additions & 1 deletion crates/typst-preview/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,18 @@ impl Previewer {
}
let actor::webview::Channels { svg } =
actor::webview::WebviewActor::<'_, C>::set_up_channels();
let (direct_render_tx, direct_render_rx) = mpsc::unbounded_channel();
let webview_actor = actor::webview::WebviewActor::new(
conn,
svg.1,
h.webview_tx.clone(),
h.webview_tx.subscribe(),
h.editor_tx.clone(),
h.renderer_tx.clone(),
direct_render_tx,
);
let render_actor = actor::render::RenderActor::new(
h.renderer_tx.subscribe(),
direct_render_rx,
h.doc_sender.clone(),
h.editor_tx.clone(),
svg.0,
Expand Down
7 changes: 6 additions & 1 deletion tools/typst-preview-frontend/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ function retrieveWsArgs() {
/// the websocket connection requires an absolute url.
///
/// See [WebSocket and relative URLs](https://github.com/whatwg/websockets/issues/20)
let urlObject = new URL("ws://127.0.0.1:23625", window.location.href);
let url = "ws://127.0.0.1:23625";
if (!url) {
return { url: "", previewMode, isContentPreview: false };
}

let urlObject = new URL(url, window.location.href);
/// Rewrite the protocol to websocket.
urlObject.protocol = urlObject.protocol.replace("https:", "wss:").replace("http:", "ws:");
if (location.href.startsWith("https://")) {
Expand Down