diff --git a/tools/lsp/Cargo.toml b/tools/lsp/Cargo.toml index 7b10bb30a..ef52ba773 100644 --- a/tools/lsp/Cargo.toml +++ b/tools/lsp/Cargo.toml @@ -103,6 +103,7 @@ i-slint-backend-selector = { workspace = true, optional = true } i-slint-core = { workspace = true, features = ["std"], optional = true } slint = { workspace = true, features = ["compat-1-2"], optional = true } slint-interpreter = { workspace = true, features = ["compat-1-2", "internal", "internal-highlight", "internal-json", "image-default-formats"], optional = true } +nucleo-matcher = "0.3.1" [target.'cfg(not(any(target_os = "windows", target_arch = "wasm32", all(target_arch = "aarch64", target_os = "linux"))))'.dependencies] tikv-jemallocator = { workspace = true } diff --git a/tools/lsp/preview/ui.rs b/tools/lsp/preview/ui.rs index dcd8403dc..cd09da5c7 100644 --- a/tools/lsp/preview/ui.rs +++ b/tools/lsp/preview/ui.rs @@ -144,6 +144,8 @@ pub fn create_ui(style: String, experimental: bool) -> Result Vec { let colors = i_slint_compiler::lookup::named_colors(); @@ -154,6 +154,47 @@ pub fn collect_palettes( collect_palette_from_globals(document_cache, document_uri, collect_colors_palette()) } +pub fn filter_palettes( + input: slint::ModelRc, + pattern: slint::SharedString, +) -> slint::ModelRc { + let pattern = pattern.to_string(); + std::rc::Rc::new(slint::VecModel::from(filter_palettes_iter(&mut input.iter(), &pattern))) + .into() +} + +fn filter_palettes_iter( + input: &mut impl Iterator, + pattern: &str, +) -> Vec { + use nucleo_matcher::{pattern, Config, Matcher}; + + let mut matcher = Matcher::new(Config::DEFAULT.match_paths()); + let pattern = pattern::Pattern::parse( + pattern, + pattern::CaseMatching::Ignore, + pattern::Normalization::Smart, + ); + + input + .filter(|p| { + let terms = [format!( + "{} %kind:{:?} %is_brush:{}", + p.name, + p.value.kind, + if [ui::PropertyValueKind::Color, ui::PropertyValueKind::Brush] + .contains(&p.value.kind) + { + "yes" + } else { + "no" + } + )]; + !pattern.match_list(terms.iter(), &mut matcher).is_empty() + }) + .collect::>() +} + #[cfg(test)] mod tests { use crate::preview::ui::PaletteEntry; @@ -348,4 +389,39 @@ export component Main { } compare(&result[4], "Test.palette.light.color2", 0x00, 0x11, 0x00); compare(&result[5], "Test.palette.light.color3", 0x00, 0x00, 0x11); } + + #[test] + fn test_filter_palette() { + let palette = super::collect_colors_palette(); + + assert_eq!(filter_palettes_iter(&mut palette.iter().cloned(), "'FOO").len(), 0); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "'%kind:Color").len(), + palette.len() + ); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "'%is_brush:yes").len(), + palette.len() + ); + assert_eq!(filter_palettes_iter(&mut palette.iter().cloned(), "'%kind:UNKNOWN").len(), 0); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "'Colors.aquamarine").len(), + 1 + ); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "Colors.aquamarine").len(), + 2 + ); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "Colors.aquamarine '%kind:Color") + .len(), + 2 + ); + assert_eq!(filter_palettes_iter(&mut palette.iter().cloned(), "aquamarine").len(), 2); + assert_eq!( + filter_palettes_iter(&mut palette.iter().cloned(), "^Colors.").len(), + palette.len() + ); + assert_eq!(filter_palettes_iter(&mut palette.iter().cloned(), "!^Colors.").len(), 0); + } } diff --git a/tools/lsp/ui/api.slint b/tools/lsp/ui/api.slint index c434c0be9..4dc451ad4 100644 --- a/tools/lsp/ui/api.slint +++ b/tools/lsp/ui/api.slint @@ -547,4 +547,7 @@ export global Api { // Get the property declaration/definition ranges callback property-declaration-ranges(property-name: string) -> PropertyDeclaration; + + // Palettes: + pure callback filter-palettes(palettes: [PaletteEntry], pattern: string) -> [PaletteEntry]; } diff --git a/tools/lsp/ui/components/widgets/floating-brush-sections/palettes.slint b/tools/lsp/ui/components/widgets/floating-brush-sections/palettes.slint index 4f5aecbbb..3957e209c 100644 --- a/tools/lsp/ui/components/widgets/floating-brush-sections/palettes.slint +++ b/tools/lsp/ui/components/widgets/floating-brush-sections/palettes.slint @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 import { SimpleColumn } from "../../layout-helpers.slint"; -import { Api } from "../../../api.slint"; +import { Api, PaletteEntry } from "../../../api.slint"; import { EditorSizeSettings } from "../../styling.slint"; import { ScrollView } from "std-widgets.slint"; @@ -27,16 +27,18 @@ export component PalettePicker { property rows: 9; + property <[PaletteEntry]> palette-entries: Api.filter_palettes(Api.palettes, "%is_brush:yes !^Colors."); + ScrollView { width: 100%; height: 100%; viewport-height: (Api.palettes.length / rows).floor() * 24px; - for i[index] in Api.palettes : PaletteIcon { + for i[index] in root.palette-entries : PaletteIcon { x: EditorSizeSettings.standard-margin + (index.mod(rows) * 24px); y: (index / rows).floor() * 24px; name: i.name; brush: i.value.value-brush; } } -} \ No newline at end of file +}