diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 29eff951d973027a96bb5ac6f8fd28981d8ebc93..97559f41a76bed36f22d3ef22bc95d913a462116 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -7,10 +7,11 @@ use anyhow::Context as _; use call::ActiveCall; use channel::{Channel, ChannelEvent, ChannelStore}; use client::{ChannelId, Client, Contact, User, UserStore}; +use collections::{HashMap, HashSet}; use contact_finder::ContactFinder; use db::kvp::KEY_VALUE_STORE; use editor::{Editor, EditorElement, EditorStyle}; -use fuzzy::{StringMatchCandidate, match_strings}; +use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ AnyElement, App, AsyncWindowContext, Bounds, ClickEvent, ClipboardItem, Context, DismissEvent, Div, Entity, EventEmitter, FocusHandle, Focusable, FontStyle, InteractiveElement, IntoElement, @@ -30,9 +31,9 @@ use smallvec::SmallVec; use std::{mem, sync::Arc}; use theme::{ActiveTheme, ThemeSettings}; use ui::{ - Avatar, AvatarAvailabilityIndicator, Button, Color, ContextMenu, Facepile, Icon, IconButton, - IconName, IconSize, Indicator, Label, ListHeader, ListItem, Tooltip, prelude::*, - tooltip_container, + Avatar, AvatarAvailabilityIndicator, Button, Color, ContextMenu, Facepile, HighlightedLabel, + Icon, IconButton, IconName, IconSize, Indicator, Label, ListHeader, ListItem, Tooltip, + prelude::*, tooltip_container, }; use util::{ResultExt, TryFutureExt, maybe}; use workspace::{ @@ -261,6 +262,8 @@ enum ListEntry { channel: Arc, depth: usize, has_children: bool, + // `None` when the channel is a parent of a matched channel. + string_match: Option, }, ChannelNotes { channel_id: ChannelId, @@ -630,6 +633,10 @@ impl CollabPanel { .enumerate() .map(|(ix, (_, channel))| StringMatchCandidate::new(ix, &channel.name)), ); + let mut channels = channel_store + .ordered_channels() + .map(|(_, chan)| chan) + .collect::>(); let matches = executor.block(match_strings( &self.match_candidates, &query, @@ -639,14 +646,34 @@ impl CollabPanel { &Default::default(), executor.clone(), )); + + let matches_by_id: HashMap<_, _> = matches + .iter() + .map(|mat| (channels[mat.candidate_id].id, mat.clone())) + .collect(); + + let channel_ids_of_matches_or_parents: HashSet<_> = matches + .iter() + .flat_map(|mat| { + let match_channel = channels[mat.candidate_id]; + + match_channel + .parent_path + .iter() + .copied() + .chain(Some(match_channel.id)) + }) + .collect(); + + channels.retain(|chan| channel_ids_of_matches_or_parents.contains(&chan.id)); + if let Some(state) = &self.channel_editing_state && matches!(state, ChannelEditingState::Create { location: None, .. }) { self.entries.push(ListEntry::ChannelEditor { depth: 0 }); } let mut collapse_depth = None; - for mat in matches { - let channel = channel_store.channel_at_index(mat.candidate_id).unwrap(); + for (idx, channel) in channels.into_iter().enumerate() { let depth = channel.parent_path.len(); if collapse_depth.is_none() && self.is_channel_collapsed(channel.id) { @@ -663,7 +690,7 @@ impl CollabPanel { } let has_children = channel_store - .channel_at_index(mat.candidate_id + 1) + .channel_at_index(idx + 1) .is_some_and(|next_channel| next_channel.parent_path.ends_with(&[channel.id])); match &self.channel_editing_state { @@ -675,6 +702,7 @@ impl CollabPanel { channel: channel.clone(), depth, has_children: false, + string_match: matches_by_id.get(&channel.id).map(|mat| (*mat).clone()), }); self.entries .push(ListEntry::ChannelEditor { depth: depth + 1 }); @@ -690,6 +718,7 @@ impl CollabPanel { channel: channel.clone(), depth, has_children, + string_match: matches_by_id.get(&channel.id).map(|mat| (*mat).clone()), }); } } @@ -2321,8 +2350,17 @@ impl CollabPanel { channel, depth, has_children, + string_match, } => self - .render_channel(channel, *depth, *has_children, is_selected, ix, cx) + .render_channel( + channel, + *depth, + *has_children, + is_selected, + ix, + string_match.as_ref(), + cx, + ) .into_any_element(), ListEntry::ChannelEditor { depth } => self .render_channel_editor(*depth, window, cx) @@ -2719,6 +2757,7 @@ impl CollabPanel { has_children: bool, is_selected: bool, ix: usize, + string_match: Option<&StringMatch>, cx: &mut Context, ) -> impl IntoElement { let channel_id = channel.id; @@ -2855,7 +2894,14 @@ impl CollabPanel { .child( h_flex() .id(channel_id.0 as usize) - .child(Label::new(channel.name.clone())) + .child(match string_match { + None => Label::new(channel.name.clone()).into_any_element(), + Some(string_match) => HighlightedLabel::new( + channel.name.clone(), + string_match.positions.clone(), + ) + .into_any_element(), + }) .children(face_pile.map(|face_pile| face_pile.p_1())), ), )