diff --git a/crates/channel/src/channel_buffer.rs b/crates/channel/src/channel_buffer.rs index 1aca05ec867a05e2125d451ef1b42266b765fd02..b5f4a06b972d8925735d0e692d4e682a32a19b5d 100644 --- a/crates/channel/src/channel_buffer.rs +++ b/crates/channel/src/channel_buffer.rs @@ -1,6 +1,6 @@ use crate::{Channel, ChannelId, ChannelStore}; use anyhow::Result; -use client::{Client, Collaborator, UserStore}; +use client::{Client, Collaborator, UserStore, ZED_ALWAYS_ACTIVE}; use collections::HashMap; use gpui::{AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task}; use language::proto::serialize_version; @@ -181,6 +181,16 @@ impl ChannelBuffer { ) { match event { language::Event::Operation(operation) => { + if *ZED_ALWAYS_ACTIVE { + match operation { + language::Operation::UpdateSelections { selections, .. } => { + if selections.is_empty() { + return; + } + } + _ => {} + } + } let operation = language::proto::serialize_operation(operation); self.client .send(proto::UpdateChannelBuffer { diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 75f0acd810d7e58814802b860f88ee1df254e991..dcab0e53942032045d5dcdc117e1c0e3adbe7c9e 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -635,7 +635,6 @@ impl UserStore { cx.spawn(|this, mut cx| async move { if let Some(rpc) = client.upgrade() { let response = rpc.request(request).await.context("error loading users")?; - dbg!(&response.users); let users = response .users .into_iter() diff --git a/crates/collab/src/db/queries/buffers.rs b/crates/collab/src/db/queries/buffers.rs index bdcaaab6ef62d8718d3b8903d9f16b4ce9d4b3f5..c19cd530a017fe93c89c68b4f5b814836cd1ef77 100644 --- a/crates/collab/src/db/queries/buffers.rs +++ b/crates/collab/src/db/queries/buffers.rs @@ -450,8 +450,21 @@ impl Database { )> { self.transaction(move |tx| async move { let channel = self.get_channel_internal(channel_id, &*tx).await?; - self.check_user_is_channel_member(&channel, user, &*tx) - .await?; + + let mut requires_write_permission = false; + for op in operations.iter() { + match op.variant { + None | Some(proto::operation::Variant::UpdateSelections(_)) => {} + Some(_) => requires_write_permission = true, + } + } + if requires_write_permission { + self.check_user_is_channel_member(&channel, user, &*tx) + .await?; + } else { + self.check_user_is_channel_participant(&channel, user, &*tx) + .await?; + } let buffer = buffer::Entity::find() .filter(buffer::Column::ChannelId.eq(channel_id)) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 56709fc79f12b73167040d0f6ee28f09e136d2a9..8876feeceff1daf1dfb85277d2cd958f1051544d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -368,7 +368,7 @@ pub struct Editor { collaboration_hub: Option>, blink_manager: Model, recently_focused: bool, - hovered_selections: HashSet<(ReplicaId, usize)>, + hovered_cursor: Option, pub show_local_selections: bool, mode: EditorMode, show_gutter: bool, @@ -420,6 +420,7 @@ pub struct EditorSnapshot { ongoing_scroll: OngoingScroll, } +#[derive(Debug)] pub struct RemoteSelection { pub replica_id: ReplicaId, pub selection: Selection, @@ -444,6 +445,11 @@ enum SelectionHistoryMode { Redoing, } +struct HoveredCursor { + replica_id: u16, + selection_id: usize, +} + impl Default for SelectionHistoryMode { fn default() -> Self { Self::Normal @@ -1608,7 +1614,7 @@ impl Editor { gutter_width: Default::default(), style: None, recently_focused: false, - hovered_selections: Default::default(), + hovered_cursor: Default::default(), editor_actions: Default::default(), show_copilot_suggestions: mode == EditorMode::Full, _subscriptions: vec![ @@ -8998,8 +9004,9 @@ impl Editor { } else { self.blink_manager.update(cx, BlinkManager::enable); self.recently_focused = true; + cx.notify(); cx.spawn(|this, mut cx| async move { - cx.background_executor().timer(Duration::from_secs(5)).await; + cx.background_executor().timer(Duration::from_secs(2)).await; this.update(&mut cx, |this, cx| { this.recently_focused = false; cx.notify() diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 942ca9fa64e0b40633328572cc299588f133f53d..309f6c7789ebe9853b0b6b7c6923524ac09afed8 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -567,6 +567,7 @@ impl EditorElement { cx, ); hover_at(editor, Some(point), cx); + Self::update_visible_cursor(editor, point, cx); } None => { update_inlay_link_and_hover_points( @@ -594,24 +595,28 @@ impl EditorElement { cx: &mut ViewContext, ) { let snapshot = editor.snapshot(cx); - if let Some(hub) = editor.collaboration_hub() { - let range = if point.column() > 0 { - DisplayPoint::new(point.row(), point.column() - 1)..point - } else { - point..DisplayPoint::new(point.row(), point.column() + 1) - }; - let range = snapshot + let Some(hub) = editor.collaboration_hub() else { + return; + }; + let range = DisplayPoint::new(point.row(), point.column().saturating_sub(1)) + ..DisplayPoint::new(point.row(), point.column() + 1); + + let range = snapshot + .buffer_snapshot + .anchor_at(range.start.to_point(&snapshot.display_snapshot), Bias::Left) + ..snapshot .buffer_snapshot - .anchor_at(range.start.to_point(&snapshot.display_snapshot), Bias::Left) - ..snapshot - .buffer_snapshot - .anchor_at(range.end.to_point(&snapshot.display_snapshot), Bias::Right); - for selection in snapshot.remote_selections_in_range(&range, hub, cx) { - let key = (selection.replica_id, selection.selection.id); - editor.hovered_selections.insert(key); - } - } - editor.hovered_selections.clear(); + .anchor_at(range.end.to_point(&snapshot.display_snapshot), Bias::Right); + + let Some(selection) = snapshot.remote_selections_in_range(&range, hub, cx).next() else { + editor.hovered_cursor.take(); + return; + }; + editor.hovered_cursor.replace(crate::HoveredCursor { + replica_id: selection.replica_id, + selection_id: selection.selection.id, + }); + cx.notify() } fn paint_background( @@ -1990,7 +1995,7 @@ impl EditorElement { if Some(selection.peer_id) == editor.leader_peer_id { continue; } - let id = (selection.replica_id, selection.selection.id); + let is_shown = editor.recently_focused || editor.hovered_cursor.as_ref().is_some_and(|c| c.replica_id == selection.replica_id && c.selection_id == selection.selection.id); remote_selections .entry(selection.replica_id) @@ -2003,7 +2008,7 @@ impl EditorElement { &snapshot.display_snapshot, false, false, - if editor.recently_focused || editor.hovered_selections.contains(&id) { + if is_shown { selection.user_name } else { None @@ -3209,26 +3214,20 @@ impl Cursor { fill(bounds, self.color) }; - cx.paint_quad(cursor); - - if let Some(block_text) = &self.block_text { - block_text - .paint(self.origin + origin, self.line_height, cx) - .log_err(); - } - if let Some(name) = &self.cursor_name { + let text_size = self.line_height / 1.5; + let name_origin = if name.is_top_row { point(bounds.right() - px(1.), bounds.top()) } else { - point(bounds.left(), bounds.top() - self.line_height / 4. - px(1.)) + point(bounds.left(), bounds.top() - text_size / 2. - px(1.)) }; cx.with_z_index(name.z_index, |cx| { div() .bg(self.color) - .text_size(self.line_height / 2.) + .text_size(text_size) .px_0p5() - .line_height(self.line_height / 2. + px(1.)) + .line_height(text_size + px(2.)) .text_color(name.color) .child(name.string.clone()) .into_any_element() @@ -3239,6 +3238,14 @@ impl Cursor { ) }) } + + cx.paint_quad(cursor); + + if let Some(block_text) = &self.block_text { + block_text + .paint(self.origin + origin, self.line_height, cx) + .log_err(); + } } pub fn shape(&self) -> CursorShape {