lsp: Send contents to preview for implicitly loaded slint files

This fixes the no preview in slintpad issue when retrieving the contents
of files is slow (e.g. when loaded from the web).

Fixes: #3855
This commit is contained in:
Tobias Hunger 2023-11-08 14:00:33 +01:00 committed by Tobias Hunger
parent aeb512686e
commit 0774d01a59
5 changed files with 73 additions and 59 deletions

View file

@ -123,7 +123,7 @@ pub struct Context {
pub document_cache: RefCell<DocumentCache>, pub document_cache: RefCell<DocumentCache>,
pub server_notifier: crate::ServerNotifier, pub server_notifier: crate::ServerNotifier,
pub init_param: InitializeParams, pub init_param: InitializeParams,
pub preview: Box<dyn PreviewApi>, pub preview: Rc<dyn PreviewApi>,
} }
#[derive(Default)] #[derive(Default)]

View file

@ -311,6 +311,24 @@ pub fn run_lsp_server() -> Result<IoThreads> {
} }
fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()> { fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()> {
let mut rh = RequestHandler::default();
register_request_handlers(&mut rh);
let request_queue = OutgoingRequestQueue::default();
let server_notifier = ServerNotifier(connection.sender.clone(), request_queue.clone());
let preview = Rc::new(Previewer {
server_notifier: server_notifier.clone(),
#[cfg(all(not(feature = "preview-builtin"), not(feature = "preview-external")))]
use_external_previewer: RefCell::new(false), // No preview, pick any.
#[cfg(all(not(feature = "preview-builtin"), feature = "preview-external"))]
use_external_previewer: RefCell::new(true), // external only
#[cfg(all(feature = "preview-builtin", not(feature = "preview-external")))]
use_external_previewer: RefCell::new(false), // internal only
#[cfg(all(feature = "preview-builtin", feature = "preview-external"))]
use_external_previewer: RefCell::new(false), // prefer internal
to_show: RefCell::new(None),
});
let mut compiler_config = let mut compiler_config =
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter); CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
@ -318,28 +336,23 @@ fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()>
compiler_config.style = compiler_config.style =
Some(if cli_args.style.is_empty() { "fluent".into() } else { cli_args.style }); Some(if cli_args.style.is_empty() { "fluent".into() } else { cli_args.style });
compiler_config.include_paths = cli_args.include_paths; compiler_config.include_paths = cli_args.include_paths;
let preview_notifier = preview.clone();
compiler_config.open_import_fallback = Some(Rc::new(move |path| {
let preview_notifier = preview_notifier.clone();
Box::pin(async move {
let contents = std::fs::read_to_string(&path);
if let Ok(contents) = &contents {
preview_notifier.set_contents(&PathBuf::from(path), contents);
}
Some(contents)
})
}));
let mut rh = RequestHandler::default();
register_request_handlers(&mut rh);
let request_queue = OutgoingRequestQueue::default();
let server_notifier = ServerNotifier(connection.sender.clone(), request_queue.clone());
let ctx = Rc::new(Context { let ctx = Rc::new(Context {
document_cache: RefCell::new(DocumentCache::new(compiler_config)), document_cache: RefCell::new(DocumentCache::new(compiler_config)),
server_notifier: server_notifier.clone(), server_notifier: server_notifier,
init_param, init_param,
preview: Box::new(Previewer { preview,
server_notifier,
#[cfg(all(not(feature = "preview-builtin"), not(feature = "preview-external")))]
use_external_previewer: RefCell::new(false), // No preview, pick any.
#[cfg(all(not(feature = "preview-builtin"), feature = "preview-external"))]
use_external_previewer: RefCell::new(true), // external only
#[cfg(all(feature = "preview-builtin", not(feature = "preview-external")))]
use_external_previewer: RefCell::new(false), // internal only
#[cfg(all(feature = "preview-builtin", feature = "preview-external"))]
use_external_previewer: RefCell::new(false), // prefer internal
to_show: RefCell::new(None),
}),
}); });
let mut futures = Vec::<Pin<Box<dyn Future<Output = Result<()>>>>>::new(); let mut futures = Vec::<Pin<Box<dyn Future<Output = Result<()>>>>>::new();

View file

@ -65,7 +65,8 @@ pub fn set_contents(path: &Path, content: String) {
let current = cache.current.clone(); let current = cache.current.clone();
let ui_is_visible = cache.ui_is_visible; let ui_is_visible = cache.ui_is_visible;
drop(cache); drop(cache);
if ui_is_visible {
if ui_is_visible && !current.path.as_os_str().is_empty() {
load_preview(current); load_preview(current);
} }
} }
@ -79,11 +80,14 @@ fn set_design_mode(enable: bool) {
} }
fn change_style() { fn change_style() {
let component = { let cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
let cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap(); let ui_is_visible = cache.ui_is_visible;
cache.current.clone() let current = cache.current.clone();
}; drop(cache);
load_preview(component);
if ui_is_visible && !current.path.as_os_str().is_empty() {
load_preview(current);
}
} }
pub fn start_parsing() { pub fn start_parsing() {
@ -119,7 +123,8 @@ pub fn config_changed(
let current = cache.current.clone(); let current = cache.current.clone();
let ui_is_visible = cache.ui_is_visible; let ui_is_visible = cache.ui_is_visible;
drop(cache); drop(cache);
if ui_is_visible {
if ui_is_visible && !current.path.as_os_str().is_empty() {
load_preview(current); load_preview(current);
} }
} }

View file

@ -65,6 +65,10 @@ impl PreviewApi for Previewer {
} }
fn load_preview(&self, component: common::PreviewComponent) { fn load_preview(&self, component: common::PreviewComponent) {
if component.path.as_os_str().is_empty() {
return;
}
self.to_show.replace(Some(component.clone())); self.to_show.replace(Some(component.clone()));
#[cfg(feature = "preview-external")] #[cfg(feature = "preview-external")]
@ -260,29 +264,38 @@ pub fn create(
) -> JsResult<SlintServer> { ) -> JsResult<SlintServer> {
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
let send_request = Function::from(send_request.clone());
let server_notifier = ServerNotifier { send_notification, send_request };
let preview = Rc::new(Previewer {
server_notifier: server_notifier.clone(),
to_show: Default::default(),
});
let init_param = serde_wasm_bindgen::from_value(init_param)?; let init_param = serde_wasm_bindgen::from_value(init_param)?;
let mut compiler_config = let mut compiler_config =
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter); CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
let preview_notifier = preview.clone();
compiler_config.open_import_fallback = Some(Rc::new(move |path| { compiler_config.open_import_fallback = Some(Rc::new(move |path| {
let load_file = Function::from(load_file.clone()); let load_file = Function::from(load_file.clone());
Box::pin(async move { Some(self::load_file(path, &load_file).await) }) let preview_notifier = preview_notifier.clone();
Box::pin(async move {
let contents = self::load_file(path.clone(), &load_file).await;
if let Ok(contents) = &contents {
preview_notifier.set_contents(&PathBuf::from(path), contents);
}
Some(contents)
})
})); }));
let document_cache = RefCell::new(DocumentCache::new(compiler_config)); let document_cache = RefCell::new(DocumentCache::new(compiler_config));
let send_request = Function::from(send_request.clone());
let reentry_guard = Rc::new(RefCell::new(ReentryGuard::default())); let reentry_guard = Rc::new(RefCell::new(ReentryGuard::default()));
let mut rh = RequestHandler::default(); let mut rh = RequestHandler::default();
language::register_request_handlers(&mut rh); language::register_request_handlers(&mut rh);
let server_notifier = ServerNotifier { send_notification, send_request };
Ok(SlintServer { Ok(SlintServer {
ctx: Rc::new(Context { ctx: Rc::new(Context { document_cache, init_param, server_notifier, preview }),
document_cache,
init_param,
server_notifier: server_notifier.clone(),
preview: Box::new(Previewer { server_notifier, to_show: Default::default() }),
}),
reentry_guard, reentry_guard,
rh: Rc::new(rh), rh: Rc::new(rh),
}) })

View file

@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
// cSpell: ignore edcore lumino mimetypes printerdemo // cSpell: ignore codingame lumino mimetypes printerdemo
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
@ -416,6 +416,10 @@ class EditorPaneWidget extends Widget {
if (monaco.editor.getModels().length === 1) { if (monaco.editor.getModels().length === 1) {
this.#main_uri = uri; this.#main_uri = uri;
this.set_model(uri); this.set_model(uri);
this.language_client?.sendRequest("workspace/executeCommand", {
command: "slint/showPreview",
arguments: [this.#main_uri?.toString() ?? "", ""],
});
} }
} }
@ -797,7 +801,6 @@ export class EditorWidget extends Widget {
} }
async set_demo(location: string) { async set_demo(location: string) {
let result_uri: monaco.Uri | null = null;
if (location) { if (location) {
const default_tag = "XXXX_DEFAULT_TAG_XXXX"; const default_tag = "XXXX_DEFAULT_TAG_XXXX";
let tag = default_tag.startsWith("XXXX_DEFAULT_TAG_") let tag = default_tag.startsWith("XXXX_DEFAULT_TAG_")
@ -813,32 +816,12 @@ export class EditorWidget extends Widget {
tag = "v" + found[1]; tag = "v" + found[1];
} }
} }
result_uri = await this.project_from_url( await this.project_from_url(
`https://raw.githubusercontent.com/slint-ui/slint/${tag}/${location}`, `https://raw.githubusercontent.com/slint-ui/slint/${tag}/${location}`,
); );
} else { } else {
this.#editor.clear_models(); this.#editor.clear_models();
const model = await createModel( await createModel(this.#editor.internal_uuid, hello_world);
this.#editor.internal_uuid,
hello_world,
);
if (model) {
result_uri = model.uri;
}
}
if (result_uri) {
setTimeout(
() =>
this.language_client?.sendRequest(
"workspace/executeCommand",
{
command: "slint/showPreview",
arguments: [result_uri?.toString() ?? "", ""],
},
),
1000,
);
} }
} }