diff --git a/editors/vscode/package.json b/editors/vscode/package.json index 440ec237cc3..73fe1bb5d72 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -91,13 +91,13 @@ }, { "command": "slint.selectRemotePreview", - "title": "Connect to Remote Preview", + "title": "(Experimental) Connect to Remote Preview", "category": "Slint", "icon": "$(preview)" }, { "command": "slint.disconnectRemotePreview", - "title": "Disconnect Remote Preview", + "title": "(Experimental) Disconnect Remote Preview", "category": "Slint", "icon": "$(debug-disconnect)" }, diff --git a/internal/preview-protocol/src/preview_to_lsp.rs b/internal/preview-protocol/src/preview_to_lsp.rs index bc88b5132f9..28fa1d0c5c1 100644 --- a/internal/preview-protocol/src/preview_to_lsp.rs +++ b/internal/preview-protocol/src/preview_to_lsp.rs @@ -8,13 +8,9 @@ use crate::SourceFileVersion; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "kebab-case")] pub enum PreviewTarget { - #[allow(dead_code)] ChildProcess, - #[allow(dead_code)] EmbeddedWasm, - #[allow(dead_code)] Remote, - #[allow(dead_code)] Dummy, } diff --git a/tools/lsp/language.rs b/tools/lsp/language.rs index 305f820d621..c1036287425 100644 --- a/tools/lsp/language.rs +++ b/tools/lsp/language.rs @@ -126,6 +126,16 @@ pub fn send_state_to_preview(ctx: &Context) { #[cfg(any(feature = "preview-external", feature = "preview-engine", feature = "preview-remote"))] pub fn send_files_to_preview(ctx: &Context, files: &[lsp_types::Url]) { for url in files { + if let Some(node) = ctx.document_cache.get_document(url).and_then(|doc| doc.node.as_ref()) { + let version = ctx.document_cache.document_version_by_path(node.source_file.path()); + let contents = node.text().to_string().into(); + tracing::debug!("Sending cached file {} to preview", url); + ctx.to_preview.send(&i_slint_preview_protocol::LspToPreviewMessage::SetContents { + url: i_slint_preview_protocol::VersionedUrl::new(url.clone(), version), + contents, + }); + continue; + } let Some(path) = url.to_file_path().ok() else { tracing::warn!("Cannot convert URL to file path: {url}"); continue; @@ -439,11 +449,14 @@ pub fn register_request_handlers(rh: &mut RequestHandler) { } #[cfg(feature = "preview-remote")] CONNECT_REMOTE_PREVIEW_COMMAND => { - return connect_remote_preview_command(¶ms.arguments, ctx); + return crate::preview::connector::remote::connect_remote_preview_command( + ¶ms.arguments, + ctx, + ); } #[cfg(feature = "preview-remote")] DISCONNECT_REMOTE_PREVIEW_COMMAND => { - disconnect_remote_preview_command(ctx); + crate::preview::connector::remote::disconnect_remote_preview_command(ctx); } _ => { tracing::error!("Received unknown command {}", params.command.as_str()); @@ -673,61 +686,6 @@ pub fn show_preview(component: i_slint_preview_protocol::PreviewComponent, ctx: ctx.to_preview.send(&i_slint_preview_protocol::LspToPreviewMessage::ShowPreview(component)); } -#[cfg(feature = "preview-remote")] -pub fn connect_remote_preview_command( - params: &[serde_json::Value], - ctx: &Context, -) -> Result, LspError> { - let addresses = params.first().and_then(serde_json::Value::as_array).map(|addresses| { - addresses.iter().filter_map(serde_json::Value::as_str).map(String::from).collect::>() - }); - let port = params.get(1).and_then(serde_json::Value::as_u64); - - if let Some(addresses) = addresses { - if let Some(port) = port { - use crate::preview::connector::remote::RemoteLspToPreview; - - let _ = - ctx.to_preview.set_preview_target(i_slint_preview_protocol::PreviewTarget::Remote); - ctx.to_preview.with_preview_target::, LspError>>( - |remote| { - let preview_to_lsp_sender = ctx.preview_to_lsp_sender.clone(); - let future = remote.connect(addresses, port as u16); - crate::common::spawn_local(async move { - if let Err(err) = future.await { - LspError { - code: LspErrorCode::RequestFailed, - message: format!("Failed to connect to remote preview: {err}"), - }; - } else { - let _ = preview_to_lsp_sender.send(PreviewToLspMessage::RequestState { files: Vec::new() }); - } - }); - Ok(None) - }).unwrap() - } else { - Err(LspError { - code: LspErrorCode::InvalidParameter, - message: "Need number as the second parameter".to_owned(), - }) - } - } else { - Err(LspError { - code: LspErrorCode::InvalidParameter, - message: "Need array of string as the first parameter".to_owned(), - }) - } -} - -#[cfg(feature = "preview-remote")] -pub fn disconnect_remote_preview_command(ctx: &Context) { - let to_preview = ctx.to_preview.clone(); - tracing::debug!("disconnect_remote_preview_command"); - to_preview.with_preview_target::(|remote| { - crate::common::spawn_local(remote.disconnect()); - }); -} - fn populate_command_range( node: &SyntaxNode, format: common::ByteFormat, diff --git a/tools/lsp/main.rs b/tools/lsp/main.rs index 5e688dd3dfe..370d553a7b1 100644 --- a/tools/lsp/main.rs +++ b/tools/lsp/main.rs @@ -42,7 +42,7 @@ use std::time::Duration; use crate::common::{SwitchableLspToPreview, document_cache::CompilerConfiguration}; #[cfg(feature = "preview-remote")] -use crate::preview::connector::RemoteLspToPreview; +use crate::preview::connector::remote::RemoteLspToPreview; #[cfg(not(any( target_os = "openbsd", @@ -359,7 +359,7 @@ async fn main_loop( Box::new(preview::connector::EmbeddedLspToPreview::new(sn.clone())); #[cfg(feature = "preview-remote")] let remote_preview: Box = Box::new( - preview::connector::RemoteLspToPreview::new(sn, preview_to_lsp_sender.clone()), + preview::connector::remote::RemoteLspToPreview::new(sn, preview_to_lsp_sender.clone()), ); Rc::new( preview::connector::SwitchableLspToPreview::new( diff --git a/tools/lsp/preview/connector.rs b/tools/lsp/preview/connector.rs index b715614ec64..e4ea1e6499b 100644 --- a/tools/lsp/preview/connector.rs +++ b/tools/lsp/preview/connector.rs @@ -14,8 +14,6 @@ pub use native::*; pub use crate::common::SwitchableLspToPreview; #[cfg(feature = "preview-remote")] pub mod remote; -#[cfg(feature = "preview-remote")] -pub use remote::*; use crate::preview; diff --git a/tools/lsp/preview/connector/remote.rs b/tools/lsp/preview/connector/remote.rs index 318acdece0d..b4e5c3eab34 100644 --- a/tools/lsp/preview/connector/remote.rs +++ b/tools/lsp/preview/connector/remote.rs @@ -14,12 +14,70 @@ use tokio::sync::mpsc; use tokio::{sync::RwLock, task::JoinHandle}; use tokio_tungstenite_wasm::{Message, WebSocketStream}; +use crate::language::{LspError, LspErrorCode}; use crate::preview::connector::remote::remote_notifications::{ ConnectionState, RemoteViewerConnectionState, }; mod remote_notifications; +pub fn connect_remote_preview_command( + params: &[serde_json::Value], + ctx: &crate::language::Context, +) -> Result, LspError> { + let addresses = params.first().and_then(serde_json::Value::as_array).map(|addresses| { + addresses.iter().filter_map(serde_json::Value::as_str).map(String::from).collect::>() + }); + let port = params.get(1).and_then(serde_json::Value::as_u64); + + if let Some(addresses) = addresses { + if let Some(port) = port { + let _ = + ctx.to_preview.set_preview_target(i_slint_preview_protocol::PreviewTarget::Remote); + ctx.to_preview.with_preview_target::, LspError>>( + |remote| { + let preview_to_lsp_sender = ctx.preview_to_lsp_sender.clone(); + let future = remote.connect(addresses, port as u16); + crate::common::spawn_local(async move { + if let Err(err) = future.await { + let _ = preview_to_lsp_sender.send( + PreviewToLspMessage::SendShowMessage { + message: lsp_types::ShowMessageParams { + typ: lsp_types::MessageType::ERROR, + message: format!( + "Failed to connect to remote preview: {err}" + ), + }, + }, + ); + } else { + let _ = preview_to_lsp_sender.send(PreviewToLspMessage::RequestState { files: Vec::new() }); + } + }); + Ok(None) + }).unwrap() + } else { + Err(LspError { + code: LspErrorCode::InvalidParameter, + message: "Need number as the second parameter".to_owned(), + }) + } + } else { + Err(LspError { + code: LspErrorCode::InvalidParameter, + message: "Need array of string as the first parameter".to_owned(), + }) + } +} + +pub fn disconnect_remote_preview_command(ctx: &crate::language::Context) { + let to_preview = ctx.to_preview.clone(); + tracing::debug!("disconnect_remote_preview_command"); + to_preview.with_preview_target::(|remote| { + crate::common::spawn_local(remote.disconnect()); + }); +} + struct RemoteLspConnection { sender: SplitSink, task: tokio::task::JoinHandle<()>,