diff --git a/tools/lsp/common.rs b/tools/lsp/common.rs index 312b37ad7cd..d6b2a3790ef 100644 --- a/tools/lsp/common.rs +++ b/tools/lsp/common.rs @@ -15,6 +15,7 @@ use std::path::Path; use std::{collections::HashMap, path::PathBuf}; pub mod component_catalog; +pub mod properties; pub mod rename_component; #[cfg(test)] pub mod test; @@ -94,19 +95,36 @@ impl DocumentCache { .and_then(|doc| doc.node.as_ref()?.source_file.version()) } - pub fn get_document(&self, url: &Url) -> Option<&Document> { + pub fn get_document<'a>(&'a self, url: &'_ Url) -> Option<&'a Document> { let path = uri_to_file(url)?; self.0.get_document(&path) } - pub fn get_document_by_path(&self, path: &Path) -> Option<&Document> { + pub fn get_document_by_path<'a>(&'a self, path: &'_ Path) -> Option<&'a Document> { self.0.get_document(path) } - pub fn get_document_for_source_file(&self, source_file: &SourceFile) -> Option<&Document> { + pub fn get_document_for_source_file<'a>( + &'a self, + source_file: &'_ SourceFile, + ) -> Option<&'a Document> { self.0.get_document(source_file.path()) } + pub fn get_document_and_offset<'a>( + &'a self, + text_document_uri: &'_ Url, + pos: &'_ lsp_types::Position, + ) -> Option<(&'a i_slint_compiler::object_tree::Document, u32)> { + let doc = self.get_document(text_document_uri)?; + let o = doc + .node + .as_ref()? + .source_file + .offset(pos.line as usize + 1, pos.character as usize + 1) as u32; + doc.node.as_ref()?.text_range().contains_inclusive(o.into()).then_some((doc, o)) + } + pub fn all_url_documents(&self) -> impl Iterator + '_ { self.0.all_file_documents().filter_map(|(p, d)| Some((file_to_uri(p)?, d))) } @@ -172,6 +190,48 @@ impl DocumentCache { pub fn compiler_configuration(&self) -> &CompilerConfiguration { &self.0.compiler_config } + + pub fn element_at_position( + &self, + text_document_uri: &Url, + pos: &lsp_types::Position, + ) -> Option { + fn element_contains( + element: &i_slint_compiler::object_tree::ElementRc, + offset: u32, + ) -> Option { + element.borrow().debug.iter().position(|n| { + n.node.parent().map_or(false, |n| n.text_range().contains(offset.into())) + }) + } + + let (doc, offset) = self.get_document_and_offset(text_document_uri, pos)?; + + for component in &doc.inner_components { + let root_element = component.root_element.clone(); + let Some(root_debug_index) = element_contains(&root_element, offset) else { + continue; + }; + + let mut element = + ElementRcNode { element: root_element, debug_index: root_debug_index }; + while element.contains_offset(offset) { + if let Some((c, i)) = element + .element + .clone() + .borrow() + .children + .iter() + .find_map(|c| element_contains(c, offset).map(|i| (c, i))) + { + element = ElementRcNode { element: c.clone(), debug_index: i }; + } else { + return Some(element); + } + } + } + None + } } pub fn extract_element(node: SyntaxNode) -> Option { @@ -375,6 +435,12 @@ impl ElementRcNode { std::rc::Rc::ptr_eq(&s.source_file, &o.source_file) && s.text_range() == o.text_range() } + + pub fn contains_offset(&self, offset: u32) -> bool { + self.with_element_node(|node| { + node.parent().map_or(false, |n| n.text_range().contains(offset.into())) + }) + } } pub fn create_workspace_edit(uri: Url, version: UrlVersion, edits: Vec) -> WorkspaceEdit { @@ -568,13 +634,6 @@ pub enum PreviewToLspMessage { /// Request all documents and configuration to be sent from the LSP to the /// Preview. RequestState { unused: bool }, - /// Update properties on an element at `position` - /// The LSP side needs to look at properties: It sees way more of them! - UpdateElement { - label: Option, - position: VersionedPosition, - properties: Vec, - }, /// Pass a `WorkspaceEdit` on to the editor SendWorkspaceEdit { label: Option, edit: lsp_types::WorkspaceEdit }, } @@ -687,6 +746,8 @@ pub mod lsp_to_editor { #[cfg(test)] mod tests { + use crate::test::complex_document_cache; + use super::*; #[test] @@ -716,4 +777,70 @@ mod tests { assert_eq!(back_conversion1, builtin_path1); } + + fn id_at_position(dc: &DocumentCache, url: &Url, line: u32, character: u32) -> Option { + let result = dc.element_at_position(url, &lsp_types::Position { line, character })?; + let element = result.element.borrow(); + Some(element.id.clone()) + } + + fn base_type_at_position( + dc: &DocumentCache, + url: &Url, + line: u32, + character: u32, + ) -> Option { + let result = dc.element_at_position(url, &lsp_types::Position { line, character })?; + let element = result.element.borrow(); + Some(format!("{}", &element.base_type)) + } + + #[test] + fn test_element_at_position_no_element() { + let (dc, url, _) = complex_document_cache(); + assert_eq!(id_at_position(&dc, &url, 0, 10), None); + // TODO: This is past the end of the line and should thus return None + assert_eq!(id_at_position(&dc, &url, 42, 90), Some(String::new())); + assert_eq!(id_at_position(&dc, &url, 1, 0), None); + assert_eq!(id_at_position(&dc, &url, 55, 1), None); + assert_eq!(id_at_position(&dc, &url, 56, 5), None); + } + + #[test] + fn test_element_at_position_no_such_document() { + let (dc, _, _) = complex_document_cache(); + assert_eq!(id_at_position(&dc, &Url::parse("https://foo.bar/baz").unwrap(), 5, 0), None); + } + + #[test] + fn test_element_at_position_root() { + let (dc, url, _) = complex_document_cache(); + + assert_eq!(id_at_position(&dc, &url, 2, 30), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 2, 32), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 2, 42), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 3, 0), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 3, 53), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 4, 19), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 5, 0), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 6, 8), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 6, 15), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 6, 23), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 8, 15), Some("root".to_string())); + assert_eq!(id_at_position(&dc, &url, 12, 3), Some("root".to_string())); // right before child // TODO: Seems wrong! + assert_eq!(id_at_position(&dc, &url, 51, 5), Some("root".to_string())); // right after child // TODO: Why does this not work? + assert_eq!(id_at_position(&dc, &url, 52, 0), Some("root".to_string())); + } + + #[test] + fn test_element_at_position_child() { + let (dc, url, _) = complex_document_cache(); + + assert_eq!(base_type_at_position(&dc, &url, 12, 4), Some("VerticalBox".to_string())); + assert_eq!(base_type_at_position(&dc, &url, 14, 22), Some("HorizontalBox".to_string())); + assert_eq!(base_type_at_position(&dc, &url, 15, 33), Some("Text".to_string())); + assert_eq!(base_type_at_position(&dc, &url, 27, 4), Some("VerticalBox".to_string())); + assert_eq!(base_type_at_position(&dc, &url, 28, 8), Some("Text".to_string())); + assert_eq!(base_type_at_position(&dc, &url, 51, 4), Some("VerticalBox".to_string())); + } } diff --git a/tools/lsp/language/properties.rs b/tools/lsp/common/properties.rs similarity index 98% rename from tools/lsp/language/properties.rs rename to tools/lsp/common/properties.rs index d0af1db4bc6..2ed3504c56e 100644 --- a/tools/lsp/language/properties.rs +++ b/tools/lsp/common/properties.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 use crate::common::{self, Result}; -use crate::language; use crate::util; use i_slint_compiler::diagnostics::{BuildDiagnostics, SourceFileVersion, Spanned}; @@ -606,7 +605,7 @@ fn set_binding_on_known_property( } pub fn set_binding( - document_cache: &language::DocumentCache, + document_cache: &common::DocumentCache, uri: &lsp_types::Url, version: SourceFileVersion, element: &common::ElementRcNode, @@ -679,7 +678,7 @@ pub fn set_binding( #[cfg(any(feature = "preview-external", feature = "preview-engine"))] pub fn set_bindings( - document_cache: &language::DocumentCache, + document_cache: &common::DocumentCache, uri: lsp_types::Url, version: SourceFileVersion, element: &common::ElementRcNode, @@ -721,7 +720,7 @@ pub fn set_bindings( #[cfg(any(feature = "preview-external", feature = "preview-engine"))] fn element_at_source_code_position( - document_cache: &mut language::DocumentCache, + document_cache: &common::DocumentCache, position: &common::VersionedPosition, ) -> Result { if &document_cache.document_version(position.url()) != position.version() { @@ -739,22 +738,21 @@ fn element_at_source_code_position( .ok_or_else(|| "Document had no node".to_string())?; let element_position = util::map_position(&source_file, position.offset().into()); - Ok(language::element_at_position(document_cache, position.url(), &element_position) - .ok_or_else(|| { - format!("No element found at the given start position {:?}", &element_position) - })?) + Ok(document_cache.element_at_position(position.url(), &element_position).ok_or_else(|| { + format!("No element found at the given start position {:?}", &element_position) + })?) } #[cfg(any(feature = "preview-external", feature = "preview-engine"))] pub fn update_element_properties( - ctx: &language::Context, + document_cache: &common::DocumentCache, position: common::VersionedPosition, properties: Vec, ) -> Result { - let element = element_at_source_code_position(&mut ctx.document_cache.borrow_mut(), &position)?; + let element = element_at_source_code_position(document_cache, &position)?; let (_, e) = set_bindings( - &ctx.document_cache.borrow_mut(), + document_cache, position.url().clone(), *position.version(), &element, @@ -857,11 +855,8 @@ mod tests { document_cache: &common::DocumentCache, url: &lsp_types::Url, ) -> Option<(common::ElementRcNode, Vec)> { - let element = language::element_at_position( - document_cache, - url, - &lsp_types::Position { line, character }, - )?; + let element = + document_cache.element_at_position(url, &lsp_types::Position { line, character })?; Some((element.clone(), get_properties(&element))) } @@ -871,7 +866,7 @@ mod tests { ) -> Option<( common::ElementRcNode, Vec, - language::DocumentCache, + common::DocumentCache, lsp_types::Url, )> { let (dc, url, _) = complex_document_cache(); @@ -914,8 +909,7 @@ mod tests { fn test_element_information() { let (document_cache, url, _) = complex_document_cache(); let element = - language::element_at_position(&document_cache, &url, &lsp_types::Position::new(33, 4)) - .unwrap(); + document_cache.element_at_position(&url, &lsp_types::Position::new(33, 4)).unwrap(); let result = get_element_information(&element); diff --git a/tools/lsp/common/rename_component.rs b/tools/lsp/common/rename_component.rs index 83446636477..6c9364073f3 100644 --- a/tools/lsp/common/rename_component.rs +++ b/tools/lsp/common/rename_component.rs @@ -287,7 +287,7 @@ pub fn rename_component_from_definition( } let component_type = identifier.text().to_string().trim().to_string(); - if &component_type == new_name { + if component_type == new_name { return Ok(lsp_types::WorkspaceEdit::default()); } diff --git a/tools/lsp/language.rs b/tools/lsp/language.rs index 7007ee88c10..b66ba3c23a3 100644 --- a/tools/lsp/language.rs +++ b/tools/lsp/language.rs @@ -6,12 +6,11 @@ pub mod completion; mod formatting; mod goto; -pub mod properties; mod semantic_tokens; #[cfg(test)] pub mod test; -use crate::common::{self, DocumentCache, Result}; +use crate::common::{self, properties, DocumentCache, Result}; use crate::util; #[cfg(target_arch = "wasm32")] @@ -454,7 +453,7 @@ pub fn query_properties_command( .expect("Failed to serialize none-element property query result!")); }; - if let Some(element) = element_at_position(document_cache, &text_document_uri, &position) { + if let Some(element) = document_cache.element_at_position(&text_document_uri, &position) { properties::query_properties(&text_document_uri, source_version, &element) .map(|r| serde_json::to_value(r).expect("Failed to serialize property query result!")) } else { @@ -507,7 +506,7 @@ pub async fn set_binding_command( } let element = - element_at_position(document_cache, &uri, &element_range.start).ok_or_else(|| { + document_cache.element_at_position(&uri, &element_range.start).ok_or_else(|| { format!("No element found at the given start position {:?}", &element_range.start) })?; @@ -592,7 +591,7 @@ pub async fn remove_binding_command( } let element = - element_at_position(document_cache, &uri, &element_range.start).ok_or_else(|| { + document_cache.element_at_position(&uri, &element_range.start).ok_or_else(|| { format!("No element found at the given start position {:?}", &element_range.start) })?; @@ -702,74 +701,13 @@ pub async fn reload_document( Ok(()) } -fn get_document_and_offset<'a>( - document_cache: &'a DocumentCache, - text_document_uri: &'_ Url, - pos: &'_ Position, -) -> Option<(&'a i_slint_compiler::object_tree::Document, u32)> { - let doc = document_cache.get_document(text_document_uri)?; - let o = doc.node.as_ref()?.source_file.offset(pos.line as usize + 1, pos.character as usize + 1) - as u32; - doc.node.as_ref()?.text_range().contains_inclusive(o.into()).then_some((doc, o)) -} - -fn element_contains( - element: &i_slint_compiler::object_tree::ElementRc, - offset: u32, -) -> Option { - element - .borrow() - .debug - .iter() - .position(|n| n.node.parent().map_or(false, |n| n.text_range().contains(offset.into()))) -} - -fn element_node_contains(element: &common::ElementRcNode, offset: u32) -> bool { - element.with_element_node(|node| { - node.parent().map_or(false, |n| n.text_range().contains(offset.into())) - }) -} - -pub fn element_at_position( - document_cache: &DocumentCache, - text_document_uri: &Url, - pos: &Position, -) -> Option { - let (doc, offset) = get_document_and_offset(document_cache, text_document_uri, pos)?; - - for component in &doc.inner_components { - let root_element = component.root_element.clone(); - let Some(root_debug_index) = element_contains(&root_element, offset) else { - continue; - }; - - let mut element = - common::ElementRcNode { element: root_element, debug_index: root_debug_index }; - while element_node_contains(&element, offset) { - if let Some((c, i)) = element - .element - .clone() - .borrow() - .children - .iter() - .find_map(|c| element_contains(c, offset).map(|i| (c, i))) - { - element = common::ElementRcNode { element: c.clone(), debug_index: i }; - } else { - return Some(element); - } - } - } - None -} - /// return the token, and the offset within the file fn token_descr( document_cache: &mut DocumentCache, text_document_uri: &Url, pos: &Position, ) -> Option<(SyntaxToken, u32)> { - let (doc, o) = get_document_and_offset(document_cache, text_document_uri, pos)?; + let (doc, o) = document_cache.get_document_and_offset(text_document_uri, pos)?; let node = doc.node.as_ref()?; let token = token_at_offset(node, o)?; @@ -892,7 +830,7 @@ fn get_code_actions( if has_experimental_client_capability(client_capabilities, "snippetTextEdit") { let r = util::map_range(&token.source_file, node.parent().unwrap().text_range()); - let element = element_at_position(document_cache, &uri, &r.start); + let element = document_cache.element_at_position(&uri, &r.start); let element_indent = element.as_ref().and_then(util::find_element_indent); let indented_lines = node .parent() @@ -1393,80 +1331,6 @@ pub mod tests { assert_eq!(f64::trunc(color.alpha as f64 * 255.0), 128.0); } - fn id_at_position( - dc: &mut DocumentCache, - url: &Url, - line: u32, - character: u32, - ) -> Option { - let result = element_at_position(&dc, url, &Position { line, character })?; - let element = result.element.borrow(); - Some(element.id.clone()) - } - - fn base_type_at_position( - dc: &mut DocumentCache, - url: &Url, - line: u32, - character: u32, - ) -> Option { - let result = element_at_position(&dc, url, &Position { line, character })?; - let element = result.element.borrow(); - Some(format!("{}", &element.base_type)) - } - - #[test] - fn test_element_at_position_no_element() { - let (mut dc, url, _) = complex_document_cache(); - assert_eq!(id_at_position(&mut dc, &url, 0, 10), None); - // TODO: This is past the end of the line and should thus return None - assert_eq!(id_at_position(&mut dc, &url, 42, 90), Some(String::new())); - assert_eq!(id_at_position(&mut dc, &url, 1, 0), None); - assert_eq!(id_at_position(&mut dc, &url, 55, 1), None); - assert_eq!(id_at_position(&mut dc, &url, 56, 5), None); - } - - #[test] - fn test_element_at_position_no_such_document() { - let (mut dc, _, _) = complex_document_cache(); - assert_eq!( - id_at_position(&mut dc, &Url::parse("https://foo.bar/baz").unwrap(), 5, 0), - None - ); - } - - #[test] - fn test_element_at_position_root() { - let (mut dc, url, _) = complex_document_cache(); - - assert_eq!(id_at_position(&mut dc, &url, 2, 30), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 2, 32), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 2, 42), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 3, 0), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 3, 53), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 4, 19), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 5, 0), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 6, 8), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 6, 15), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 6, 23), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 8, 15), Some("root".to_string())); - assert_eq!(id_at_position(&mut dc, &url, 12, 3), Some("root".to_string())); // right before child // TODO: Seems wrong! - assert_eq!(id_at_position(&mut dc, &url, 51, 5), Some("root".to_string())); // right after child // TODO: Why does this not work? - assert_eq!(id_at_position(&mut dc, &url, 52, 0), Some("root".to_string())); - } - - #[test] - fn test_element_at_position_child() { - let (mut dc, url, _) = complex_document_cache(); - - assert_eq!(base_type_at_position(&mut dc, &url, 12, 4), Some("VerticalBox".to_string())); - assert_eq!(base_type_at_position(&mut dc, &url, 14, 22), Some("HorizontalBox".to_string())); - assert_eq!(base_type_at_position(&mut dc, &url, 15, 33), Some("Text".to_string())); - assert_eq!(base_type_at_position(&mut dc, &url, 27, 4), Some("VerticalBox".to_string())); - assert_eq!(base_type_at_position(&mut dc, &url, 28, 8), Some("Text".to_string())); - assert_eq!(base_type_at_position(&mut dc, &url, 51, 4), Some("VerticalBox".to_string())); - } - #[test] fn test_document_symbols() { let (mut dc, uri, _) = complex_document_cache(); @@ -1584,7 +1448,7 @@ enum {} .unwrap(); let check_start_with = |pos, str: &str| { - let (_, offset) = get_document_and_offset(&dc, &uri, &pos).unwrap(); + let (_, offset) = dc.get_document_and_offset(&uri, &pos).unwrap(); assert_eq!(&source[offset as usize..][..str.len()], str); }; diff --git a/tools/lsp/main.rs b/tools/lsp/main.rs index 8dea26b9a48..8b483557182 100644 --- a/tools/lsp/main.rs +++ b/tools/lsp/main.rs @@ -484,14 +484,6 @@ async fn handle_preview_to_lsp_message( M::RequestState { .. } => { crate::language::request_state(ctx); } - M::UpdateElement { label, position, properties } => { - let _ = send_workspace_edit( - ctx.server_notifier.clone(), - label, - properties::update_element_properties(ctx, position, properties), - ) - .await; - } M::SendWorkspaceEdit { label, edit } => { let _ = send_workspace_edit(ctx.server_notifier.clone(), label, Ok(edit)).await; } diff --git a/tools/lsp/preview.rs b/tools/lsp/preview.rs index a567a8a0a0c..a285bb71aca 100644 --- a/tools/lsp/preview.rs +++ b/tools/lsp/preview.rs @@ -286,7 +286,7 @@ fn rename_component( new_name: slint::SharedString, ) { let old_name = old_name.to_string(); - let Ok(old_url) = lsp_types::Url::parse(&old_url.to_string()) else { + let Ok(old_url) = lsp_types::Url::parse(old_url.as_ref()) else { return; }; let new_name = new_name.to_string(); @@ -334,7 +334,6 @@ fn rename_component( // triggered from the UI, running in UI thread fn navigate(nav_direction: i32) { - eprintln!("navigate({nav_direction})"); if let Some(current) = { let mut cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap(); cache.navigate_component_history(nav_direction); @@ -347,7 +346,7 @@ fn navigate(nav_direction: i32) { // triggered from the UI, running in UI thread fn show_component(name: slint::SharedString, url: slint::SharedString) { let name = name.to_string(); - let Ok(url) = Url::parse(&url.to_string()) else { + let Ok(url) = Url::parse(url.as_ref()) else { return; }; @@ -483,27 +482,33 @@ fn delete_selected_element() { // triggered from the UI, running in UI thread fn resize_selected_element(x: f32, y: f32, width: f32, height: f32) { - resize_selected_element_impl(LogicalRect::new( + let Ok(Some((edit, label))) = resize_selected_element_impl(LogicalRect::new( LogicalPoint::new(x, y), LogicalSize::new(width, height), - )) + )) else { + return; + }; + + send_message_to_lsp(crate::common::PreviewToLspMessage::SendWorkspaceEdit { label, edit }); } -fn resize_selected_element_impl(rect: LogicalRect) { +fn resize_selected_element_impl( + rect: LogicalRect, +) -> common::Result)>> { let Some(selected) = selected_element() else { - return; + return Ok(None); }; let Some(selected_element_node) = selected.as_element_node() else { - return; + return Ok(None); }; let Some(component_instance) = component_instance() else { - return; + return Ok(None); }; let Some(geometry) = selected_element_node.geometries(&component_instance).get(selected.instance_index).cloned() else { - return; + return Ok(None); }; let position = rect.origin; @@ -553,25 +558,26 @@ fn resize_selected_element_impl(rect: LogicalRect) { (p, op) }; - if !properties.is_empty() { - let Ok(url) = Url::from_file_path(&selected.path) else { - return; - }; + if properties.is_empty() { + return Ok(None); + } - let cache = CONTENT_CACHE.get_or_init(Default::default).lock().unwrap(); - let Some((version, _)) = cache.source_code.get(&url).cloned() else { - return; - }; + let Ok(url) = Url::from_file_path(&selected.path) else { + return Ok(None); + }; - send_message_to_lsp(crate::common::PreviewToLspMessage::UpdateElement { - label: Some(format!("{op} element")), - position: common::VersionedPosition::new( - common::VersionedUrl::new(url, version), - selected.offset, - ), - properties, - }); - } + let Some(document_cache) = document_cache() else { + return Ok(None); + }; + + let version = document_cache.document_version(&url); + + common::properties::update_element_properties( + &document_cache, + common::VersionedPosition::new(common::VersionedUrl::new(url, version), selected.offset), + properties, + ) + .map(|edit| Some((edit, Some(format!("{op} element"))))) } // triggered from the UI, running in UI thread diff --git a/tools/lsp/preview/drop_location.rs b/tools/lsp/preview/drop_location.rs index a31a8bb22bf..66d08817fad 100644 --- a/tools/lsp/preview/drop_location.rs +++ b/tools/lsp/preview/drop_location.rs @@ -1092,8 +1092,13 @@ pub fn create_move_element_workspace_edit( let size = element.geometries(component_instance).first().map(|g| g.size)?; if drop_info.target_element_node.layout_kind() == ui::LayoutKind::None { - preview::resize_selected_element_impl(LogicalRect::new(position, size)); - return None; + let Ok(Some((edit, _))) = + preview::resize_selected_element_impl(LogicalRect::new(position, size)) + else { + return None; + }; + let (path, selection_offset) = element.path_and_offset(); + return Some((edit, DropData { selection_offset, path })); } else { let children = drop_info.target_element_node.children(); let child_index = { diff --git a/tools/lsp/util.rs b/tools/lsp/util.rs index f39bc3946a8..794d4b39055 100644 --- a/tools/lsp/util.rs +++ b/tools/lsp/util.rs @@ -305,7 +305,6 @@ fn to_lsp_diag_level(level: DiagnosticLevel) -> lsp_types::DiagnosticSeverity { mod tests { use super::*; - use crate::language; use crate::language::test::loaded_document_cache; #[test] @@ -319,13 +318,13 @@ mod tests { .to_string(), ); - let window = language::element_at_position(&dc, &url, &lsp_types::Position::new(0, 30)); + let window = dc.element_at_position(&url, &lsp_types::Position::new(0, 30)); assert_eq!(find_element_indent(&window.unwrap()), None); - let vbox = language::element_at_position(&dc, &url, &lsp_types::Position::new(1, 4)); + let vbox = dc.element_at_position(&url, &lsp_types::Position::new(1, 4)); assert_eq!(find_element_indent(&vbox.unwrap()), Some(" ".to_string())); - let label = language::element_at_position(&dc, &url, &lsp_types::Position::new(2, 17)); + let label = dc.element_at_position(&url, &lsp_types::Position::new(2, 17)); assert_eq!(find_element_indent(&label.unwrap()), Some(" ".to_string())); } } diff --git a/tools/lsp/wasm_main.rs b/tools/lsp/wasm_main.rs index 4c1359b9176..cfb3ccb96a0 100644 --- a/tools/lsp/wasm_main.rs +++ b/tools/lsp/wasm_main.rs @@ -297,15 +297,6 @@ impl SlintServer { M::RequestState { .. } => { crate::language::request_state(&self.ctx); } - M::UpdateElement { label, position, properties } => { - send_workspace_edit( - self.ctx.server_notifier.clone(), - label, - language::properties::update_element_properties( - &self.ctx, position, properties, - ), - ); - } M::SendWorkspaceEdit { label, edit } => { send_workspace_edit(self.ctx.server_notifier.clone(), label, Ok(edit)); }