Skip to content

live-preview: Turn the live preview into a separate process #8836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

hunger
Copy link
Member

@hunger hunger commented Jul 2, 2025

Todo:

  • Checkable Menu items
  • Conditional MenuBar
  • then the preview crash, it is not reported to the crash reporter
  • Clicking on "show preview" reset the style to native
  • Handle VSCode closing gracefully (currently the LSP locks)
  • Close the preview when the LSP dies

I removed the change again that changes the MUDA menu on the mac to a Slint menu bar.

@hunger hunger force-pushed the tobias/live-preview-exe branch from 3f02da3 to 114a5ab Compare July 4, 2025 11:35
@hunger
Copy link
Member Author

hunger commented Jul 4, 2025

It is slowly coming back together:

Screencast.From.2025-07-04.13-20-38.mp4

Still todo: The WASM side of the story.

@hunger hunger force-pushed the tobias/live-preview-exe branch 3 times, most recently from 9292b55 to 828b154 Compare July 7, 2025 09:22
@hunger hunger marked this pull request as ready for review July 7, 2025 09:23
@hunger
Copy link
Member Author

hunger commented Jul 7, 2025

This PR supports the WASM-based LSP together with the WASM-based preview and the native LSP together with the native preview. It does not support native LSP with WASM preview.

I doubt anyone is using the WASM preview if not needed due to running in the web -- it is noticeably slower. So I would prefer to just add a PR that just removes this mixed mode entirely over adding a commit that unbreaks mixed mode.

@hunger hunger changed the title WIP: live-preview: Turn the live preview into a separate process live-preview: Turn the live preview into a separate process Jul 7, 2025
@hunger hunger force-pushed the tobias/live-preview-exe branch 4 times, most recently from 0a174f8 to c365fb0 Compare July 7, 2025 12:56
@hunger
Copy link
Member Author

hunger commented Jul 7, 2025

The Mac-specific code also needs adaptation: The "Quit hides the UI" hack is no longer needed, the rest might be able to exist in a normal Slint-based Menu bar.

@hunger hunger force-pushed the tobias/live-preview-exe branch from c365fb0 to ddf7285 Compare July 7, 2025 13:15
@tronical
Copy link
Member

tronical commented Jul 7, 2025

The "Quit hides the UI" hack is no longer needed

Ah great, so if I quit it, the LSP will automatically restart it the next time I choose "Show Preview"?

@hunger
Copy link
Member Author

hunger commented Jul 7, 2025

@tronical: That is the idea, yes.

I did remove some Mac-specific code -- to make the PR compile. I am not sure I am doing the right thing though.

Copy link
Member

@ogoffart ogoffart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Just a bit of polishing to do, especially with regards to error reporting.

[...] It does not support native LSP with WASM preview.

Why not?

I doubt anyone is using the WASM preview if not needed due to running in the web

I sometimes do, and other people use the "provided by editor" setting.

Also, this is required to work on code space or everywhere the LSP is running remote.

The Mac-specific code also needs adaptation: The "Quit hides the UI" hack is no longer needed, the rest might be able to exist in a normal Slint-based Menu bar.

@tronical will have to comment on that.

@hunger
Copy link
Member Author

hunger commented Jul 7, 2025

I noticed that the apple specific code is not called anymore, so I commented it out for the moment -- just to see whether the CI goes green :-)

I need to reenable it -- maybe as a normal Slint Menu? We probably want to hide that in Slintpad though, so that needs to be configurable.

@hunger hunger force-pushed the tobias/live-preview-exe branch from ddf7285 to c01ca76 Compare July 7, 2025 13:49
@hunger
Copy link
Member Author

hunger commented Jul 7, 2025

The latest version mostly ignored @ogoffart's comments... Sorry.

But it has two new commits:

  • Replace the Mac-specific menu with a generic Slint menu. I am not really happy with this one: First off, the "Always on top" does not work in wayland and secondly the menubar wastes vertical space. Unfortunately I can not conditionally have the menu bar -- which will also be a problem for Slintpad.
  • Enable switching between different kinds of previews again. Probably over-engineered that one a bit.

Up next: Fix @ogoffart's comments.

@hunger hunger force-pushed the tobias/live-preview-exe branch from ec82cf6 to 8fbeb63 Compare July 7, 2025 17:25
@hunger
Copy link
Member Author

hunger commented Jul 8, 2025

I think this is all :-)

What shall we do about the menu though?

I have now unconditionally added a menu that has "Reload" and "Always on top" -- like the Mac had. I assume the Mac will add in its standard menu items?

I am not happy with that approach though: For starters "Always on top" does not work for me on wayland, so I'd love to hide that. Then the menu wastes vertical screen space (not an issue ion the mac) and will also look strange in slintpad.

Any chance to make the menu conditional in slint? So that I can show/hide it programmatically?

Or should I remove it entirely and hope for Simon to create a new menu from Rust code using Muda? I can port the old muda-based menu into something that might work, but I have no mac to fix it on.

@hunger hunger force-pushed the tobias/live-preview-exe branch from 06ac412 to 236162e Compare July 8, 2025 10:52
ogoffart
ogoffart previously approved these changes Jul 8, 2025
Copy link
Member

@ogoffart ogoffart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it and it works well, almost transparently, we don't see there is any other process. Good job!

A few bug i noticed while trying:

  • then the preview crash, it is not reported to the crash reporter
  • Clicking on "show preview" reset the style to native
  • When lsp process crashes, the live-preview process doesn't quit.

let communication_handle = std::thread::spawn(move || -> Result<(), String> {
let reader = std::io::BufReader::new(from_child);
for line in reader.lines() {
let line = line.map_err(|e| e.to_string())?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still like to see error reporting.
I've just tried it: When the preview crashes, nothing happens (just that the preview stderr is piped to the lsp stderr which is is shown in the output tab.

But there should be a telemetry or error event sent back to the vscode extension so that we can send the panic message to our crash reporter.

@ogoffart ogoffart dismissed their stale review July 8, 2025 11:00

(i didn't mean to approve it already, see previous message, sorry about that)

@ogoffart
Copy link
Member

ogoffart commented Jul 8, 2025

What shall we do about the menu though?

@tronical will have to chime in about that.

I have now unconditionally added a menu that has "Reload" and "Always on top" -- like the Mac had. I assume the Mac will add in its standard menu items?

I think that's cool, because we will probably end up adding more stuff in that menu, don't we?

Or should I remove it entirely and hope for Simon to create a new menu from Rust code using Muda?

That's the other option.

@tronical
Copy link
Member

tronical commented Jul 8, 2025

I tried the code in the PR and the behaviour of "Quit" looks correct to me (window disappears, no error message).

I see two issues:

  • The always on top item should be checked when the option is selected, and it should be unchecked when not.
  • When the preview launches, it shows a terminal icon in the dock - instead of the Slint logo.

Or should I remove it entirely and hope for Simon to create a new menu from Rust code using Muda?

I advise against putting hope into me ;-). What's the motivation of creating a new menu?

@hunger
Copy link
Member Author

hunger commented Jul 8, 2025

@tronical: I do not want that bar in Slintpad. It is also pretty useless on Linux: The Always on top does not work and the reload is right there as a button anyway... and there is nothing else in there.

But with slint's MenuBar you either have a menu bar or you do not. You apparently can not have it conditionally (e.g. only on Mac) or hide it away.

@hunger
Copy link
Member Author

hunger commented Jul 8, 2025

@ogoffart: That used to be the case with the version from yesterday, but with todays I specifically tested killing the LSP (kill -9, so no chance to clean up) and had the Preview close as expected.

@ogoffart
Copy link
Member

ogoffart commented Jul 8, 2025

Conditional MenuBar shouldn't be too hard: #8282 (comment)
But maybe for this patch then we could just go back to muda on macOs ?
Or maybe no menu at all since the issue it tried to work around is (i think) no longer existing with a different process. (But i'm not sure about that one. Mac expert needs to tell)

@tronical
Copy link
Member

tronical commented Jul 8, 2025

Or maybe no menu at all since the issue it tried to work around is (i think) no longer existing with a different process. (But i'm not sure about that one. Mac expert needs to tell)

I tried the PR. Without our own menu bar we get the winit menu bar and "Quit" works as expected. However, we loose the Window -> Keep On Top feature. That's a regression.

@ogoffart
Copy link
Member

ogoffart commented Jul 8, 2025

but with todays I specifically tested killing the LSP (kill -9, so no chance to clean up) and had the Preview close as expected.

I confirm that then the lsp crashes, the preview also closes now. 👍

However, when killing vscode, both process are kept open.
The parent slint-lsp is struck in

Thread 3 (Thread 0x7db6403ff6c0 (LWP 602046) "LspServerWriter"):
[...]
#4  std::thread::park () at library/std/src/thread/mod.rs:1083
#5  0x00005f734c5d21f7 in crossbeam_channel::context::Context::wait_until (self=0x7db6403fc828, deadline=...) 
#6  0x00005f734c5d6290 in crossbeam_channel::flavors::zero::{impl#3}::recv::{closure#1}<lsp_server::msg::Message> (cx=0x7db6403fc828) 
[...]

Thread 2 (Thread 0x7db63e6ff6c0 (LWP 604548) "slint-lsp"):
[...]
#4  0x00005f734e21fbc4 in std::sys::pal::unix::fd::FileDesc::read_buf ()
#5  std::sys::pal::unix::pipe::AnonPipe::read_buf (
#6  std::process::{impl#16}::read_buf ()
#7  0x00005f734b46747b in std::io::impls::{impl#0}::read_buf<std::process::ChildStdout> (self=0x7db63e6fc4d8, cursor=...)
#8  0x00005f734ba423c2 in std::io::buffered::bufreader::buffer::Buffer::fill_buf<&mut std::process::ChildStdout> (self=0x7db63e6fcb98, reader=0x7db63e6fcbc0) 
#9  0x00005f734b495cbd in std::io::buffered::bufreader::{impl#6}::fill_buf<std::process::ChildStdout> (self=0x7db63e6fcb98) 
#10 0x00005f734b7c4d13 in std::io::read_until<std::io::buffered::bufreader::BufReader<std::process::ChildStdout>> (r=0x7db63e6fcb98, delim=10, buf=0x7db63e6fc938)
#11 0x00005f734b7c58bb in std::io::BufRead::read_line::{closure#0}<std::io::buffered::bufreader::BufReader<std::process::ChildStdout>> (b=0x7db63e6fc938)
#12 0x00005f734b7c54d9 in std::io::append_to_string<std::io::BufRead::read_line::{closure_env#0}<std::io::buffered::bufreader::BufReader<std::process::ChildStdout>>> (buf=0x7db63e6fc938, f=...) 
#13 0x00005f734b49555e in std::io::BufRead::read_line<std::io::buffered::bufreader::BufReader<std::process::ChildStdout>> (self=0x7db63e6fcb98, buf=0x7db63e6fc938)
#14 0x00005f734b7c5e9e in std::io::{impl#27}::next<std::io::buffered::bufreader::BufReader<std::process::ChildStdout>> (self=0x7db63e6fcb98) 
#15 0x00005f734b4d2c94 in slint_lsp::preview::connector::native::{impl#0}::start_preview::{closure#0} () at tools/lsp/preview/connector/native.rs:57
#16 0x00005f734b436771 in std::sys::backtrace::__rust_begin_short_backtrace<slint_lsp::preview::connector::native::{impl#0}::start_preview::{closure_env#0}, core::result::Result<(), alloc::string::String>> (f=...) 


Thread 1 (Thread 0x7db644428140 (LWP 602044) "slint-lsp"):
[...]
#6  0x00005f734e224e61 in std::sys::pal::unix::thread::Thread::join () 
#7  0x00005f734b4c8da5 in std::thread::JoinInner<core::result::Result<(), alloc::string::String>>::join<core::result::Result<(), alloc::string::String>> 
#8  0x00005f734b4c8f60 in std::thread::JoinHandle<core::result::Result<(), alloc::string::String>>::join<core::result::Result<(), alloc::string::String>> (self=...)
#9  0x00005f734b766d1c in slint_lsp::preview::connector::native::{impl#1}::drop (self=0x7db640809000) at tools/lsp/preview/connector/native.rs:77
#10 0x00005f734b6f5953 in core::ptr::drop_in_place<slint_lsp::preview::connector::native::ChildProcessLspToPreview> () 
#11 0x00005f734b6f5d04 in core::ptr::drop_in_place<alloc::boxed::Box<dyn slint_lsp::common::LspToPreview, alloc::alloc::Global>> () at
[...]
#21 0x00005f734b6f524a in core::ptr::drop_in_place<slint_lsp::preview::connector::native::SwitchableLspToPreview> () at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:523
#22 0x00005f734b6eee6d in core::ptr::drop_in_place<dyn slint_lsp::common::LspToPreview> () at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:523
#23 0x00005f734bde9e82 in alloc::rc::Rc<dyn slint_lsp::common::LspToPreview, alloc::alloc::Global>::drop_slow<dyn slint_lsp::common::LspToPreview, alloc::alloc::Global> (self=0x7db6408ca300) at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/rc.rs:388
#24 0x00005f734b704d8e in alloc::rc::{impl#32}::drop<dyn slint_lsp::common::LspToPreview, alloc::alloc::Global> (self=0x7db6408ca300) at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/rc.rs:2312
#25 0x00005f734b6f4b1a in core::ptr::drop_in_place<alloc::rc::Rc<dyn slint_lsp::common::LspToPreview, alloc::alloc::Global>> () at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:523
#26 0x00005f734b6e1966 in core::ptr::drop_in_place<slint_lsp::language::Context> () at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:523
#27 0x00005f734bde9bce in alloc::rc::Rc<slint_lsp::language::Context, alloc::alloc::Global>::drop_slow<slint_lsp::language::Context, alloc::alloc::Global> (self=0x7ffd74ee7b38) at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/rc.rs:388
#28 0x00005f734b7041dc in alloc::rc::{impl#32}::drop<slint_lsp::language::Context, alloc::alloc::Global> (self=0x7ffd74ee7b38) at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/rc.rs:2312
#29 0x00005f734b6f184a in core::ptr::drop_in_place<alloc::rc::Rc<slint_lsp::language::Context, alloc::alloc::Global>> () at /home/olivier/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:523
#30 0x00005f734b4cfb05 in slint_lsp::main_loop (connection=..., init_param=..., cli_args=...) at tools/lsp/main.rs:441
#31 0x00005f734b4ce6bb in slint_lsp::run_lsp_server (args=...) at tools/lsp/main.rs:289
#32 0x00005f734b4cdee5 in slint_lsp::main () at tools/lsp/main.rs:270

Looks like thread 1 is waiting on thread 2 which is blocked in trying to read.

Edit: Thread 1 is blocked waiting on thread 2 which is waiting on the UI process. The UI process is still running fine (and the window is still visible). But closing the window do stop the deadlock.
We should kill our child process or at least send a command to shutdown, before waiting on it.

@hunger hunger force-pushed the tobias/live-preview-exe branch 3 times, most recently from f664b10 to 0d3adba Compare July 23, 2025 15:33
@hunger
Copy link
Member Author

hunger commented Jul 23, 2025

All but the menu items are now fixed.

hunger added 13 commits July 24, 2025 13:29
... and into preview/connector.

This is just a intermediary step to separate them even more strongly from
each other.
The UI is always visible while the live preview runs.
... the wasm preview still does not work though.
Probably a bit over-engineered, but this works for me.
Make the extension set SLINT_LSP_PANIC_LOG_DIR (instead of setting a file).
Have the Lsp/live preview create panic logs in that folder as panics happen.
Make the extension watch that folder and upload any file it sees getting created there
Delete the file after upload
Simplify style selection, now that we are "always up": All we need to do
is change the style when the configuration changes. That is a part
of the initial state request we send when the preview starts up, so we set
the style properly and then we do not need to do anything anymore till
somebody configures a new style.
@hunger hunger force-pushed the tobias/live-preview-exe branch from 1f56c60 to cb3c225 Compare July 24, 2025 13:29
@hunger
Copy link
Member Author

hunger commented Jul 24, 2025

@tronical: The one thing left to do is to fix up the menu on mac. Would you please do the honors?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants