Skip to content

Commit 03f1e10

Browse files
committed
live-preview: Cache compilation results while moving elements around
1 parent 8d9ea63 commit 03f1e10

File tree

4 files changed

+58
-41
lines changed

4 files changed

+58
-41
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ bytemuck = { version = "1.13.1" }
133133
cbindgen = { version = "0.26", default-features = false }
134134
cfg_aliases = { version = "0.2.0" }
135135
clap = { version = "4.0", features = ["derive", "wrap_help"] }
136+
clru = { version = "0.6.0" }
136137
css-color-parser2 = { version = "1.0.1" }
137138
derive_more = { version = "0.99.17" }
138139
euclid = { version = "0.22.1", default-features = false }

internal/core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ integer-sqrt = { version = "0.1.5" }
8181
bytemuck = { workspace = true, optional = true, features = ["derive"] }
8282

8383
image = { workspace = true, optional = true, default-features = false }
84-
clru = { version = "0.6.0", optional = true }
84+
clru = { workspace = true, optional = true }
8585

8686
resvg = { workspace = true, optional = true }
8787
fontdb = { workspace = true, optional = true }

tools/lsp/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ default = ["backend-default", "renderer-femtovg", "preview"]
7979
[dependencies]
8080
i-slint-compiler = { workspace = true, features = ["display-diagnostics"] }
8181

82+
by_address = { workspace = true }
83+
clru = { workspace = true }
8284
dissimilar = "1.0.7"
8385
euclid = { workspace = true }
8486
itertools = { workspace = true }

tools/lsp/preview/drop_location.rs

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright © SixtyFPS GmbH <info@slint.dev>
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

4+
use std::cell::RefCell;
5+
use std::num::NonZeroUsize;
6+
47
use i_slint_compiler::diagnostics::{BuildDiagnostics, SourceFile};
58
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
69
use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize};
@@ -601,7 +604,7 @@ fn find_filtered_location(
601604

602605
/// Find the Element to insert into. None means we can not insert at this point.
603606
pub fn can_drop_at(position: LogicalPoint, component_type: &str) -> bool {
604-
let dm = &super::component_instance()
607+
let dm = &preview::component_instance()
605608
.and_then(|ci| find_drop_location(&ci, position, component_type));
606609

607610
preview::set_drop_mark(&dm.as_ref().and_then(|dm| dm.drop_mark.clone()));
@@ -616,27 +619,21 @@ pub fn workspace_edit_compiles(
616619
return false;
617620
};
618621

619-
let Some(mut tmp_document_cache) = document_cache.snapshot() else {
620-
return false;
621-
};
622622
let mut diag = BuildDiagnostics::default();
623623

624+
let mut document_cache = document_cache.snapshot().expect("This is not loading anything!");
625+
624626
// Fill in changed sources:
625627
for (u, c) in result.drain(..).map(|mut r| {
626628
let contents = std::mem::take(&mut r.contents);
627629
(r.url.clone(), contents)
628630
}) {
629-
diag = BuildDiagnostics::default(); // reset errors that might be due to missing changes elsewhere..
630-
// <debug>
631-
let _ = crate::preview::poll_once(tmp_document_cache.load_url(&u, None, c, &mut diag));
632-
}
631+
diag = BuildDiagnostics::default(); // reset errors that might be due to missing changes elsewhere
633632

634-
if diag.has_error() {
635-
eprintln!("Compilation failed! Diagnostics:\n{}", diag.diagnostics_as_string());
636-
return false;
633+
let _ = preview::poll_once(document_cache.load_url(&u, None, c, &mut diag));
637634
}
638635

639-
true
636+
!diag.has_error()
640637
}
641638

642639
/// Find the Element to insert into. None means we can not insert at this point.
@@ -654,39 +651,57 @@ pub fn can_move_to(
654651
let dm =
655652
find_move_location(&component_instance, mouse_position, &element_node, &component_type);
656653

657-
if let Some(dm) = &dm {
658-
if let Some((edit, _)) =
659-
create_move_element_workspace_edit(&component_instance, dm, &element_node, position)
660-
{
661-
if let Some(lsp_types::DocumentChanges::Edits(e)) = &edit.document_changes {
662-
for e in e {
663-
eprintln!("Edit: {}", e.text_document.uri);
664-
for e in &e.edits {
665-
match &e {
666-
lsp_types::OneOf::Left(e) => {
667-
eprintln!(" {:?} => \"{}\"", e.range, e.new_text);
668-
}
669-
_ => {
670-
eprintln!("Annotated edit. No idea how that got here");
671-
}
672-
}
673-
}
674-
}
675-
} else {
676-
eprintln!("No docuemnt changes in WorkspaceEdit!");
677-
}
654+
let can_move = if let Some(dm) = &dm {
655+
// Cache compilation results:
656+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
657+
struct CacheEntry {
658+
source_element: by_address::ByAddress<i_slint_compiler::object_tree::ElementRc>,
659+
source_node_index: usize,
660+
target_element: by_address::ByAddress<i_slint_compiler::object_tree::ElementRc>,
661+
target_node_index: usize,
662+
child_index: usize,
663+
}
664+
static mut CACHE: std::cell::OnceCell<RefCell<clru::CLruCache<CacheEntry, bool>>> =
665+
std::cell::OnceCell::new();
678666

679-
if !workspace_edit_compiles(document_cache, &edit) {
680-
preview::set_drop_mark(&None);
681-
return false;
682-
}
667+
// SAFETY: This uses the document_cache, which means it runs in the UI thread.
668+
let cache = unsafe {
669+
CACHE.get_or_init(|| RefCell::new(clru::CLruCache::new(NonZeroUsize::new(10).unwrap())))
670+
};
671+
let mut cache = cache.borrow_mut();
672+
673+
let cache_entry = CacheEntry {
674+
source_element: by_address::ByAddress(element_node.element.clone()),
675+
source_node_index: element_node.debug_index,
676+
target_element: by_address::ByAddress(dm.target_element_node.element.clone()),
677+
target_node_index: dm.target_element_node.debug_index,
678+
child_index: dm.child_index,
679+
};
680+
681+
if let Some(does_compile) = cache.get(&cache_entry) {
682+
*does_compile
683+
} else {
684+
let does_compile = if let Some((edit, _)) =
685+
create_move_element_workspace_edit(&component_instance, dm, &element_node, position)
686+
{
687+
workspace_edit_compiles(document_cache, &edit)
688+
} else {
689+
false
690+
};
691+
cache.put(cache_entry, does_compile);
692+
does_compile
683693
}
684-
preview::set_drop_mark(&dm.drop_mark);
694+
} else {
695+
false
696+
};
697+
698+
if can_move {
699+
preview::set_drop_mark(&dm.unwrap().drop_mark);
685700
} else {
686701
preview::set_drop_mark(&None);
687702
}
688703

689-
dm.is_some()
704+
can_move
690705
}
691706

692707
/// Extra data on an added Element, relevant to the Preview side only.
@@ -1069,7 +1084,6 @@ pub fn move_element_to(
10691084
// Can not drop here: Ignore the move
10701085
return None;
10711086
};
1072-
10731087
create_move_element_workspace_edit(&component_instance, &drop_info, &element, position)
10741088
.and_then(|(e, d)| workspace_edit_compiles(document_cache, &e).then_some((e, d)))
10751089
}

0 commit comments

Comments
 (0)