Render the DAG
This commit is contained in:
parent
3a62d2988a
commit
8222102d01
4 changed files with 227 additions and 123 deletions
|
@ -11,6 +11,7 @@ use std::{mem, sync::Arc, time::Duration};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
use self::channel_index::ChannelIndex;
|
use self::channel_index::ChannelIndex;
|
||||||
|
pub use self::channel_index::ChannelPath;
|
||||||
|
|
||||||
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
|
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
|
@ -145,11 +146,13 @@ impl ChannelStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_at_index(&self, ix: usize) -> Option<(usize, &Arc<Channel>)> {
|
pub fn channel_at_index(&self, ix: usize) -> Option<(usize, &Arc<Channel>, &Arc<[ChannelId]>)> {
|
||||||
let path = self.channel_index.get(ix)?;
|
let path = self.channel_index.get(ix)?;
|
||||||
let id = path.last().unwrap();
|
let id = path.last().unwrap();
|
||||||
let channel = self.channel_for_id(*id).unwrap();
|
let channel = self.channel_for_id(*id).unwrap();
|
||||||
Some((path.len() - 1, channel))
|
|
||||||
|
|
||||||
|
Some((path.len() - 1, channel, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_invitations(&self) -> &[Arc<Channel>] {
|
pub fn channel_invitations(&self) -> &[Arc<Channel>] {
|
||||||
|
@ -734,12 +737,15 @@ impl ChannelStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.channel_index.insert_channels(payload.channels);
|
let mut channel_index = self.channel_index.start_upsert();
|
||||||
|
for channel in payload.channels {
|
||||||
|
channel_index.upsert(channel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for edge in payload.delete_channel_edge {
|
for edge in payload.delete_channel_edge {
|
||||||
self.channel_index
|
self.channel_index
|
||||||
.remove_edge(edge.parent_id, edge.channel_id);
|
.delete_edge(edge.parent_id, edge.channel_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for permission in payload.channel_permissions {
|
for permission in payload.channel_permissions {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use std::{ops::{Deref, DerefMut}, sync::Arc};
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use rpc::proto;
|
use rpc::proto;
|
||||||
|
|
||||||
use crate::{ChannelId, Channel};
|
use crate::{ChannelId, Channel};
|
||||||
|
|
||||||
pub type ChannelPath = Vec<ChannelId>;
|
pub type ChannelPath = Arc<[ChannelId]>;
|
||||||
pub type ChannelsById = HashMap<ChannelId, Arc<Channel>>;
|
pub type ChannelsById = HashMap<ChannelId, Arc<Channel>>;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
@ -20,33 +20,6 @@ impl ChannelIndex {
|
||||||
&self.channels_by_id
|
&self.channels_by_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert or update all of the given channels into the index
|
|
||||||
pub fn insert_channels(&mut self, channels: Vec<proto::Channel>) {
|
|
||||||
let mut insert = self.insert();
|
|
||||||
|
|
||||||
for channel_proto in channels {
|
|
||||||
if let Some(existing_channel) = insert.channels_by_id.get_mut(&channel_proto.id) {
|
|
||||||
Arc::make_mut(existing_channel).name = channel_proto.name;
|
|
||||||
|
|
||||||
if let Some(parent_id) = channel_proto.parent_id {
|
|
||||||
insert.insert_edge(parent_id, channel_proto.id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let channel = Arc::new(Channel {
|
|
||||||
id: channel_proto.id,
|
|
||||||
name: channel_proto.name,
|
|
||||||
});
|
|
||||||
insert.channels_by_id.insert(channel.id, channel.clone());
|
|
||||||
|
|
||||||
if let Some(parent_id) = channel_proto.parent_id {
|
|
||||||
insert.insert_edge(parent_id, channel.id);
|
|
||||||
} else {
|
|
||||||
insert.insert_root(channel.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.paths.clear();
|
self.paths.clear();
|
||||||
self.channels_by_id.clear();
|
self.channels_by_id.clear();
|
||||||
|
@ -54,7 +27,7 @@ impl ChannelIndex {
|
||||||
|
|
||||||
/// Remove the given edge from this index. This will not remove the channel
|
/// Remove the given edge from this index. This will not remove the channel
|
||||||
/// and may result in dangling channels.
|
/// and may result in dangling channels.
|
||||||
pub fn remove_edge(&mut self, parent_id: ChannelId, channel_id: ChannelId) {
|
pub fn delete_edge(&mut self, parent_id: ChannelId, channel_id: ChannelId) {
|
||||||
self.paths.retain(|path| {
|
self.paths.retain(|path| {
|
||||||
!path
|
!path
|
||||||
.windows(2)
|
.windows(2)
|
||||||
|
@ -68,8 +41,9 @@ impl ChannelIndex {
|
||||||
self.paths.retain(|channel_path| !channel_path.iter().any(|channel_id| {channels.contains(channel_id)}))
|
self.paths.retain(|channel_path| !channel_path.iter().any(|channel_id| {channels.contains(channel_id)}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(& mut self) -> ChannelPathsInsertGuard {
|
/// Upsert one or more channels into this index.
|
||||||
ChannelPathsInsertGuard {
|
pub fn start_upsert(& mut self) -> ChannelPathsUpsertGuard {
|
||||||
|
ChannelPathsUpsertGuard {
|
||||||
paths: &mut self.paths,
|
paths: &mut self.paths,
|
||||||
channels_by_id: &mut self.channels_by_id,
|
channels_by_id: &mut self.channels_by_id,
|
||||||
}
|
}
|
||||||
|
@ -86,47 +60,54 @@ impl Deref for ChannelIndex {
|
||||||
|
|
||||||
/// A guard for ensuring that the paths index maintains its sort and uniqueness
|
/// A guard for ensuring that the paths index maintains its sort and uniqueness
|
||||||
/// invariants after a series of insertions
|
/// invariants after a series of insertions
|
||||||
struct ChannelPathsInsertGuard<'a> {
|
pub struct ChannelPathsUpsertGuard<'a> {
|
||||||
paths: &'a mut Vec<ChannelPath>,
|
paths: &'a mut Vec<ChannelPath>,
|
||||||
channels_by_id: &'a mut ChannelsById,
|
channels_by_id: &'a mut ChannelsById,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ChannelPathsInsertGuard<'_> {
|
impl<'a> ChannelPathsUpsertGuard<'a> {
|
||||||
type Target = ChannelsById;
|
pub fn upsert(&mut self, channel_proto: proto::Channel) {
|
||||||
|
if let Some(existing_channel) = self.channels_by_id.get_mut(&channel_proto.id) {
|
||||||
|
Arc::make_mut(existing_channel).name = channel_proto.name;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
if let Some(parent_id) = channel_proto.parent_id {
|
||||||
&self.channels_by_id
|
self.insert_edge(parent_id, channel_proto.id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let channel = Arc::new(Channel {
|
||||||
|
id: channel_proto.id,
|
||||||
|
name: channel_proto.name,
|
||||||
|
});
|
||||||
|
self.channels_by_id.insert(channel.id, channel.clone());
|
||||||
|
|
||||||
|
if let Some(parent_id) = channel_proto.parent_id {
|
||||||
|
self.insert_edge(parent_id, channel.id);
|
||||||
|
} else {
|
||||||
|
self.insert_root(channel.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for ChannelPathsInsertGuard<'_> {
|
fn insert_edge(&mut self, parent_id: ChannelId, channel_id: ChannelId) {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.channels_by_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> ChannelPathsInsertGuard<'a> {
|
|
||||||
pub fn insert_edge(&mut self, parent_id: ChannelId, channel_id: ChannelId) {
|
|
||||||
let mut ix = 0;
|
let mut ix = 0;
|
||||||
while ix < self.paths.len() {
|
while ix < self.paths.len() {
|
||||||
let path = &self.paths[ix];
|
let path = &self.paths[ix];
|
||||||
if path.ends_with(&[parent_id]) {
|
if path.ends_with(&[parent_id]) {
|
||||||
let mut new_path = path.clone();
|
let mut new_path = path.to_vec();
|
||||||
new_path.push(channel_id);
|
new_path.push(channel_id);
|
||||||
self.paths.insert(ix + 1, new_path);
|
self.paths.insert(ix + 1, new_path.into());
|
||||||
ix += 1;
|
ix += 1;
|
||||||
}
|
}
|
||||||
ix += 1;
|
ix += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_root(&mut self, channel_id: ChannelId) {
|
fn insert_root(&mut self, channel_id: ChannelId) {
|
||||||
self.paths.push(vec![channel_id]);
|
self.paths.push(Arc::from([channel_id]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for ChannelPathsInsertGuard<'a> {
|
impl<'a> Drop for ChannelPathsUpsertGuard<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.paths.sort_by(|a, b| {
|
self.paths.sort_by(|a, b| {
|
||||||
let a = channel_path_sorting_key(a, &self.channels_by_id);
|
let a = channel_path_sorting_key(a, &self.channels_by_id);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use channel::{Channel, ChannelEvent, ChannelId, ChannelStore};
|
use channel::{Channel, ChannelEvent, ChannelId, ChannelStore, ChannelPath};
|
||||||
use channel_modal::ChannelModal;
|
use channel_modal::ChannelModal;
|
||||||
use client::{proto::PeerId, Client, Contact, User, UserStore};
|
use client::{proto::PeerId, Client, Contact, User, UserStore};
|
||||||
use contact_finder::ContactFinder;
|
use contact_finder::ContactFinder;
|
||||||
|
@ -40,7 +40,7 @@ use menu::{Confirm, SelectNext, SelectPrev};
|
||||||
use project::{Fs, Project};
|
use project::{Fs, Project};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
use std::{borrow::Cow, mem, sync::Arc};
|
use std::{borrow::Cow, mem, sync::Arc, hash::Hash};
|
||||||
use theme::{components::ComponentExt, IconButton};
|
use theme::{components::ComponentExt, IconButton};
|
||||||
use util::{iife, ResultExt, TryFutureExt};
|
use util::{iife, ResultExt, TryFutureExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
|
@ -51,32 +51,32 @@ use workspace::{
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct RemoveChannel {
|
struct RemoveChannel {
|
||||||
channel_id: u64,
|
channel_id: ChannelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct ToggleCollapse {
|
struct ToggleCollapse {
|
||||||
channel_id: u64,
|
location: ChannelLocation<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct NewChannel {
|
struct NewChannel {
|
||||||
channel_id: u64,
|
location: ChannelLocation<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct InviteMembers {
|
struct InviteMembers {
|
||||||
channel_id: u64,
|
channel_id: ChannelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct ManageMembers {
|
struct ManageMembers {
|
||||||
channel_id: u64,
|
channel_id: ChannelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct RenameChannel {
|
struct RenameChannel {
|
||||||
channel_id: u64,
|
location: ChannelLocation<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
@ -89,6 +89,26 @@ pub struct JoinChannelCall {
|
||||||
pub channel_id: u64,
|
pub channel_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct OpenChannelBuffer {
|
||||||
|
channel_id: ChannelId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct CopyChannel {
|
||||||
|
channel_id: ChannelId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct CutChannel {
|
||||||
|
channel_id: ChannelId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct PasteChannel {
|
||||||
|
channel_id: ChannelId,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
collab_panel,
|
collab_panel,
|
||||||
[
|
[
|
||||||
|
@ -111,12 +131,35 @@ impl_actions!(
|
||||||
ToggleCollapse,
|
ToggleCollapse,
|
||||||
OpenChannelNotes,
|
OpenChannelNotes,
|
||||||
JoinChannelCall,
|
JoinChannelCall,
|
||||||
|
OpenChannelBuffer,
|
||||||
|
CopyChannel,
|
||||||
|
CutChannel,
|
||||||
|
PasteChannel,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
|
const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct ChannelLocation<'a> {
|
||||||
|
channel: ChannelId,
|
||||||
|
parent: Cow<'a, ChannelPath>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(ChannelId, ChannelPath)> for ChannelLocation<'static> {
|
||||||
|
fn from(value: (ChannelId, ChannelPath)) -> Self {
|
||||||
|
ChannelLocation { channel: value.0, parent: Cow::Owned(value.1) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<(ChannelId, &'a ChannelPath)> for ChannelLocation<'a> {
|
||||||
|
fn from(value: (ChannelId, &'a ChannelPath)) -> Self {
|
||||||
|
ChannelLocation { channel: value.0, parent: Cow::Borrowed(value.1) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
|
settings::register::<panel_settings::CollaborationPanelSettings>(cx);
|
||||||
contact_finder::init(cx);
|
contact_finder::init(cx);
|
||||||
channel_modal::init(cx);
|
channel_modal::init(cx);
|
||||||
channel_view::init(cx);
|
channel_view::init(cx);
|
||||||
|
@ -137,16 +180,37 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(CollabPanel::collapse_selected_channel);
|
cx.add_action(CollabPanel::collapse_selected_channel);
|
||||||
cx.add_action(CollabPanel::expand_selected_channel);
|
cx.add_action(CollabPanel::expand_selected_channel);
|
||||||
cx.add_action(CollabPanel::open_channel_notes);
|
cx.add_action(CollabPanel::open_channel_notes);
|
||||||
|
cx.add_action(CollabPanel::open_channel_buffer);
|
||||||
|
|
||||||
|
cx.add_action(|panel: &mut CollabPanel, action: &CopyChannel, _: &mut ViewContext<CollabPanel>| {
|
||||||
|
panel.copy = Some(ChannelCopy::Copy(action.channel_id));
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.add_action(|panel: &mut CollabPanel, action: &CutChannel, _: &mut ViewContext<CollabPanel>| {
|
||||||
|
// panel.copy = Some(ChannelCopy::Cut(action.channel_id));
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.add_action(|panel: &mut CollabPanel, action: &PasteChannel, cx: &mut ViewContext<CollabPanel>| {
|
||||||
|
if let Some(copy) = &panel.copy {
|
||||||
|
match copy {
|
||||||
|
ChannelCopy::Cut {..} => todo!(),
|
||||||
|
ChannelCopy::Copy(channel) => panel.channel_store.update(cx, |channel_store, cx| {
|
||||||
|
channel_store.move_channel(*channel, None, Some(action.channel_id), cx).detach_and_log_err(cx)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ChannelEditingState {
|
pub enum ChannelEditingState {
|
||||||
Create {
|
Create {
|
||||||
parent_id: Option<u64>,
|
location: Option<ChannelLocation<'static>>,
|
||||||
pending_name: Option<String>,
|
pending_name: Option<String>,
|
||||||
},
|
},
|
||||||
Rename {
|
Rename {
|
||||||
channel_id: u64,
|
location: ChannelLocation<'static>,
|
||||||
pending_name: Option<String>,
|
pending_name: Option<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -160,10 +224,19 @@ impl ChannelEditingState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ChannelCopy {
|
||||||
|
Cut {
|
||||||
|
channel_id: u64,
|
||||||
|
parent_id: Option<u64>,
|
||||||
|
},
|
||||||
|
Copy(u64),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CollabPanel {
|
pub struct CollabPanel {
|
||||||
width: Option<f32>,
|
width: Option<f32>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
has_focus: bool,
|
has_focus: bool,
|
||||||
|
copy: Option<ChannelCopy>,
|
||||||
pending_serialization: Task<Option<()>>,
|
pending_serialization: Task<Option<()>>,
|
||||||
context_menu: ViewHandle<ContextMenu>,
|
context_menu: ViewHandle<ContextMenu>,
|
||||||
filter_editor: ViewHandle<Editor>,
|
filter_editor: ViewHandle<Editor>,
|
||||||
|
@ -179,7 +252,7 @@ pub struct CollabPanel {
|
||||||
list_state: ListState<Self>,
|
list_state: ListState<Self>,
|
||||||
subscriptions: Vec<Subscription>,
|
subscriptions: Vec<Subscription>,
|
||||||
collapsed_sections: Vec<Section>,
|
collapsed_sections: Vec<Section>,
|
||||||
collapsed_channels: Vec<ChannelId>,
|
collapsed_channels: Vec<ChannelLocation<'static>>,
|
||||||
workspace: WeakViewHandle<Workspace>,
|
workspace: WeakViewHandle<Workspace>,
|
||||||
context_menu_on_selected: bool,
|
context_menu_on_selected: bool,
|
||||||
}
|
}
|
||||||
|
@ -187,7 +260,7 @@ pub struct CollabPanel {
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct SerializedCollabPanel {
|
struct SerializedCollabPanel {
|
||||||
width: Option<f32>,
|
width: Option<f32>,
|
||||||
collapsed_channels: Option<Vec<ChannelId>>,
|
collapsed_channels: Option<Vec<ChannelLocation<'static>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -231,6 +304,7 @@ enum ListEntry {
|
||||||
Channel {
|
Channel {
|
||||||
channel: Arc<Channel>,
|
channel: Arc<Channel>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
|
path: Arc<[ChannelId]>,
|
||||||
},
|
},
|
||||||
ChannelNotes {
|
ChannelNotes {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
@ -348,10 +422,11 @@ impl CollabPanel {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ListEntry::Channel { channel, depth } => {
|
ListEntry::Channel { channel, depth, path } => {
|
||||||
let channel_row = this.render_channel(
|
let channel_row = this.render_channel(
|
||||||
&*channel,
|
&*channel,
|
||||||
*depth,
|
*depth,
|
||||||
|
path.to_owned(),
|
||||||
&theme.collab_panel,
|
&theme.collab_panel,
|
||||||
is_selected,
|
is_selected,
|
||||||
cx,
|
cx,
|
||||||
|
@ -420,6 +495,7 @@ impl CollabPanel {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
width: None,
|
width: None,
|
||||||
has_focus: false,
|
has_focus: false,
|
||||||
|
copy: None,
|
||||||
fs: workspace.app_state().fs.clone(),
|
fs: workspace.app_state().fs.clone(),
|
||||||
pending_serialization: Task::ready(None),
|
pending_serialization: Task::ready(None),
|
||||||
context_menu: cx.add_view(|cx| ContextMenu::new(view_id, cx)),
|
context_menu: cx.add_view(|cx| ContextMenu::new(view_id, cx)),
|
||||||
|
@ -700,7 +776,7 @@ impl CollabPanel {
|
||||||
if matches!(
|
if matches!(
|
||||||
state,
|
state,
|
||||||
ChannelEditingState::Create {
|
ChannelEditingState::Create {
|
||||||
parent_id: None,
|
location: None,
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -709,16 +785,18 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
let mut collapse_depth = None;
|
let mut collapse_depth = None;
|
||||||
for mat in matches {
|
for mat in matches {
|
||||||
let (depth, channel) =
|
let (depth, channel, path) =
|
||||||
channel_store.channel_at_index(mat.candidate_id).unwrap();
|
channel_store.channel_at_index(mat.candidate_id).unwrap();
|
||||||
|
|
||||||
if collapse_depth.is_none() && self.is_channel_collapsed(channel.id) {
|
let location: ChannelLocation<'_> = (channel.id, path).into();
|
||||||
|
|
||||||
|
if collapse_depth.is_none() && self.is_channel_collapsed(&location) {
|
||||||
collapse_depth = Some(depth);
|
collapse_depth = Some(depth);
|
||||||
} else if let Some(collapsed_depth) = collapse_depth {
|
} else if let Some(collapsed_depth) = collapse_depth {
|
||||||
if depth > collapsed_depth {
|
if depth > collapsed_depth {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if self.is_channel_collapsed(channel.id) {
|
if self.is_channel_collapsed(&location) {
|
||||||
collapse_depth = Some(depth);
|
collapse_depth = Some(depth);
|
||||||
} else {
|
} else {
|
||||||
collapse_depth = None;
|
collapse_depth = None;
|
||||||
|
@ -726,18 +804,19 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
match &self.channel_editing_state {
|
match &self.channel_editing_state {
|
||||||
Some(ChannelEditingState::Create { parent_id, .. })
|
Some(ChannelEditingState::Create { location: parent_id, .. })
|
||||||
if *parent_id == Some(channel.id) =>
|
if *parent_id == Some(location) =>
|
||||||
{
|
{
|
||||||
self.entries.push(ListEntry::Channel {
|
self.entries.push(ListEntry::Channel {
|
||||||
channel: channel.clone(),
|
channel: channel.clone(),
|
||||||
depth,
|
depth,
|
||||||
|
path: path.clone(),
|
||||||
});
|
});
|
||||||
self.entries
|
self.entries
|
||||||
.push(ListEntry::ChannelEditor { depth: depth + 1 });
|
.push(ListEntry::ChannelEditor { depth: depth + 1 });
|
||||||
}
|
}
|
||||||
Some(ChannelEditingState::Rename { channel_id, .. })
|
Some(ChannelEditingState::Rename { location, .. })
|
||||||
if *channel_id == channel.id =>
|
if location.channel == channel.id && location.parent == Cow::Borrowed(path) =>
|
||||||
{
|
{
|
||||||
self.entries.push(ListEntry::ChannelEditor { depth });
|
self.entries.push(ListEntry::ChannelEditor { depth });
|
||||||
}
|
}
|
||||||
|
@ -745,6 +824,7 @@ impl CollabPanel {
|
||||||
self.entries.push(ListEntry::Channel {
|
self.entries.push(ListEntry::Channel {
|
||||||
channel: channel.clone(),
|
channel: channel.clone(),
|
||||||
depth,
|
depth,
|
||||||
|
path: path.clone()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1546,14 +1626,21 @@ impl CollabPanel {
|
||||||
&self,
|
&self,
|
||||||
channel: &Channel,
|
channel: &Channel,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
|
path: ChannelPath,
|
||||||
theme: &theme::CollabPanel,
|
theme: &theme::CollabPanel,
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> AnyElement<Self> {
|
) -> AnyElement<Self> {
|
||||||
let channel_id = channel.id;
|
let channel_id = channel.id;
|
||||||
let has_children = self.channel_store.read(cx).has_children(channel_id);
|
let has_children = self.channel_store.read(cx).has_children(channel_id);
|
||||||
let disclosed =
|
|
||||||
has_children.then(|| !self.collapsed_channels.binary_search(&channel_id).is_ok());
|
let disclosed = {
|
||||||
|
let location = ChannelLocation {
|
||||||
|
channel: channel_id,
|
||||||
|
parent: Cow::Borrowed(&path),
|
||||||
|
};
|
||||||
|
has_children.then(|| !self.collapsed_channels.binary_search(&location).is_ok())
|
||||||
|
};
|
||||||
|
|
||||||
let is_active = iife!({
|
let is_active = iife!({
|
||||||
let call_channel = ActiveCall::global(cx)
|
let call_channel = ActiveCall::global(cx)
|
||||||
|
@ -1569,7 +1656,7 @@ impl CollabPanel {
|
||||||
|
|
||||||
enum ChannelCall {}
|
enum ChannelCall {}
|
||||||
|
|
||||||
MouseEventHandler::new::<Channel, _>(channel.id as usize, cx, |state, cx| {
|
MouseEventHandler::new::<Channel, _>(id(&path) as usize, cx, |state, cx| {
|
||||||
let row_hovered = state.hovered();
|
let row_hovered = state.hovered();
|
||||||
|
|
||||||
Flex::<Self>::row()
|
Flex::<Self>::row()
|
||||||
|
@ -1637,8 +1724,8 @@ impl CollabPanel {
|
||||||
)
|
)
|
||||||
.align_children_center()
|
.align_children_center()
|
||||||
.styleable_component()
|
.styleable_component()
|
||||||
.disclosable(disclosed, Box::new(ToggleCollapse { channel_id }))
|
.disclosable(disclosed, Box::new(ToggleCollapse { location: (channel_id, path.clone()).into() }))
|
||||||
.with_id(channel_id as usize)
|
.with_id(id(&path) as usize)
|
||||||
.with_style(theme.disclosure.clone())
|
.with_style(theme.disclosure.clone())
|
||||||
.element()
|
.element()
|
||||||
.constrained()
|
.constrained()
|
||||||
|
@ -1654,7 +1741,7 @@ impl CollabPanel {
|
||||||
this.join_channel_chat(channel_id, cx);
|
this.join_channel_chat(channel_id, cx);
|
||||||
})
|
})
|
||||||
.on_click(MouseButton::Right, move |e, this, cx| {
|
.on_click(MouseButton::Right, move |e, this, cx| {
|
||||||
this.deploy_channel_context_menu(Some(e.position), channel_id, cx);
|
this.deploy_channel_context_menu(Some(e.position), &(channel_id, path.clone()).into(), cx);
|
||||||
})
|
})
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
@ -1901,7 +1988,7 @@ impl CollabPanel {
|
||||||
fn deploy_channel_context_menu(
|
fn deploy_channel_context_menu(
|
||||||
&mut self,
|
&mut self,
|
||||||
position: Option<Vector2F>,
|
position: Option<Vector2F>,
|
||||||
channel_id: u64,
|
location: &ChannelLocation<'static>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
self.context_menu_on_selected = position.is_none();
|
self.context_menu_on_selected = position.is_none();
|
||||||
|
@ -1913,27 +2000,29 @@ impl CollabPanel {
|
||||||
OverlayPositionMode::Window
|
OverlayPositionMode::Window
|
||||||
});
|
});
|
||||||
|
|
||||||
let expand_action_name = if self.is_channel_collapsed(channel_id) {
|
let expand_action_name = if self.is_channel_collapsed(&location) {
|
||||||
"Expand Subchannels"
|
"Expand Subchannels"
|
||||||
} else {
|
} else {
|
||||||
"Collapse Subchannels"
|
"Collapse Subchannels"
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut items = vec![
|
let mut items = vec![
|
||||||
ContextMenuItem::action(expand_action_name, ToggleCollapse { channel_id }),
|
ContextMenuItem::action(expand_action_name, ToggleCollapse { location: location.clone() }),
|
||||||
ContextMenuItem::action("Open Notes", OpenChannelNotes { channel_id }),
|
ContextMenuItem::action("Open Notes", OpenChannelBuffer { channel_id: location.channel }),
|
||||||
];
|
];
|
||||||
|
|
||||||
if self.channel_store.read(cx).is_user_admin(channel_id) {
|
if self.channel_store.read(cx).is_user_admin(location.channel) {
|
||||||
items.extend([
|
items.extend([
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("New Subchannel", NewChannel { channel_id }),
|
ContextMenuItem::action("New Subchannel", NewChannel { location: location.clone() }),
|
||||||
ContextMenuItem::action("Rename", RenameChannel { channel_id }),
|
ContextMenuItem::action("Rename", RenameChannel { location: location.clone() }),
|
||||||
|
ContextMenuItem::action("Copy", CopyChannel { channel_id: location.channel }),
|
||||||
|
ContextMenuItem::action("Paste", PasteChannel { channel_id: location.channel }),
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("Invite Members", InviteMembers { channel_id }),
|
ContextMenuItem::action("Invite Members", InviteMembers { channel_id: location.channel }),
|
||||||
ContextMenuItem::action("Manage Members", ManageMembers { channel_id }),
|
ContextMenuItem::action("Manage Members", ManageMembers { channel_id: location.channel }),
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("Delete", RemoveChannel { channel_id }),
|
ContextMenuItem::action("Delete", RemoveChannel { channel_id: location.channel }),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2059,7 +2148,7 @@ impl CollabPanel {
|
||||||
if let Some(editing_state) = &mut self.channel_editing_state {
|
if let Some(editing_state) = &mut self.channel_editing_state {
|
||||||
match editing_state {
|
match editing_state {
|
||||||
ChannelEditingState::Create {
|
ChannelEditingState::Create {
|
||||||
parent_id,
|
location,
|
||||||
pending_name,
|
pending_name,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -2072,13 +2161,13 @@ impl CollabPanel {
|
||||||
|
|
||||||
self.channel_store
|
self.channel_store
|
||||||
.update(cx, |channel_store, cx| {
|
.update(cx, |channel_store, cx| {
|
||||||
channel_store.create_channel(&channel_name, *parent_id, cx)
|
channel_store.create_channel(&channel_name, location.as_ref().map(|location| location.channel), cx)
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
ChannelEditingState::Rename {
|
ChannelEditingState::Rename {
|
||||||
channel_id,
|
location,
|
||||||
pending_name,
|
pending_name,
|
||||||
} => {
|
} => {
|
||||||
if pending_name.is_some() {
|
if pending_name.is_some() {
|
||||||
|
@ -2089,7 +2178,7 @@ impl CollabPanel {
|
||||||
|
|
||||||
self.channel_store
|
self.channel_store
|
||||||
.update(cx, |channel_store, cx| {
|
.update(cx, |channel_store, cx| {
|
||||||
channel_store.rename(*channel_id, &channel_name, cx)
|
channel_store.rename(location.channel, &channel_name, cx)
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -2116,38 +2205,42 @@ impl CollabPanel {
|
||||||
_: &CollapseSelectedChannel,
|
_: &CollapseSelectedChannel,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let Some(channel_id) = self.selected_channel().map(|channel| channel.id) else {
|
let Some((channel_id, path)) = self.selected_channel().map(|(channel, parent)| (channel.id, parent)) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.is_channel_collapsed(channel_id) {
|
let path = path.to_owned();
|
||||||
|
|
||||||
|
if self.is_channel_collapsed(&(channel_id, path.clone()).into()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toggle_channel_collapsed(&ToggleCollapse { channel_id }, cx)
|
self.toggle_channel_collapsed(&ToggleCollapse { location: (channel_id, path).into() }, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext<Self>) {
|
fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext<Self>) {
|
||||||
let Some(channel_id) = self.selected_channel().map(|channel| channel.id) else {
|
let Some((channel_id, path)) = self.selected_channel().map(|(channel, parent)| (channel.id, parent)) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.is_channel_collapsed(channel_id) {
|
let path = path.to_owned();
|
||||||
|
|
||||||
|
if !self.is_channel_collapsed(&(channel_id, path.clone()).into()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toggle_channel_collapsed(&ToggleCollapse { channel_id }, cx)
|
self.toggle_channel_collapsed(&ToggleCollapse { location: (channel_id, path).into() }, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapse, cx: &mut ViewContext<Self>) {
|
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapse, cx: &mut ViewContext<Self>) {
|
||||||
let channel_id = action.channel_id;
|
let location = action.location.clone();
|
||||||
|
|
||||||
match self.collapsed_channels.binary_search(&channel_id) {
|
match self.collapsed_channels.binary_search(&location) {
|
||||||
Ok(ix) => {
|
Ok(ix) => {
|
||||||
self.collapsed_channels.remove(ix);
|
self.collapsed_channels.remove(ix);
|
||||||
}
|
}
|
||||||
Err(ix) => {
|
Err(ix) => {
|
||||||
self.collapsed_channels.insert(ix, channel_id);
|
self.collapsed_channels.insert(ix, location);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.serialize(cx);
|
self.serialize(cx);
|
||||||
|
@ -2156,8 +2249,8 @@ impl CollabPanel {
|
||||||
cx.focus_self();
|
cx.focus_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_channel_collapsed(&self, channel: ChannelId) -> bool {
|
fn is_channel_collapsed(&self, location: &ChannelLocation) -> bool {
|
||||||
self.collapsed_channels.binary_search(&channel).is_ok()
|
self.collapsed_channels.binary_search(location).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave_call(cx: &mut ViewContext<Self>) {
|
fn leave_call(cx: &mut ViewContext<Self>) {
|
||||||
|
@ -2182,7 +2275,7 @@ impl CollabPanel {
|
||||||
|
|
||||||
fn new_root_channel(&mut self, cx: &mut ViewContext<Self>) {
|
fn new_root_channel(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.channel_editing_state = Some(ChannelEditingState::Create {
|
self.channel_editing_state = Some(ChannelEditingState::Create {
|
||||||
parent_id: None,
|
location: None,
|
||||||
pending_name: None,
|
pending_name: None,
|
||||||
});
|
});
|
||||||
self.update_entries(false, cx);
|
self.update_entries(false, cx);
|
||||||
|
@ -2200,9 +2293,9 @@ impl CollabPanel {
|
||||||
|
|
||||||
fn new_subchannel(&mut self, action: &NewChannel, cx: &mut ViewContext<Self>) {
|
fn new_subchannel(&mut self, action: &NewChannel, cx: &mut ViewContext<Self>) {
|
||||||
self.collapsed_channels
|
self.collapsed_channels
|
||||||
.retain(|&channel| channel != action.channel_id);
|
.retain(|channel| *channel != action.location);
|
||||||
self.channel_editing_state = Some(ChannelEditingState::Create {
|
self.channel_editing_state = Some(ChannelEditingState::Create {
|
||||||
parent_id: Some(action.channel_id),
|
location: Some(action.location.to_owned()),
|
||||||
pending_name: None,
|
pending_name: None,
|
||||||
});
|
});
|
||||||
self.update_entries(false, cx);
|
self.update_entries(false, cx);
|
||||||
|
@ -2220,16 +2313,16 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, _: &Remove, cx: &mut ViewContext<Self>) {
|
fn remove(&mut self, _: &Remove, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(channel) = self.selected_channel() {
|
if let Some((channel, _)) = self.selected_channel() {
|
||||||
self.remove_channel(channel.id, cx)
|
self.remove_channel(channel.id, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rename_selected_channel(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext<Self>) {
|
fn rename_selected_channel(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(channel) = self.selected_channel() {
|
if let Some((channel, parent)) = self.selected_channel() {
|
||||||
self.rename_channel(
|
self.rename_channel(
|
||||||
&RenameChannel {
|
&RenameChannel {
|
||||||
channel_id: channel.id,
|
location: (channel.id, parent.to_owned()).into(),
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -2238,12 +2331,12 @@ impl CollabPanel {
|
||||||
|
|
||||||
fn rename_channel(&mut self, action: &RenameChannel, cx: &mut ViewContext<Self>) {
|
fn rename_channel(&mut self, action: &RenameChannel, cx: &mut ViewContext<Self>) {
|
||||||
let channel_store = self.channel_store.read(cx);
|
let channel_store = self.channel_store.read(cx);
|
||||||
if !channel_store.is_user_admin(action.channel_id) {
|
if !channel_store.is_user_admin(action.location.channel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(channel) = channel_store.channel_for_id(action.channel_id).cloned() {
|
if let Some(channel) = channel_store.channel_for_id(action.location.channel).cloned() {
|
||||||
self.channel_editing_state = Some(ChannelEditingState::Rename {
|
self.channel_editing_state = Some(ChannelEditingState::Rename {
|
||||||
channel_id: action.channel_id,
|
location: action.location.to_owned(),
|
||||||
pending_name: None,
|
pending_name: None,
|
||||||
});
|
});
|
||||||
self.channel_name_editor.update(cx, |editor, cx| {
|
self.channel_name_editor.update(cx, |editor, cx| {
|
||||||
|
@ -2263,18 +2356,18 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_inline_context_menu(&mut self, _: &menu::ShowContextMenu, cx: &mut ViewContext<Self>) {
|
fn show_inline_context_menu(&mut self, _: &menu::ShowContextMenu, cx: &mut ViewContext<Self>) {
|
||||||
let Some(channel) = self.selected_channel() else {
|
let Some((channel, path)) = self.selected_channel() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.deploy_channel_context_menu(None, channel.id, cx);
|
self.deploy_channel_context_menu(None, &(channel.id, path.to_owned()).into(), cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected_channel(&self) -> Option<&Arc<Channel>> {
|
fn selected_channel(&self) -> Option<(&Arc<Channel>, &ChannelPath)> {
|
||||||
self.selection
|
self.selection
|
||||||
.and_then(|ix| self.entries.get(ix))
|
.and_then(|ix| self.entries.get(ix))
|
||||||
.and_then(|entry| match entry {
|
.and_then(|entry| match entry {
|
||||||
ListEntry::Channel { channel, .. } => Some(channel),
|
ListEntry::Channel { channel, path: parent, .. } => Some((channel, parent)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2657,13 +2750,15 @@ impl PartialEq for ListEntry {
|
||||||
ListEntry::Channel {
|
ListEntry::Channel {
|
||||||
channel: channel_1,
|
channel: channel_1,
|
||||||
depth: depth_1,
|
depth: depth_1,
|
||||||
|
path: parent_1,
|
||||||
} => {
|
} => {
|
||||||
if let ListEntry::Channel {
|
if let ListEntry::Channel {
|
||||||
channel: channel_2,
|
channel: channel_2,
|
||||||
depth: depth_2,
|
depth: depth_2,
|
||||||
|
path: parent_2,
|
||||||
} = other
|
} = other
|
||||||
{
|
{
|
||||||
return channel_1.id == channel_2.id && depth_1 == depth_2;
|
return channel_1.id == channel_2.id && depth_1 == depth_2 && parent_1 == parent_2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListEntry::ChannelNotes { channel_id } => {
|
ListEntry::ChannelNotes { channel_id } => {
|
||||||
|
@ -2726,3 +2821,26 @@ fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Elemen
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(style.container)
|
.with_style(style.container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Hash a channel path to a u64, for use as a mouse id
|
||||||
|
/// Based on the Fowler–Noll–Vo hash:
|
||||||
|
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||||
|
fn id(path: &[ChannelId]) -> u64 {
|
||||||
|
// I probably should have done this, but I didn't
|
||||||
|
// let hasher = DefaultHasher::new();
|
||||||
|
// let path = path.hash(&mut hasher);
|
||||||
|
// let x = hasher.finish();
|
||||||
|
|
||||||
|
const OFFSET: u64 = 14695981039346656037;
|
||||||
|
const PRIME: u64 = 1099511628211;
|
||||||
|
|
||||||
|
let mut hash = OFFSET;
|
||||||
|
for id in path.iter() {
|
||||||
|
for id in id.to_ne_bytes() {
|
||||||
|
hash = hash ^ (id as u64);
|
||||||
|
hash = (hash as u128 * PRIME as u128) as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
|
|
@ -328,7 +328,6 @@ request_messages!(
|
||||||
(GetChannelMessages, GetChannelMessagesResponse),
|
(GetChannelMessages, GetChannelMessagesResponse),
|
||||||
(GetChannelMembers, GetChannelMembersResponse),
|
(GetChannelMembers, GetChannelMembersResponse),
|
||||||
(JoinChannel, JoinRoomResponse),
|
(JoinChannel, JoinRoomResponse),
|
||||||
(RemoveChannel, Ack),
|
|
||||||
(RemoveChannelMessage, Ack),
|
(RemoveChannelMessage, Ack),
|
||||||
(DeleteChannel, Ack),
|
(DeleteChannel, Ack),
|
||||||
(RenameProjectEntry, ProjectEntryResponse),
|
(RenameProjectEntry, ProjectEntryResponse),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue