mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 20:31:27 +00:00
LSP: Report error through the LSP when the preview can't open
Instead of panicking the whole server Issue #204
This commit is contained in:
parent
3c08a71d21
commit
21e67e27a7
6 changed files with 133 additions and 105 deletions
|
|
@ -673,6 +673,8 @@ pub enum PreviewToLspMessage {
|
|||
RequestState { unused: bool },
|
||||
/// Pass a `WorkspaceEdit` on to the editor
|
||||
SendWorkspaceEdit { label: Option<String>, edit: lsp_types::WorkspaceEdit },
|
||||
/// Pass a `ShowMessage` notification on to the editor
|
||||
SendShowMessage { message: lsp_types::ShowMessageParams },
|
||||
}
|
||||
|
||||
/// Information on the Element types available
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ use i_slint_compiler::CompilerConfiguration;
|
|||
use lsp_types::notification::{
|
||||
DidChangeConfiguration, DidChangeTextDocument, DidOpenTextDocument, Notification,
|
||||
};
|
||||
use lsp_types::{
|
||||
DidChangeTextDocumentParams, DidOpenTextDocumentParams, InitializeParams, ShowMessageParams,
|
||||
Url,
|
||||
};
|
||||
use lsp_types::{DidChangeTextDocumentParams, DidOpenTextDocumentParams, InitializeParams, Url};
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use itertools::Itertools;
|
||||
|
|
@ -161,7 +158,7 @@ impl ServerNotifier {
|
|||
let _ = self.send_notification::<common::LspToPreviewMessage>(message);
|
||||
} else {
|
||||
#[cfg(feature = "preview-builtin")]
|
||||
preview::lsp_to_preview_message(message, self);
|
||||
preview::lsp_to_preview_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +284,9 @@ fn main_loop(connection: Connection, init_param: InitializeParams, cli_args: Cli
|
|||
preview_to_lsp_sender,
|
||||
};
|
||||
|
||||
#[cfg(feature = "preview-builtin")]
|
||||
preview::set_server_notifier(server_notifier.clone());
|
||||
|
||||
let mut compiler_config =
|
||||
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
|
||||
|
||||
|
|
@ -435,7 +435,7 @@ async fn handle_notification(req: lsp_server::Notification, ctx: &Rc<Context>) -
|
|||
LspErrorCode::RequestFailed => ctx
|
||||
.server_notifier
|
||||
.send_notification::<lsp_types::notification::ShowMessage>(
|
||||
ShowMessageParams {
|
||||
lsp_types::ShowMessageParams {
|
||||
typ: lsp_types::MessageType::ERROR,
|
||||
message: e.message,
|
||||
},
|
||||
|
|
@ -514,6 +514,10 @@ async fn handle_preview_to_lsp_message(
|
|||
M::SendWorkspaceEdit { label, edit } => {
|
||||
let _ = send_workspace_edit(ctx.server_notifier.clone(), label, Ok(edit)).await;
|
||||
}
|
||||
M::SendShowMessage { message } => {
|
||||
ctx.server_notifier
|
||||
.send_notification::<lsp_types::notification::ShowMessage>(message)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
use crate::common::properties;
|
||||
use crate::common::{
|
||||
self, component_catalog, rename_component, ComponentInformation, ElementRcNode,
|
||||
PreviewComponent, PreviewConfig,
|
||||
self, component_catalog, properties, rename_component, ComponentInformation, ElementRcNode,
|
||||
PreviewComponent, PreviewConfig, PreviewToLspMessage,
|
||||
};
|
||||
use crate::lsp_ext::Health;
|
||||
use crate::preview::element_selection::ElementSelection;
|
||||
|
|
@ -16,7 +15,7 @@ use i_slint_core::component_factory::FactoryContext;
|
|||
use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize};
|
||||
use i_slint_core::model::VecModel;
|
||||
use lsp_types::Url;
|
||||
use slint::Model;
|
||||
use slint::{Model, PlatformError};
|
||||
use slint_interpreter::{ComponentDefinition, ComponentHandle, ComponentInstance};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
|
@ -131,13 +130,12 @@ struct PreviewState {
|
|||
}
|
||||
thread_local! {static PREVIEW_STATE: std::cell::RefCell<PreviewState> = Default::default();}
|
||||
|
||||
struct DummyWaker();
|
||||
|
||||
impl std::task::Wake for DummyWaker {
|
||||
fn wake(self: std::sync::Arc<Self>) {}
|
||||
}
|
||||
|
||||
pub fn poll_once<F: std::future::Future>(future: F) -> Option<F::Output> {
|
||||
struct DummyWaker();
|
||||
impl std::task::Wake for DummyWaker {
|
||||
fn wake(self: std::sync::Arc<Self>) {}
|
||||
}
|
||||
|
||||
let waker = std::sync::Arc::new(DummyWaker()).into();
|
||||
let mut ctx = std::task::Context::from_waker(&waker);
|
||||
|
||||
|
|
@ -149,7 +147,7 @@ pub fn poll_once<F: std::future::Future>(future: F) -> Option<F::Output> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_contents(url: &common::VersionedUrl, content: String) {
|
||||
fn set_contents(url: &common::VersionedUrl, content: String) {
|
||||
let mut cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
let old = cache.source_code.insert(url.url().clone(), (*url.version(), content.clone()));
|
||||
|
||||
|
|
@ -803,10 +801,7 @@ fn send_workspace_edit(label: String, edit: lsp_types::WorkspaceEdit) -> bool {
|
|||
});
|
||||
|
||||
if !workspace_edit_sent {
|
||||
send_message_to_lsp(common::PreviewToLspMessage::SendWorkspaceEdit {
|
||||
label: Some(label),
|
||||
edit,
|
||||
});
|
||||
send_message_to_lsp(PreviewToLspMessage::SendWorkspaceEdit { label: Some(label), edit });
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -903,7 +898,7 @@ fn finish_parsing(ok: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn config_changed(config: PreviewConfig) {
|
||||
fn config_changed(config: PreviewConfig) {
|
||||
if let Some(cache) = CONTENT_CACHE.get() {
|
||||
let mut cache = cache.lock().unwrap();
|
||||
if cache.config != config {
|
||||
|
|
@ -941,8 +936,11 @@ fn get_path_from_cache(path: &Path) -> Option<(common::UrlVersion, String)> {
|
|||
get_url_from_cache(&url)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LoadBehavior {
|
||||
/// We reload the preview, most likely because a file has changed
|
||||
Reload,
|
||||
/// We load the preview because the user asked for it. The UI should become visible if it wasn't already
|
||||
Load,
|
||||
}
|
||||
|
||||
|
|
@ -950,13 +948,14 @@ pub fn load_preview(preview_component: PreviewComponent, behavior: LoadBehavior)
|
|||
{
|
||||
let mut cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
match behavior {
|
||||
LoadBehavior::Reload => { /* do nothing */ }
|
||||
LoadBehavior::Reload => {
|
||||
if !cache.ui_is_visible {
|
||||
return;
|
||||
}
|
||||
}
|
||||
LoadBehavior::Load => cache.push_component(preview_component),
|
||||
}
|
||||
|
||||
if !cache.ui_is_visible {
|
||||
return;
|
||||
}
|
||||
match cache.loading_state {
|
||||
PreviewFutureState::Pending => (),
|
||||
PreviewFutureState::PreLoading => return,
|
||||
|
|
@ -969,7 +968,7 @@ pub fn load_preview(preview_component: PreviewComponent, behavior: LoadBehavior)
|
|||
cache.loading_state = PreviewFutureState::PreLoading;
|
||||
};
|
||||
|
||||
run_in_ui_thread(move || async move {
|
||||
let result = run_in_ui_thread(move || async move {
|
||||
let (selected, notify_editor) = PREVIEW_STATE.with(|preview_state| {
|
||||
let mut preview_state = preview_state.borrow_mut();
|
||||
let notify_editor = preview_state.notify_editor_about_selection_after_update;
|
||||
|
|
@ -984,7 +983,7 @@ pub fn load_preview(preview_component: PreviewComponent, behavior: LoadBehavior)
|
|||
cache.clear_style_of_component();
|
||||
|
||||
assert_eq!(cache.loading_state, PreviewFutureState::PreLoading);
|
||||
if !cache.ui_is_visible {
|
||||
if !cache.ui_is_visible && behavior != LoadBehavior::Load {
|
||||
cache.loading_state = PreviewFutureState::Pending;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1013,7 +1012,15 @@ pub fn load_preview(preview_component: PreviewComponent, behavior: LoadBehavior)
|
|||
}
|
||||
});
|
||||
|
||||
reload_preview_impl(preview_component, style, config).await;
|
||||
match reload_preview_impl(preview_component, style, config).await {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
CONTENT_CACHE.get_or_init(Default::default).lock().unwrap().loading_state =
|
||||
PreviewFutureState::Pending;
|
||||
send_platform_error_notification(&e.to_string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
match cache.loading_state {
|
||||
|
|
@ -1061,6 +1068,12 @@ pub fn load_preview(preview_component: PreviewComponent, behavior: LoadBehavior)
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(e) = result {
|
||||
CONTENT_CACHE.get_or_init(Default::default).lock().unwrap().loading_state =
|
||||
PreviewFutureState::Pending;
|
||||
send_platform_error_notification(&e);
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_source(
|
||||
|
|
@ -1103,7 +1116,11 @@ async fn parse_source(
|
|||
}
|
||||
|
||||
// Must be inside the thread running the slint event loop
|
||||
async fn reload_preview_impl(component: PreviewComponent, style: String, config: PreviewConfig) {
|
||||
async fn reload_preview_impl(
|
||||
component: PreviewComponent,
|
||||
style: String,
|
||||
config: PreviewConfig,
|
||||
) -> Result<(), PlatformError> {
|
||||
start_parsing();
|
||||
|
||||
let path = component.url.to_file_path().unwrap_or(PathBuf::from(&component.url.to_string()));
|
||||
|
|
@ -1125,8 +1142,19 @@ async fn reload_preview_impl(component: PreviewComponent, style: String, config:
|
|||
notify_diagnostics(&diagnostics);
|
||||
|
||||
let success = compiled.is_some();
|
||||
update_preview_area(compiled);
|
||||
update_preview_area(compiled)?;
|
||||
finish_parsing(success);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sends a notification back to the editor when the preview fails to load because of a slint::PlatormError.
|
||||
fn send_platform_error_notification(platform_error_str: &str) {
|
||||
let message = format!("Error displaying the Slint preview window: {platform_error_str}");
|
||||
// Also output the message in the console in case the user missed the notification in the editor
|
||||
eprintln!("{message}");
|
||||
send_message_to_lsp(PreviewToLspMessage::SendShowMessage {
|
||||
message: lsp_types::ShowMessageParams { typ: lsp_types::MessageType::ERROR, message },
|
||||
})
|
||||
}
|
||||
|
||||
/// This sets up the preview area to show the ComponentInstance
|
||||
|
|
@ -1174,7 +1202,7 @@ pub fn highlight(url: Option<Url>, offset: u32) {
|
|||
let selected = selected_element();
|
||||
|
||||
if cache.highlight.as_ref().map_or(true, |(url, _)| cache.dependency.contains(url)) {
|
||||
run_in_ui_thread(move || async move {
|
||||
let _ = run_in_ui_thread(move || async move {
|
||||
let Some(path) = url.and_then(|u| Url::to_file_path(&u).ok()) else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -1184,7 +1212,7 @@ pub fn highlight(url: Option<Url>, offset: u32) {
|
|||
return;
|
||||
}
|
||||
element_selection::select_element_at_source_code_position(path, offset, None, false);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1376,7 +1404,7 @@ fn document_cache_from(preview_state: &PreviewState) -> Option<Rc<common::Docume
|
|||
}
|
||||
|
||||
fn set_show_preview_ui(show_preview_ui: bool) {
|
||||
run_in_ui_thread(move || async move {
|
||||
let _ = run_in_ui_thread(move || async move {
|
||||
PREVIEW_STATE.with(|preview_state| {
|
||||
let preview_state = preview_state.borrow();
|
||||
if let Some(ui) = &preview_state.ui {
|
||||
|
|
@ -1440,14 +1468,14 @@ fn set_diagnostics(diagnostics: &[slint_interpreter::Diagnostic]) {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
/// This runs `set_preview_factory` in the UI thread
|
||||
fn update_preview_area(compiled: Option<ComponentDefinition>) {
|
||||
/// This ensure that the preview window is visible and runs `set_preview_factory`
|
||||
fn update_preview_area(compiled: Option<ComponentDefinition>) -> Result<(), PlatformError> {
|
||||
PREVIEW_STATE.with(move |preview_state| {
|
||||
let mut preview_state = preview_state.borrow_mut();
|
||||
preview_state.workspace_edit_sent = false;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
native::open_ui_impl(&mut preview_state);
|
||||
native::open_ui_impl(&mut preview_state)?;
|
||||
|
||||
let ui = preview_state.ui.as_ref().unwrap();
|
||||
|
||||
|
|
@ -1470,15 +1498,13 @@ fn update_preview_area(compiled: Option<ComponentDefinition>) {
|
|||
reset_selections(ui);
|
||||
}
|
||||
|
||||
ui.show().unwrap();
|
||||
});
|
||||
ui.show()
|
||||
})?;
|
||||
element_selection::reselect_element();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lsp_to_preview_message(
|
||||
message: crate::common::LspToPreviewMessage,
|
||||
#[cfg(not(target_arch = "wasm32"))] sender: &crate::ServerNotifier,
|
||||
) {
|
||||
pub fn lsp_to_preview_message(message: crate::common::LspToPreviewMessage) {
|
||||
use crate::common::LspToPreviewMessage as M;
|
||||
match message {
|
||||
M::SetContents { url, contents } => {
|
||||
|
|
@ -1488,8 +1514,6 @@ pub fn lsp_to_preview_message(
|
|||
config_changed(config);
|
||||
}
|
||||
M::ShowPreview(pc) => {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
native::open_ui(sender);
|
||||
load_preview(pc, LoadBehavior::Load);
|
||||
}
|
||||
M::HighlightFromEditor { url, offset } => {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
// cSpell: ignore condvar
|
||||
|
||||
use super::PreviewState;
|
||||
use crate::common::PreviewToLspMessage;
|
||||
use crate::lsp_ext::Health;
|
||||
use crate::ServerNotifier;
|
||||
use once_cell::sync::Lazy;
|
||||
|
|
@ -11,7 +12,7 @@ use slint_interpreter::ComponentHandle;
|
|||
use std::future::Future;
|
||||
use std::sync::{Condvar, Mutex};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum RequestedGuiEventLoopState {
|
||||
/// The UI event loop hasn't been started yet because no preview has been requested
|
||||
Uninitialized,
|
||||
|
|
@ -22,6 +23,8 @@ enum RequestedGuiEventLoopState {
|
|||
LoopStarted,
|
||||
/// The LSP thread requested the application to be terminated
|
||||
QuitLoop,
|
||||
/// There was an error when initializing the UI thread
|
||||
InitializationError(String),
|
||||
}
|
||||
|
||||
static GUI_EVENT_LOOP_NOTIFIER: Lazy<Condvar> = Lazy::new(Condvar::new);
|
||||
|
|
@ -32,7 +35,7 @@ thread_local! {static CLI_ARGS: std::cell::OnceCell<crate::Cli> = Default::defau
|
|||
|
||||
pub fn run_in_ui_thread<F: Future<Output = ()> + 'static>(
|
||||
create_future: impl Send + FnOnce() -> F + 'static,
|
||||
) {
|
||||
) -> Result<(), String> {
|
||||
// Wake up the main thread to start the event loop, if possible
|
||||
{
|
||||
let mut state_request = GUI_EVENT_LOOP_STATE_REQUEST.lock().unwrap();
|
||||
|
|
@ -44,19 +47,28 @@ pub fn run_in_ui_thread<F: Future<Output = ()> + 'static>(
|
|||
while *state_request == RequestedGuiEventLoopState::StartLoop {
|
||||
state_request = GUI_EVENT_LOOP_NOTIFIER.wait(state_request).unwrap();
|
||||
}
|
||||
|
||||
if let RequestedGuiEventLoopState::InitializationError(err) = &*state_request {
|
||||
return Err(err.clone());
|
||||
}
|
||||
}
|
||||
i_slint_core::api::invoke_from_event_loop(move || {
|
||||
i_slint_core::future::spawn_local(create_future()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This is the main entry for the Slint event loop. It runs on the main thread,
|
||||
/// but only runs the event loop if a preview is requested to avoid potential
|
||||
/// crash so that the LSP works without preview in that case.
|
||||
pub fn start_ui_event_loop(cli_args: crate::Cli) {
|
||||
CLI_ARGS.with(|f| f.set(cli_args).ok());
|
||||
|
||||
{
|
||||
let mut state_requested = GUI_EVENT_LOOP_STATE_REQUEST.lock().unwrap();
|
||||
|
||||
// Wait until we either quit, or the LSP thread request to start the loop
|
||||
while *state_requested == RequestedGuiEventLoopState::Uninitialized {
|
||||
state_requested = GUI_EVENT_LOOP_NOTIFIER.wait(state_requested).unwrap();
|
||||
}
|
||||
|
|
@ -67,7 +79,18 @@ pub fn start_ui_event_loop(cli_args: crate::Cli) {
|
|||
|
||||
if *state_requested == RequestedGuiEventLoopState::StartLoop {
|
||||
// make sure the backend is initialized
|
||||
i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
|
||||
match i_slint_backend_selector::with_platform(|_| Ok(())) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
*state_requested =
|
||||
RequestedGuiEventLoopState::InitializationError(err.to_string());
|
||||
GUI_EVENT_LOOP_NOTIFIER.notify_one();
|
||||
while *state_requested != RequestedGuiEventLoopState::QuitLoop {
|
||||
state_requested = GUI_EVENT_LOOP_NOTIFIER.wait(state_requested).unwrap();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
// Send an event so that once the loop is started, we notify the LSP thread that it can send more events
|
||||
i_slint_core::api::invoke_from_event_loop(|| {
|
||||
let mut state_request = GUI_EVENT_LOOP_STATE_REQUEST.lock().unwrap();
|
||||
|
|
@ -96,49 +119,11 @@ pub fn quit_ui_event_loop() {
|
|||
|
||||
let _ = i_slint_core::api::quit_event_loop();
|
||||
|
||||
// Make sure then sender channel gets dropped.
|
||||
if let Some(sender) = SERVER_NOTIFIER.get() {
|
||||
let mut sender = sender.lock().unwrap();
|
||||
*sender = None;
|
||||
};
|
||||
// Make sure then sender channel gets dropped, otherwise the lsp thread will never quit
|
||||
*SERVER_NOTIFIER.lock().unwrap() = None
|
||||
}
|
||||
|
||||
pub fn open_ui(sender: &ServerNotifier) {
|
||||
// Wake up the main thread to start the event loop, if possible
|
||||
{
|
||||
let mut state_request = GUI_EVENT_LOOP_STATE_REQUEST.lock().unwrap();
|
||||
if *state_request == RequestedGuiEventLoopState::Uninitialized {
|
||||
*state_request = RequestedGuiEventLoopState::StartLoop;
|
||||
GUI_EVENT_LOOP_NOTIFIER.notify_one();
|
||||
}
|
||||
// We don't want to call post_event before the loop is properly initialized
|
||||
while *state_request == RequestedGuiEventLoopState::StartLoop {
|
||||
state_request = GUI_EVENT_LOOP_NOTIFIER.wait(state_request).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
if cache.ui_is_visible {
|
||||
return; // UI is already up!
|
||||
}
|
||||
cache.ui_is_visible = true;
|
||||
|
||||
let mut s = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap();
|
||||
*s = Some(sender.clone());
|
||||
};
|
||||
|
||||
i_slint_core::api::invoke_from_event_loop(move || {
|
||||
super::PREVIEW_STATE.with(|preview_state| {
|
||||
let mut preview_state = preview_state.borrow_mut();
|
||||
|
||||
open_ui_impl(&mut preview_state);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(super) fn open_ui_impl(preview_state: &mut PreviewState) {
|
||||
pub(super) fn open_ui_impl(preview_state: &mut PreviewState) -> Result<(), slint::PlatformError> {
|
||||
let (default_style, show_preview_ui, fullscreen) = {
|
||||
let cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
let style = cache.config.style.clone();
|
||||
|
|
@ -161,21 +146,23 @@ pub(super) fn open_ui_impl(preview_state: &mut PreviewState) {
|
|||
.map(|s| !s.is_empty() && s != "0")
|
||||
.unwrap_or(false);
|
||||
|
||||
let ui = preview_state
|
||||
.ui
|
||||
.get_or_insert_with(|| super::ui::create_ui(default_style, experimental).unwrap());
|
||||
let ui = match preview_state.ui.as_ref() {
|
||||
Some(ui) => ui,
|
||||
None => {
|
||||
let ui = super::ui::create_ui(default_style, experimental)?;
|
||||
preview_state.ui.insert(ui)
|
||||
}
|
||||
};
|
||||
|
||||
let api = ui.global::<crate::preview::ui::Api>();
|
||||
api.set_show_preview_ui(show_preview_ui);
|
||||
ui.window().set_fullscreen(fullscreen);
|
||||
ui.window().on_close_requested(|| {
|
||||
let mut cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||
cache.ui_is_visible = false;
|
||||
|
||||
let mut sender = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap();
|
||||
*sender = None;
|
||||
|
||||
slint::CloseRequestResponse::HideWindow
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close_ui() {
|
||||
|
|
@ -203,13 +190,17 @@ fn close_ui_impl(preview_state: &mut PreviewState) {
|
|||
}
|
||||
}
|
||||
|
||||
static SERVER_NOTIFIER: std::sync::OnceLock<Mutex<Option<ServerNotifier>>> =
|
||||
std::sync::OnceLock::new();
|
||||
static SERVER_NOTIFIER: Mutex<Option<ServerNotifier>> = Mutex::new(None);
|
||||
|
||||
/// Give the UI thread a handle to send message back to the LSP thread
|
||||
pub fn set_server_notifier(sender: ServerNotifier) {
|
||||
*SERVER_NOTIFIER.lock().unwrap() = Some(sender);
|
||||
}
|
||||
|
||||
pub fn notify_diagnostics(diagnostics: &[slint_interpreter::Diagnostic]) -> Option<()> {
|
||||
super::set_diagnostics(diagnostics);
|
||||
|
||||
let Some(sender) = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap().clone() else {
|
||||
let Some(sender) = SERVER_NOTIFIER.lock().unwrap().clone() else {
|
||||
return Some(());
|
||||
};
|
||||
|
||||
|
|
@ -222,7 +213,7 @@ pub fn notify_diagnostics(diagnostics: &[slint_interpreter::Diagnostic]) -> Opti
|
|||
}
|
||||
|
||||
pub fn send_status(message: &str, health: Health) {
|
||||
let Some(sender) = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap().clone() else {
|
||||
let Some(sender) = SERVER_NOTIFIER.lock().unwrap().clone() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -230,7 +221,7 @@ pub fn send_status(message: &str, health: Health) {
|
|||
}
|
||||
|
||||
pub fn ask_editor_to_show_document(file: &str, selection: lsp_types::Range) {
|
||||
let Some(sender) = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap().clone() else {
|
||||
let Some(sender) = SERVER_NOTIFIER.lock().unwrap().clone() else {
|
||||
return;
|
||||
};
|
||||
let Ok(url) = lsp_types::Url::from_file_path(file) else { return };
|
||||
|
|
@ -238,8 +229,8 @@ pub fn ask_editor_to_show_document(file: &str, selection: lsp_types::Range) {
|
|||
slint_interpreter::spawn_local(fut).unwrap(); // Fire and forget.
|
||||
}
|
||||
|
||||
pub fn send_message_to_lsp(message: crate::common::PreviewToLspMessage) {
|
||||
let Some(sender) = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap().clone() else {
|
||||
pub fn send_message_to_lsp(message: PreviewToLspMessage) {
|
||||
let Some(sender) = SERVER_NOTIFIER.lock().unwrap().clone() else {
|
||||
return;
|
||||
};
|
||||
sender.send_message_to_lsp(message);
|
||||
|
|
|
|||
|
|
@ -179,8 +179,9 @@ fn invoke_from_event_loop_wrapped_in_promise(
|
|||
|
||||
pub fn run_in_ui_thread<F: Future<Output = ()> + 'static>(
|
||||
create_future: impl Send + FnOnce() -> F + 'static,
|
||||
) {
|
||||
i_slint_core::future::spawn_local(create_future()).unwrap();
|
||||
) -> Result<(), String> {
|
||||
i_slint_core::future::spawn_local(create_future()).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resource_url_mapper(
|
||||
|
|
|
|||
|
|
@ -302,6 +302,12 @@ impl SlintServer {
|
|||
M::SendWorkspaceEdit { label, edit } => {
|
||||
send_workspace_edit(self.ctx.server_notifier.clone(), label, Ok(edit));
|
||||
}
|
||||
M::SendShowMessage { message } => {
|
||||
let _ = self
|
||||
.ctx
|
||||
.server_notifier
|
||||
.send_notification::<lsp_types::notification::ShowMessage>(message);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue