mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-22 08:12:48 +00:00
lsp: Add option to show/hide preview ui
... and use that option in VSCode configuration.
This commit is contained in:
parent
b19cbba7ad
commit
548f10be2b
11 changed files with 177 additions and 66 deletions
|
@ -94,6 +94,10 @@
|
||||||
},
|
},
|
||||||
"description": "The command line arguments passed to the Slint LSP server"
|
"description": "The command line arguments passed to the Slint LSP server"
|
||||||
},
|
},
|
||||||
|
"slint.preview.show_ui": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Show the toolbar of the preview"
|
||||||
|
},
|
||||||
"slint.preview.style": {
|
"slint.preview.style": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The default style to be used for the preview (eg: 'fluent', 'material', or 'native')"
|
"description": "The default style to be used for the preview (eg: 'fluent', 'material', or 'native')"
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub trait PreviewApi {
|
||||||
fn load_preview(&self, component: PreviewComponent);
|
fn load_preview(&self, component: PreviewComponent);
|
||||||
fn config_changed(
|
fn config_changed(
|
||||||
&self,
|
&self,
|
||||||
|
show_preview_ui: bool,
|
||||||
style: &str,
|
style: &str,
|
||||||
include_paths: &[PathBuf],
|
include_paths: &[PathBuf],
|
||||||
library_paths: &HashMap<String, PathBuf>,
|
library_paths: &HashMap<String, PathBuf>,
|
||||||
|
@ -27,6 +28,12 @@ pub trait PreviewApi {
|
||||||
|
|
||||||
/// What is the current component to preview?
|
/// What is the current component to preview?
|
||||||
fn current_component(&self) -> Option<PreviewComponent>;
|
fn current_component(&self) -> Option<PreviewComponent>;
|
||||||
|
|
||||||
|
/// Return the currently configured `show_preview_ui` value.
|
||||||
|
///
|
||||||
|
/// This is not ideal, but we can not access the configuration without
|
||||||
|
/// a round trip into the editor.
|
||||||
|
fn show_preview_ui(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Component to preview
|
/// The Component to preview
|
||||||
|
@ -57,6 +64,7 @@ pub enum LspToPreviewMessage {
|
||||||
contents: String,
|
contents: String,
|
||||||
},
|
},
|
||||||
SetConfiguration {
|
SetConfiguration {
|
||||||
|
show_preview_ui: bool,
|
||||||
style: String,
|
style: String,
|
||||||
include_paths: Vec<String>,
|
include_paths: Vec<String>,
|
||||||
library_paths: Vec<(String, String)>,
|
library_paths: Vec<(String, String)>,
|
||||||
|
|
|
@ -90,6 +90,7 @@ pub fn request_state(ctx: &std::rc::Rc<Context>) {
|
||||||
}
|
}
|
||||||
let style = documents.compiler_config.style.clone().unwrap_or_default();
|
let style = documents.compiler_config.style.clone().unwrap_or_default();
|
||||||
ctx.preview.config_changed(
|
ctx.preview.config_changed(
|
||||||
|
ctx.preview.show_preview_ui(),
|
||||||
&style,
|
&style,
|
||||||
&documents.compiler_config.include_paths,
|
&documents.compiler_config.include_paths,
|
||||||
&documents.compiler_config.library_paths,
|
&documents.compiler_config.library_paths,
|
||||||
|
@ -1221,6 +1222,7 @@ pub async fn load_configuration(ctx: &Context) -> Result<()> {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let document_cache = &mut ctx.document_cache.borrow_mut();
|
let document_cache = &mut ctx.document_cache.borrow_mut();
|
||||||
|
let mut show_preview_ui = false;
|
||||||
for v in r {
|
for v in r {
|
||||||
if let Some(o) = v.as_object() {
|
if let Some(o) = v.as_object() {
|
||||||
if let Some(ip) = o.get("includePaths").and_then(|v| v.as_array()) {
|
if let Some(ip) = o.get("includePaths").and_then(|v| v.as_array()) {
|
||||||
|
@ -1244,6 +1246,10 @@ pub async fn load_configuration(ctx: &Context) -> Result<()> {
|
||||||
document_cache.documents.compiler_config.style = Some(style.into());
|
document_cache.documents.compiler_config.style = Some(style.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
show_preview_ui = o
|
||||||
|
.get("preview")
|
||||||
|
.and_then(|v| v.as_object()?.get("show_ui")?.as_bool())
|
||||||
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1254,6 +1260,7 @@ pub async fn load_configuration(ctx: &Context) -> Result<()> {
|
||||||
let cc = &document_cache.documents.compiler_config;
|
let cc = &document_cache.documents.compiler_config;
|
||||||
let empty_string = String::new();
|
let empty_string = String::new();
|
||||||
ctx.preview.config_changed(
|
ctx.preview.config_changed(
|
||||||
|
show_preview_ui,
|
||||||
cc.style.as_ref().unwrap_or(&empty_string),
|
cc.style.as_ref().unwrap_or(&empty_string),
|
||||||
&cc.include_paths,
|
&cc.include_paths,
|
||||||
&cc.library_paths,
|
&cc.library_paths,
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct Previewer {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
server_notifier: ServerNotifier,
|
server_notifier: ServerNotifier,
|
||||||
use_external_previewer: RefCell<bool>,
|
use_external_previewer: RefCell<bool>,
|
||||||
|
show_preview_ui: RefCell<bool>,
|
||||||
to_show: RefCell<Option<common::PreviewComponent>>,
|
to_show: RefCell<Option<common::PreviewComponent>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,15 +104,18 @@ impl PreviewApi for Previewer {
|
||||||
|
|
||||||
fn config_changed(
|
fn config_changed(
|
||||||
&self,
|
&self,
|
||||||
|
_show_preview_ui: bool,
|
||||||
_style: &str,
|
_style: &str,
|
||||||
_include_paths: &[PathBuf],
|
_include_paths: &[PathBuf],
|
||||||
_library_paths: &HashMap<String, PathBuf>,
|
_library_paths: &HashMap<String, PathBuf>,
|
||||||
) {
|
) {
|
||||||
|
*self.show_preview_ui.borrow_mut() = _show_preview_ui;
|
||||||
if *self.use_external_previewer.borrow() {
|
if *self.use_external_previewer.borrow() {
|
||||||
#[cfg(feature = "preview-external")]
|
#[cfg(feature = "preview-external")]
|
||||||
let _ = self.server_notifier.send_notification(
|
let _ = self.server_notifier.send_notification(
|
||||||
"slint/lsp_to_preview".to_string(),
|
"slint/lsp_to_preview".to_string(),
|
||||||
crate::common::LspToPreviewMessage::SetConfiguration {
|
crate::common::LspToPreviewMessage::SetConfiguration {
|
||||||
|
show_preview_ui: _show_preview_ui,
|
||||||
style: _style.to_string(),
|
style: _style.to_string(),
|
||||||
include_paths: _include_paths
|
include_paths: _include_paths
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -125,7 +129,7 @@ impl PreviewApi for Previewer {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "preview-builtin")]
|
#[cfg(feature = "preview-builtin")]
|
||||||
preview::config_changed(_style, _include_paths, _library_paths);
|
preview::config_changed(_show_preview_ui, _style, _include_paths, _library_paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +156,10 @@ impl PreviewApi for Previewer {
|
||||||
fn current_component(&self) -> Option<crate::common::PreviewComponent> {
|
fn current_component(&self) -> Option<crate::common::PreviewComponent> {
|
||||||
self.to_show.borrow().clone()
|
self.to_show.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_preview_ui(&self) -> bool {
|
||||||
|
*self.show_preview_ui.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, clap::Parser)]
|
#[derive(Clone, clap::Parser)]
|
||||||
|
@ -176,6 +184,10 @@ struct Cli {
|
||||||
/// Start the preview in full screen mode
|
/// Start the preview in full screen mode
|
||||||
#[arg(long, action)]
|
#[arg(long, action)]
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
|
|
||||||
|
/// Show the preview UI
|
||||||
|
#[arg(long, default_value = "true", action = clap::ArgAction::Set)]
|
||||||
|
show_preview_ui: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OutgoingRequest {
|
enum OutgoingRequest {
|
||||||
|
@ -265,11 +277,13 @@ fn main() {
|
||||||
std::env::set_var("SLINT_FULLSCREEN", "1");
|
std::env::set_var("SLINT_FULLSCREEN", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let show_preview_ui = args.show_preview_ui;
|
||||||
|
|
||||||
#[cfg(feature = "preview-engine")]
|
#[cfg(feature = "preview-engine")]
|
||||||
{
|
{
|
||||||
let lsp_thread = std::thread::Builder::new()
|
let lsp_thread = std::thread::Builder::new()
|
||||||
.name("LanguageServer".into())
|
.name("LanguageServer".into())
|
||||||
.spawn(|| {
|
.spawn(move || {
|
||||||
/// Make sure we quit the event loop even if we panic
|
/// Make sure we quit the event loop even if we panic
|
||||||
struct QuitEventLoop;
|
struct QuitEventLoop;
|
||||||
impl Drop for QuitEventLoop {
|
impl Drop for QuitEventLoop {
|
||||||
|
@ -279,7 +293,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
let quit_ui_loop = QuitEventLoop;
|
let quit_ui_loop = QuitEventLoop;
|
||||||
|
|
||||||
let threads = match run_lsp_server() {
|
let threads = match run_lsp_server(show_preview_ui) {
|
||||||
Ok(threads) => threads,
|
Ok(threads) => threads,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("Error running LSP server: {}", error);
|
eprintln!("Error running LSP server: {}", error);
|
||||||
|
@ -304,7 +318,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_lsp_server() -> Result<IoThreads> {
|
pub fn run_lsp_server(show_preview_ui: bool) -> Result<IoThreads> {
|
||||||
let (connection, io_threads) = Connection::stdio();
|
let (connection, io_threads) = Connection::stdio();
|
||||||
let (id, params) = connection.initialize_start()?;
|
let (id, params) = connection.initialize_start()?;
|
||||||
|
|
||||||
|
@ -313,12 +327,16 @@ pub fn run_lsp_server() -> Result<IoThreads> {
|
||||||
serde_json::to_value(language::server_initialize_result(&init_param.capabilities))?;
|
serde_json::to_value(language::server_initialize_result(&init_param.capabilities))?;
|
||||||
connection.initialize_finish(id, initialize_result)?;
|
connection.initialize_finish(id, initialize_result)?;
|
||||||
|
|
||||||
main_loop(connection, init_param)?;
|
main_loop(connection, init_param, show_preview_ui)?;
|
||||||
|
|
||||||
Ok(io_threads)
|
Ok(io_threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()> {
|
fn main_loop(
|
||||||
|
connection: Connection,
|
||||||
|
init_param: InitializeParams,
|
||||||
|
show_preview_ui: bool,
|
||||||
|
) -> Result<()> {
|
||||||
let mut rh = RequestHandler::default();
|
let mut rh = RequestHandler::default();
|
||||||
register_request_handlers(&mut rh);
|
register_request_handlers(&mut rh);
|
||||||
|
|
||||||
|
@ -336,6 +354,7 @@ fn main_loop(connection: Connection, init_param: InitializeParams) -> Result<()>
|
||||||
#[cfg(all(feature = "preview-builtin", feature = "preview-external"))]
|
#[cfg(all(feature = "preview-builtin", feature = "preview-external"))]
|
||||||
use_external_previewer: RefCell::new(false), // prefer internal
|
use_external_previewer: RefCell::new(false), // prefer internal
|
||||||
to_show: RefCell::new(None),
|
to_show: RefCell::new(None),
|
||||||
|
show_preview_ui: RefCell::new(show_preview_ui),
|
||||||
});
|
});
|
||||||
let mut compiler_config =
|
let mut compiler_config =
|
||||||
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
|
CompilerConfiguration::new(i_slint_compiler::generator::OutputFormat::Interpreter);
|
||||||
|
|
|
@ -49,6 +49,8 @@ struct ContentCache {
|
||||||
ui_is_visible: bool,
|
ui_is_visible: bool,
|
||||||
design_mode: bool,
|
design_mode: bool,
|
||||||
default_style: String,
|
default_style: String,
|
||||||
|
// Duplicate this information in case the UI is not up yet.
|
||||||
|
show_preview_ui: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
static CONTENT_CACHE: std::sync::OnceLock<Mutex<ContentCache>> = std::sync::OnceLock::new();
|
static CONTENT_CACHE: std::sync::OnceLock<Mutex<ContentCache>> = std::sync::OnceLock::new();
|
||||||
|
@ -106,6 +108,7 @@ pub fn finish_parsing(ok: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config_changed(
|
pub fn config_changed(
|
||||||
|
show_preview_ui: bool,
|
||||||
style: &str,
|
style: &str,
|
||||||
include_paths: &[PathBuf],
|
include_paths: &[PathBuf],
|
||||||
library_paths: &HashMap<String, PathBuf>,
|
library_paths: &HashMap<String, PathBuf>,
|
||||||
|
@ -116,15 +119,20 @@ pub fn config_changed(
|
||||||
if cache.current.style != style
|
if cache.current.style != style
|
||||||
|| cache.current.include_paths != include_paths
|
|| cache.current.include_paths != include_paths
|
||||||
|| cache.current.library_paths != *library_paths
|
|| cache.current.library_paths != *library_paths
|
||||||
|
|| cache.show_preview_ui != show_preview_ui
|
||||||
{
|
{
|
||||||
cache.current.include_paths = include_paths.to_vec();
|
cache.current.include_paths = include_paths.to_vec();
|
||||||
cache.current.library_paths = library_paths.clone();
|
cache.current.library_paths = library_paths.clone();
|
||||||
cache.default_style = style;
|
cache.default_style = style;
|
||||||
|
cache.show_preview_ui = show_preview_ui;
|
||||||
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;
|
||||||
|
let show_preview_ui = cache.show_preview_ui;
|
||||||
|
|
||||||
drop(cache);
|
drop(cache);
|
||||||
|
|
||||||
if ui_is_visible && !current.path.as_os_str().is_empty() {
|
if ui_is_visible && !current.path.as_os_str().is_empty() {
|
||||||
|
set_show_preview_ui(show_preview_ui);
|
||||||
load_preview(current);
|
load_preview(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ pub fn open_ui(sender: &ServerNotifier) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let default_style = {
|
let (default_style, show_preview_ui) = {
|
||||||
let mut cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
let mut cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||||
if cache.ui_is_visible {
|
if cache.ui_is_visible {
|
||||||
return; // UI is already up!
|
return; // UI is already up!
|
||||||
|
@ -132,21 +132,23 @@ pub fn open_ui(sender: &ServerNotifier) {
|
||||||
let mut s = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap();
|
let mut s = SERVER_NOTIFIER.get_or_init(Default::default).lock().unwrap();
|
||||||
*s = Some(sender.clone());
|
*s = Some(sender.clone());
|
||||||
|
|
||||||
cache.default_style.clone()
|
(cache.default_style.clone(), cache.show_preview_ui)
|
||||||
};
|
};
|
||||||
|
|
||||||
i_slint_core::api::invoke_from_event_loop(move || {
|
i_slint_core::api::invoke_from_event_loop(move || {
|
||||||
PREVIEW_STATE.with(|preview_state| {
|
PREVIEW_STATE.with(|preview_state| {
|
||||||
let mut preview_state = preview_state.borrow_mut();
|
let mut preview_state = preview_state.borrow_mut();
|
||||||
open_ui_impl(&mut preview_state, default_style);
|
open_ui_impl(&mut preview_state, default_style, show_preview_ui);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_ui_impl(preview_state: &mut PreviewState, default_style: String) {
|
fn open_ui_impl(preview_state: &mut PreviewState, default_style: String, show_preview_ui: bool) {
|
||||||
// TODO: Handle Error!
|
// TODO: Handle Error!
|
||||||
let ui = preview_state.ui.get_or_insert_with(|| super::ui::create_ui(default_style).unwrap());
|
let ui = preview_state
|
||||||
|
.ui
|
||||||
|
.get_or_insert_with(|| super::ui::create_ui(default_style, show_preview_ui).unwrap());
|
||||||
ui.on_show_document(|url, line, column| {
|
ui.on_show_document(|url, line, column| {
|
||||||
ask_editor_to_show_document(
|
ask_editor_to_show_document(
|
||||||
url.as_str().to_string(),
|
url.as_str().to_string(),
|
||||||
|
@ -218,6 +220,17 @@ pub fn notify_diagnostics(diagnostics: &[slint_interpreter::Diagnostic]) -> Opti
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_show_preview_ui(show_preview_ui: bool) {
|
||||||
|
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 {
|
||||||
|
ui.set_show_preview_ui(show_preview_ui)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_current_style(style: String) {
|
pub fn set_current_style(style: String) {
|
||||||
PREVIEW_STATE.with(move |preview_state| {
|
PREVIEW_STATE.with(move |preview_state| {
|
||||||
let preview_state = preview_state.borrow_mut();
|
let preview_state = preview_state.borrow_mut();
|
||||||
|
@ -312,15 +325,15 @@ pub fn configure_design_mode(enabled: bool) {
|
||||||
|
|
||||||
/// This runs `set_preview_factory` in the UI thread
|
/// This runs `set_preview_factory` in the UI thread
|
||||||
pub fn update_preview_area(compiled: slint_interpreter::ComponentDefinition, design_mode: bool) {
|
pub fn update_preview_area(compiled: slint_interpreter::ComponentDefinition, design_mode: bool) {
|
||||||
let default_style = {
|
let (default_style, show_preview_ui) = {
|
||||||
let cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
let cache = super::CONTENT_CACHE.get_or_init(Default::default).lock().unwrap();
|
||||||
cache.default_style.clone()
|
(cache.default_style.clone(), cache.show_preview_ui)
|
||||||
};
|
};
|
||||||
|
|
||||||
PREVIEW_STATE.with(|preview_state| {
|
PREVIEW_STATE.with(|preview_state| {
|
||||||
let mut preview_state = preview_state.borrow_mut();
|
let mut preview_state = preview_state.borrow_mut();
|
||||||
|
|
||||||
open_ui_impl(&mut preview_state, default_style);
|
open_ui_impl(&mut preview_state, default_style, show_preview_ui);
|
||||||
|
|
||||||
let shared_handle = preview_state.handle.clone();
|
let shared_handle = preview_state.handle.clone();
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,10 @@ use slint_interpreter::{DiagnosticLevel, PlatformError};
|
||||||
|
|
||||||
slint::include_modules!();
|
slint::include_modules!();
|
||||||
|
|
||||||
pub fn create_ui(style: String) -> Result<PreviewUi, PlatformError> {
|
pub fn create_ui(style: String, show_preview_ui: bool) -> Result<PreviewUi, PlatformError> {
|
||||||
let ui = PreviewUi::new()?;
|
let ui = PreviewUi::new()?;
|
||||||
|
|
||||||
if std::env::var("SLINT_FULLSCREEN").is_ok() {
|
ui.set_show_preview_ui(show_preview_ui);
|
||||||
ui.set_hide_toolbar(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// design mode:
|
// design mode:
|
||||||
ui.on_design_mode_changed(super::set_design_mode);
|
ui.on_design_mode_changed(super::set_design_mode);
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl PreviewConnector {
|
||||||
reject_c.take().call1(&JsValue::UNDEFINED,
|
reject_c.take().call1(&JsValue::UNDEFINED,
|
||||||
&JsValue::from("PreviewConnector already set up.")).unwrap_throw();
|
&JsValue::from("PreviewConnector already set up.")).unwrap_throw();
|
||||||
} else {
|
} else {
|
||||||
match super::ui::create_ui(style) {
|
match super::ui::create_ui(style, true) {
|
||||||
Ok(ui) => {
|
Ok(ui) => {
|
||||||
ui.on_show_document(|url, line, column| ask_editor_to_show_document(url.as_str().to_string(), line as u32, column as u32, line as u32, column as u32));
|
ui.on_show_document(|url, line, column| ask_editor_to_show_document(url.as_str().to_string(), line as u32, column as u32, line as u32, column as u32));
|
||||||
preview_state.borrow_mut().ui = Some(ui);
|
preview_state.borrow_mut().ui = Some(ui);
|
||||||
|
@ -125,11 +125,11 @@ impl PreviewConnector {
|
||||||
super::set_contents(&PathBuf::from(&path), contents);
|
super::set_contents(&PathBuf::from(&path), contents);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
M::SetConfiguration { style, include_paths, library_paths } => {
|
M::SetConfiguration { show_preview_ui, style, include_paths, library_paths } => {
|
||||||
let ip: Vec<PathBuf> = include_paths.iter().map(PathBuf::from).collect();
|
let ip: Vec<PathBuf> = include_paths.iter().map(PathBuf::from).collect();
|
||||||
let lp: HashMap<String, PathBuf> =
|
let lp: HashMap<String, PathBuf> =
|
||||||
library_paths.iter().map(|(n, p)| (n.clone(), PathBuf::from(p))).collect();
|
library_paths.iter().map(|(n, p)| (n.clone(), PathBuf::from(p))).collect();
|
||||||
super::config_changed(&style, &ip, &lp);
|
super::config_changed(show_preview_ui, &style, &ip, &lp);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
M::ShowPreview { path, component, style, include_paths, library_paths } => {
|
M::ShowPreview { path, component, style, include_paths, library_paths } => {
|
||||||
|
@ -259,6 +259,15 @@ pub fn send_message_to_lsp(message: crate::common::PreviewToLspMessage) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_show_preview_ui(show_preview_ui: bool) {
|
||||||
|
PREVIEW_STATE.with(move |preview_state| {
|
||||||
|
let preview_state = preview_state.borrow_mut();
|
||||||
|
if let Some(ui) = &preview_state.ui {
|
||||||
|
ui.set_show_preview_ui(show_preview_ui)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_current_style(style: String) {
|
pub fn set_current_style(style: String) {
|
||||||
PREVIEW_STATE.with(move |preview_state| {
|
PREVIEW_STATE.with(move |preview_state| {
|
||||||
let preview_state = preview_state.borrow_mut();
|
let preview_state = preview_state.borrow_mut();
|
||||||
|
|
51
tools/lsp/ui/diagnostics-overlay.slint
Normal file
51
tools/lsp/ui/diagnostics-overlay.slint
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||||
|
|
||||||
|
// cSpell: ignore Heade
|
||||||
|
|
||||||
|
import { ListView, VerticalBox } from "std-widgets.slint";
|
||||||
|
|
||||||
|
export struct Diagnostics {
|
||||||
|
level: string,
|
||||||
|
message: string,
|
||||||
|
url: string,
|
||||||
|
line: int,
|
||||||
|
column: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
export component DiagnosticsOverlay {
|
||||||
|
in property<[Diagnostics]> diagnostics;
|
||||||
|
callback show-document(/* url */ string, /* line */ int, /* column */ int);
|
||||||
|
|
||||||
|
if (root.diagnostics.length != 0): Rectangle {
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
VerticalBox {
|
||||||
|
Text {
|
||||||
|
color: #000;
|
||||||
|
text: "Compilation failed:";
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
width: parent.width - 10px;
|
||||||
|
height: parent.height - 10px;
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
for diag in root.diagnostics: Rectangle {
|
||||||
|
TouchArea {
|
||||||
|
mouse-cursor: pointer;
|
||||||
|
clicked => { root.show_document(diag.url, diag.line, diag.column); }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: 100%;
|
||||||
|
wrap: word-wrap;
|
||||||
|
color: #000;
|
||||||
|
text: diag.level + ": " + diag.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,22 +5,17 @@
|
||||||
|
|
||||||
import { Button, ComboBox, HorizontalBox, ListView, ScrollView, VerticalBox } from "std-widgets.slint";
|
import { Button, ComboBox, HorizontalBox, ListView, ScrollView, VerticalBox } from "std-widgets.slint";
|
||||||
import { HeaderBar } from "header-bar.slint";
|
import { HeaderBar } from "header-bar.slint";
|
||||||
|
import { Diagnostics, DiagnosticsOverlay } from "diagnostics-overlay.slint";
|
||||||
|
|
||||||
export struct Diagnostics {
|
export { Diagnostics }
|
||||||
level: string,
|
|
||||||
message: string,
|
|
||||||
url: string,
|
|
||||||
line: int,
|
|
||||||
column: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
export component PreviewUi inherits Window {
|
export component PreviewUi inherits Window {
|
||||||
in property<[string]> known-styles;
|
in property<[string]> known-styles;
|
||||||
in property<[Diagnostics]> diagnostics;
|
in property<[Diagnostics]> diagnostics;
|
||||||
in property<string> status-text;
|
in property<string> status-text;
|
||||||
in property<component-factory> preview-area <=> i-preview-area-container.component-factory;
|
in property<component-factory> preview-area;
|
||||||
in-out property<string> current-style;
|
in-out property<string> current-style;
|
||||||
in property<bool> hide-toolbar;
|
in property<bool> show-preview-ui;
|
||||||
|
|
||||||
callback design-mode-changed(/* enabled */ bool);
|
callback design-mode-changed(/* enabled */ bool);
|
||||||
callback style-changed();
|
callback style-changed();
|
||||||
|
@ -29,8 +24,24 @@ export component PreviewUi inherits Window {
|
||||||
title: "Slint Live-Preview";
|
title: "Slint Live-Preview";
|
||||||
icon: @image-url("assets/slint-logo-small-light.png");
|
icon: @image-url("assets/slint-logo-small-light.png");
|
||||||
|
|
||||||
VerticalLayout {
|
if (!show-preview-ui): VerticalLayout {
|
||||||
if !hide_toolbar: HeaderBar {
|
no-ui-drawing-rect := Rectangle {
|
||||||
|
/* background: checkerboard pattern; */
|
||||||
|
ComponentContainer {
|
||||||
|
component-factory <=> root.preview-area;
|
||||||
|
width: clamp(no-ui-drawing-rect.width, self.min-width, self.max-width);
|
||||||
|
height: clamp(no-ui-drawing-rect.height, self.min-height, self.max-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostics overlay:
|
||||||
|
DiagnosticsOverlay {
|
||||||
|
diagnostics <=> root.diagnostics;
|
||||||
|
show-document(url, line, column) => { root.show-document(url, line, column); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (show-preview-ui): VerticalLayout {
|
||||||
|
HeaderBar {
|
||||||
vertical-stretch: 0.0;
|
vertical-stretch: 0.0;
|
||||||
|
|
||||||
height: self.preferred-height;
|
height: self.preferred-height;
|
||||||
|
@ -64,43 +75,16 @@ export component PreviewUi inherits Window {
|
||||||
|
|
||||||
drawing-rect := Rectangle {
|
drawing-rect := Rectangle {
|
||||||
/* background: checkerboard pattern; */
|
/* background: checkerboard pattern; */
|
||||||
i-preview-area-container := ComponentContainer {
|
ComponentContainer {
|
||||||
width: max(self.min-width, min(self.max-width, drawing-rect.width));
|
component-factory <=> root.preview-area;
|
||||||
height: max(self.min-height, min(self.max-height, drawing-rect.height));
|
width: clamp(drawing-rect.width, self.min-width, self.max-width);
|
||||||
|
height: clamp(drawing-rect.height, self.min-height, self.max-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostics overlay:
|
// Diagnostics overlay:
|
||||||
if (root.diagnostics.length != 0): Rectangle {
|
DiagnosticsOverlay {
|
||||||
background: #fff;
|
diagnostics <=> root.diagnostics;
|
||||||
|
show-document(url, line, column) => { root.show-document(url, line, column); }
|
||||||
VerticalBox {
|
|
||||||
|
|
||||||
Text {
|
|
||||||
color: #000;
|
|
||||||
text: "Compilation failed:";
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
width: parent.width - 10px;
|
|
||||||
height: parent.height - 10px;
|
|
||||||
|
|
||||||
padding: 5px;
|
|
||||||
|
|
||||||
for diag in root.diagnostics: Rectangle {
|
|
||||||
TouchArea {
|
|
||||||
mouse-cursor: pointer;
|
|
||||||
clicked => { root.show_document(diag.url, diag.line, diag.column); }
|
|
||||||
|
|
||||||
Text {
|
|
||||||
width: 100%;
|
|
||||||
wrap: word-wrap;
|
|
||||||
color: #000;
|
|
||||||
text: diag.level + ": " + diag.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ pub mod wasm_prelude {
|
||||||
struct Previewer {
|
struct Previewer {
|
||||||
server_notifier: ServerNotifier,
|
server_notifier: ServerNotifier,
|
||||||
to_show: RefCell<Option<common::PreviewComponent>>,
|
to_show: RefCell<Option<common::PreviewComponent>>,
|
||||||
|
show_preview_ui: RefCell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreviewApi for Previewer {
|
impl PreviewApi for Previewer {
|
||||||
|
@ -94,14 +95,18 @@ impl PreviewApi for Previewer {
|
||||||
|
|
||||||
fn config_changed(
|
fn config_changed(
|
||||||
&self,
|
&self,
|
||||||
|
show_preview_ui: bool,
|
||||||
style: &str,
|
style: &str,
|
||||||
include_paths: &[PathBuf],
|
include_paths: &[PathBuf],
|
||||||
library_paths: &HashMap<String, PathBuf>,
|
library_paths: &HashMap<String, PathBuf>,
|
||||||
) {
|
) {
|
||||||
|
*self.show_preview_ui.borrow_mut() = show_preview_ui;
|
||||||
|
|
||||||
#[cfg(feature = "preview-external")]
|
#[cfg(feature = "preview-external")]
|
||||||
let _ = self.server_notifier.send_notification(
|
let _ = self.server_notifier.send_notification(
|
||||||
"slint/lsp_to_preview".to_string(),
|
"slint/lsp_to_preview".to_string(),
|
||||||
crate::common::LspToPreviewMessage::SetConfiguration {
|
crate::common::LspToPreviewMessage::SetConfiguration {
|
||||||
|
show_preview_ui,
|
||||||
style: style.to_string(),
|
style: style.to_string(),
|
||||||
include_paths: include_paths
|
include_paths: include_paths
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -129,6 +134,10 @@ impl PreviewApi for Previewer {
|
||||||
fn current_component(&self) -> Option<crate::common::PreviewComponent> {
|
fn current_component(&self) -> Option<crate::common::PreviewComponent> {
|
||||||
self.to_show.borrow().clone()
|
self.to_show.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_preview_ui(&self) -> bool {
|
||||||
|
*self.show_preview_ui.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -269,6 +278,7 @@ pub fn create(
|
||||||
let preview = Rc::new(Previewer {
|
let preview = Rc::new(Previewer {
|
||||||
server_notifier: server_notifier.clone(),
|
server_notifier: server_notifier.clone(),
|
||||||
to_show: Default::default(),
|
to_show: Default::default(),
|
||||||
|
show_preview_ui: RefCell::new(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
let init_param = serde_wasm_bindgen::from_value(init_param)?;
|
let init_param = serde_wasm_bindgen::from_value(init_param)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue