Skip to content

Commit

Permalink
Filter entities in the UI (part 8): Make the query semantics more pow…
Browse files Browse the repository at this point in the history
…erful (#8886)
  • Loading branch information
abey79 authored Feb 4, 2025
1 parent 427ac22 commit 92a5dfa
Show file tree
Hide file tree
Showing 79 changed files with 1,248 additions and 141 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6551,6 +6551,7 @@ dependencies = [
"anyhow",
"criterion",
"egui",
"insta",
"itertools 0.13.0",
"nohash-hasher",
"once_cell",
Expand Down
7 changes: 6 additions & 1 deletion crates/viewer/re_blueprint_tree/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ all-features = true

[features]
default = []
testing = ["dep:serde", "smallvec/serde", "re_viewer_context/testing"]
testing = [
"dep:serde",
"smallvec/serde",
"re_viewer_context/testing",
"re_viewport_blueprint/testing",
]


[dependencies]
Expand Down
149 changes: 74 additions & 75 deletions crates/viewer/re_blueprint_tree/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use smallvec::SmallVec;

use re_entity_db::InstancePath;
use re_log_types::external::re_types_core::ViewClassIdentifier;
use re_log_types::{EntityPath, EntityPathPart};
use re_log_types::EntityPath;
use re_types::blueprint::components::Visible;
use re_ui::filter_widget::FilterMatcher;
use re_viewer_context::{
Expand Down Expand Up @@ -367,7 +367,7 @@ impl DataResultData {
query_result: &DataQueryResult,
data_result_or_path: &DataResultNodeOrPath<'_>,
projection: bool,
hierarchy: &mut Vec<EntityPathPart>,
hierarchy: &mut Vec<String>,
filter_matcher: &FilterMatcher,
mut is_already_a_match: bool,
) -> Option<Self> {
Expand All @@ -382,9 +382,14 @@ impl DataResultData {
let data_result_node = data_result_or_path.data_result_node();
let visible = data_result_node.is_some_and(|node| node.data_result.is_visible(ctx));

let (label, should_pop) = if let Some(entity_part) = entity_path.last() {
hierarchy.push(entity_part.clone());
(entity_part.ui_string(), true)
let entity_part_ui_string = entity_path
.last()
.map(|entity_part| entity_part.ui_string());

let (label, should_pop) = if let Some(entity_part_ui_string) = entity_part_ui_string.clone()
{
hierarchy.push(entity_part_ui_string.clone());
(entity_part_ui_string, true)
} else {
("/ (root)".to_owned(), false)
};
Expand All @@ -393,77 +398,78 @@ impl DataResultData {
// Filtering
//

// TODO(ab): we're currently only matching on the last part of `hierarchy`. Technically,
// this means that `hierarchy` is not needed at all. It will however be needed when we match
// across multiple parts, so it's good to have it already.
let (entity_part_matches, highlight_sections) = if filter_matcher.matches_everything() {
// fast path (filter is inactive)
(true, SmallVec::new())
} else if let Some(entity_part) = hierarchy.last() {
// Nominal case of matching the hierarchy.
if let Some(match_sections) = filter_matcher.find_matches(&entity_part.ui_string()) {
(true, match_sections.collect())
// We must special case origin placeholder in projection. Although it does show up (as,
// well, a placeholder), it shouldn't be considered for matching as its entity part is not
// displayed.
let is_origin_placeholder = projection && entity_path == view_blueprint.space_origin;

if !is_already_a_match && !is_origin_placeholder {
let current_path_matches =
filter_matcher.matches_hierarchy(hierarchy.iter().map(|s| s.as_str()));
is_already_a_match |= current_path_matches;
}

// here are some highlights if we end up being a match
let highlight_sections = || -> SmallVec<_> {
if is_origin_placeholder {
SmallVec::new()
} else if let Some(entity_part_ui_string) = &entity_part_ui_string {
filter_matcher
.find_ranges_for_keywords(entity_part_ui_string)
.collect()
} else {
(false, SmallVec::new())
SmallVec::new()
}
} else {
// `entity_path` is the root, it can never match anything
(false, SmallVec::new())
};

// We want to keep entire branches if a single of its node matches. So we must propagate the
// "matched" state so we can make the right call when we reach leaf nodes.
is_already_a_match |= entity_part_matches;

//
// "Nominal" data result node (extracted for deduplication).
//

let view_id = view_blueprint.id;
let mut from_data_result_node = |data_result_node: &DataResultNode,
highlight_sections: SmallVec<_>,
entity_path: EntityPath,
label,
default_open| {
let mut children = data_result_node
.children
.iter()
.filter_map(|child_handle| {
let child_node = query_result.tree.lookup_node(*child_handle);

debug_assert!(
child_node.is_some(),
"DataResultNode {data_result_node:?} has an invalid child"
);

child_node.and_then(|child_node| {
Self::from_data_result_and_filter(
ctx,
view_blueprint,
query_result,
&DataResultNodeOrPath::DataResultNode(child_node),
projection,
hierarchy,
filter_matcher,
is_already_a_match,
)
let mut from_data_result_node =
|data_result_node: &DataResultNode, entity_path: EntityPath, label, default_open| {
let mut children = data_result_node
.children
.iter()
.filter_map(|child_handle| {
let child_node = query_result.tree.lookup_node(*child_handle);

debug_assert!(
child_node.is_some(),
"DataResultNode {data_result_node:?} has an invalid child"
);

child_node.and_then(|child_node| {
Self::from_data_result_and_filter(
ctx,
view_blueprint,
query_result,
&DataResultNodeOrPath::DataResultNode(child_node),
projection,
hierarchy,
filter_matcher,
is_already_a_match,
)
})
})
.collect_vec();

// This is needed because `DataResultNode` stores children in a `SmallVec`, offering
// no guarantees about ordering.
children.sort_by(|a, b| a.entity_path.cmp(&b.entity_path));

(is_already_a_match || !children.is_empty()).then(|| Self {
kind: DataResultKind::EntityPart,
entity_path,
visible,
view_id,
label,
highlight_sections: highlight_sections(),
default_open,
children,
})
.collect_vec();

children.sort_by(|a, b| a.entity_path.cmp(&b.entity_path));

(is_already_a_match || !children.is_empty()).then(|| Self {
kind: DataResultKind::EntityPart,
entity_path,
visible,
view_id,
label,
highlight_sections,
default_open,
children,
})
};
};

//
// Handle all situations
Expand All @@ -480,14 +486,13 @@ impl DataResultData {
visible,
view_id,
label,
highlight_sections,
highlight_sections: highlight_sections(),
default_open,
children: vec![],
})
} else if let Some(data_result_node) = data_result_node {
from_data_result_node(
data_result_node,
highlight_sections,
entity_path,
label,
filter_matcher.is_active(),
Expand All @@ -505,21 +510,15 @@ impl DataResultData {
visible,
view_id,
label,
highlight_sections,
highlight_sections: highlight_sections(),
default_open: false, // not hierarchical anyway
children: vec![],
})
} else if let Some(data_result_node) = data_result_node {
let default_open = filter_matcher.is_active()
|| default_open_for_data_result(data_result_node.children.len());

from_data_result_node(
data_result_node,
highlight_sections,
entity_path,
label,
default_open,
)
from_data_result_node(data_result_node, entity_path, label, default_open)
} else {
// TODO(ab): what are the circumstances for this? Should we warn about it?
None
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
source: crates/viewer/re_blueprint_tree/tests/view_structure_test.rs
expression: blueprint_tree_data
---
root_container:
id:
id: "<container-id>"
name:
Placeholder: Grid
kind: Grid
visible: true
default_open: true
children:
- View:
id:
id: 0864e1b8-cec4-1b82-5b17-b9d628b8f4fe
class_identifier: 3D
name:
Placeholder: /
visible: true
default_open: true
origin_tree:
kind: EntityPart
entity_path: []
visible: true
view_id:
id: 0864e1b8-cec4-1b82-5b17-b9d628b8f4fe
label: / (root)
highlight_sections: []
default_open: true
children:
- kind: EntityPart
entity_path:
- path
visible: true
view_id:
id: 0864e1b8-cec4-1b82-5b17-b9d628b8f4fe
label: path
highlight_sections:
- start: 1
end: 4
default_open: true
children:
- kind: EntityPart
entity_path:
- path
- to
visible: true
view_id:
id: 0864e1b8-cec4-1b82-5b17-b9d628b8f4fe
label: to
highlight_sections: []
default_open: true
children:
- kind: EntityPart
entity_path:
- path
- to
- left
visible: true
view_id:
id: 0864e1b8-cec4-1b82-5b17-b9d628b8f4fe
label: left
highlight_sections:
- start: 0
end: 4
default_open: true
children: []
projection_trees: []
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/viewer/re_blueprint_tree/tests/view_structure_test.rs
expression: blueprint_tree_data
---
root_container: ~
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/viewer/re_blueprint_tree/tests/view_structure_test.rs
expression: blueprint_tree_data
---
root_container: ~
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 92a5dfa

Please sign in to comment.