From d20ed0aacfb7ca13eef23f21ca4a94128791ea1e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 11 Jan 2024 20:21:41 -0700 Subject: [PATCH 01/31] Try sqwauk --- .github/actions/check_style/action.yml | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/actions/check_style/action.yml b/.github/actions/check_style/action.yml index 5dc7c42b02..e6eed28b66 100644 --- a/.github/actions/check_style/action.yml +++ b/.github/actions/check_style/action.yml @@ -2,16 +2,26 @@ name: "Check formatting" description: "Checks code formatting use cargo fmt" runs: - using: "composite" - steps: - - name: cargo fmt - shell: bash -euxo pipefail {0} - run: cargo fmt --all -- --check + using: "composite" + steps: + - name: cargo fmt + shell: bash -euxo pipefail {0} + run: cargo fmt --all -- --check - - name: cargo clippy - shell: bash -euxo pipefail {0} - # clippy.toml is not currently supporting specifying allowed lints - # so specify those here, and disable the rest until Zed's workspace - # will have more fixes & suppression for the standard lint set - run: | - cargo clippy --workspace --all-features --all-targets -- -A clippy::all -D clippy::dbg_macro -D clippy::todo + - name: cargo clippy + shell: bash -euxo pipefail {0} + # clippy.toml is not currently supporting specifying allowed lints + # so specify those here, and disable the rest until Zed's workspace + # will have more fixes & suppression for the standard lint set + run: | + cargo clippy --workspace --all-features --all-targets -- -A clippy::all -D clippy::dbg_macro -D clippy::todo + + - name: Find modified migrations + shell: bash -euxo pipefail {0} + run: | + modified_migrations=$(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'crate/collab/migrations/*.sql') + echo "::set-output name=file_names::$modified_migrations" + id: modified-migrations + - uses: sbdchd/squawk-action@v1 + with: + pattern: ${{ steps.modified-migrations.outputs.file_names }} From 403fa7fbc90572653ccc6a3cabc57c708e986f4b Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 11 Jan 2024 20:40:34 -0700 Subject: [PATCH 02/31] Try the manual approach... --- .github/actions/check_style/action.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/actions/check_style/action.yml b/.github/actions/check_style/action.yml index e6eed28b66..3174376736 100644 --- a/.github/actions/check_style/action.yml +++ b/.github/actions/check_style/action.yml @@ -19,9 +19,11 @@ runs: - name: Find modified migrations shell: bash -euxo pipefail {0} run: | + cargo install squawk --git https://github.com/sbdchd/squawk --tag v0.26.0 modified_migrations=$(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'crate/collab/migrations/*.sql') - echo "::set-output name=file_names::$modified_migrations" - id: modified-migrations - - uses: sbdchd/squawk-action@v1 - with: - pattern: ${{ steps.modified-migrations.outputs.file_names }} + + SQUAWK_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} + SQUAWK_GITHUB_REPO_OWNER=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $1}') + SQUAWK_GITHUB_REPO_NAME=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $2}') + SQUAWK_GITHUB_PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }') + squawk upload-to-github $(modified_migrations) From 51e4db7d702fee06724bc1e4644871ee5ed6c959 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 11 Jan 2024 20:43:49 -0700 Subject: [PATCH 03/31] try again --- .github/actions/check_style/action.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/actions/check_style/action.yml b/.github/actions/check_style/action.yml index 3174376736..d2f648ea8f 100644 --- a/.github/actions/check_style/action.yml +++ b/.github/actions/check_style/action.yml @@ -21,8 +21,7 @@ runs: run: | cargo install squawk --git https://github.com/sbdchd/squawk --tag v0.26.0 modified_migrations=$(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'crate/collab/migrations/*.sql') - - SQUAWK_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} + SQUAWK_GITHUB_TOKEN=${{ github.token }} SQUAWK_GITHUB_REPO_OWNER=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $1}') SQUAWK_GITHUB_REPO_NAME=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $2}') SQUAWK_GITHUB_PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }') From 87ccbf6c19223da70318dd3ff5ecea5ad533db51 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 11 Jan 2024 21:09:50 -0700 Subject: [PATCH 04/31] One of these days... --- .github/actions/check_style/action.yml | 9 ++------- script/squawk | 27 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100755 script/squawk diff --git a/.github/actions/check_style/action.yml b/.github/actions/check_style/action.yml index d2f648ea8f..25020e4e4c 100644 --- a/.github/actions/check_style/action.yml +++ b/.github/actions/check_style/action.yml @@ -19,10 +19,5 @@ runs: - name: Find modified migrations shell: bash -euxo pipefail {0} run: | - cargo install squawk --git https://github.com/sbdchd/squawk --tag v0.26.0 - modified_migrations=$(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'crate/collab/migrations/*.sql') - SQUAWK_GITHUB_TOKEN=${{ github.token }} - SQUAWK_GITHUB_REPO_OWNER=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $1}') - SQUAWK_GITHUB_REPO_NAME=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $2}') - SQUAWK_GITHUB_PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }') - squawk upload-to-github $(modified_migrations) + export SQUAWK_GITHUB_TOKEN=${{ github.token }} + . ./script/squawk diff --git a/script/squawk b/script/squawk new file mode 100755 index 0000000000..e4ade6fbed --- /dev/null +++ b/script/squawk @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Squawk is a linter for database migrations. It helps identify dangerous patterns, and suggests alternatives. +# Squawk flagging an error does not mean that you need to take a different approach, but it does indicate you need to think about what you're doing. +# See also: https://squawkhq.com + +set -e + +SQUAWK_VERSION=0.26.0 +SQUAWK_BIN="./target/squawk-$SQUAWK_VERSION" +SQUAWK_ARGS="--assume-in-transaction" + + +if [ ! -f "$SQUAWK_BIN" ]; then + curl -L -o "$SQUAWK_BIN" "https://github.com/sbdchd/squawk/releases/download/v$SQUAWK_VERSION/squawk-darwin-x86_64" + chmod +x "$SQUAWK_BIN" +fi + +if [ -n "$SQUAWK_GITHUB_TOKEN" ]; then + export SQUAWK_GITHUB_REPO_OWNER=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $1}') + export SQUAWK_GITHUB_REPO_NAME=$(echo $GITHUB_REPOSITORY | awk -F/ '{print $2}') + export SQUAWK_GITHUB_PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }') + + $SQUAWK_BIN $SQUAWK_ARGS upload-to-github $(git diff --name-only origin/$GITHUB_BASE_REF...origin/$GITHUB_HEAD_REF 'crates/collab/migrations/*.sql') +else + $SQUAWK_BIN $SQUAWK_ARGS $(git ls-files --others crates/collab/migrations/*.sql) $(git diff --name-only main crates/collab/migrations/*.sql) +fi From bc09ce6ffcdf9de313209107c836c2b1792749c7 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 12 Jan 2024 10:37:18 -0500 Subject: [PATCH 05/31] Clean up some theme TODOs (#4034) This PR cleans up some TODOs we had in the themes. We won't be addressing these in the immediate term, so no need to have them show up when folks are looking for TODOs to burn down before launch. I added some general notes as signposts until we're ready to revisit this. Release Notes: - N/A --- crates/theme/src/default_colors.rs | 29 +++++++++++++++++------------ crates/theme/src/one_themes.rs | 6 +++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/crates/theme/src/default_colors.rs b/crates/theme/src/default_colors.rs index 8cbfc23fa3..fb88afb7da 100644 --- a/crates/theme/src/default_colors.rs +++ b/crates/theme/src/default_colors.rs @@ -8,6 +8,11 @@ pub(crate) fn neutral() -> ColorScaleSet { sand() } +// Note: We aren't currently making use of the default colors, as all of the +// themes have a value set for each color. +// +// We'll need to revisit these once we're ready to launch user themes, which may +// not specify a value for each color (and thus should fall back to the defaults). impl ThemeColors { pub fn light() -> Self { let system = SystemColors::default(); @@ -23,12 +28,12 @@ impl ThemeColors { surface_background: neutral().light().step_2(), background: neutral().light().step_1(), element_background: neutral().light().step_3(), - element_hover: neutral().light_alpha().step_4(), // todo!("pick the right colors") + element_hover: neutral().light_alpha().step_4(), element_active: neutral().light_alpha().step_5(), element_selected: neutral().light_alpha().step_5(), - element_disabled: neutral().light_alpha().step_3(), // todo!("pick the right colors") - drop_target_background: blue().light_alpha().step_2(), // todo!("pick the right colors") - ghost_element_background: system.transparent, // todo!("pick the right colors") + element_disabled: neutral().light_alpha().step_3(), + drop_target_background: blue().light_alpha().step_2(), + ghost_element_background: system.transparent, ghost_element_hover: neutral().light_alpha().step_3(), ghost_element_active: neutral().light_alpha().step_4(), ghost_element_selected: neutral().light_alpha().step_5(), @@ -59,7 +64,7 @@ impl ThemeColors { scrollbar_track_background: gpui::transparent_black(), scrollbar_track_border: neutral().light().step_5(), editor_foreground: neutral().light().step_12(), - editor_background: neutral().light().step_1(), // todo!(this was inserted by Mikayla) + editor_background: neutral().light().step_1(), editor_gutter_background: neutral().light().step_1(), editor_subheader_background: neutral().light().step_2(), editor_active_line_background: neutral().light_alpha().step_3(), @@ -106,17 +111,17 @@ impl ThemeColors { surface_background: neutral().dark().step_2(), background: neutral().dark().step_1(), element_background: neutral().dark().step_3(), - element_hover: neutral().dark_alpha().step_4(), // todo!("pick the right colors") + element_hover: neutral().dark_alpha().step_4(), element_active: neutral().dark_alpha().step_5(), - element_selected: neutral().dark_alpha().step_5(), // todo!("pick the right colors") - element_disabled: neutral().dark_alpha().step_3(), // todo!("pick the right colors") + element_selected: neutral().dark_alpha().step_5(), + element_disabled: neutral().dark_alpha().step_3(), drop_target_background: blue().dark_alpha().step_2(), ghost_element_background: system.transparent, - ghost_element_hover: neutral().dark_alpha().step_4(), // todo!("pick the right colors") - ghost_element_active: neutral().dark_alpha().step_5(), // todo!("pick the right colors") + ghost_element_hover: neutral().dark_alpha().step_4(), + ghost_element_active: neutral().dark_alpha().step_5(), ghost_element_selected: neutral().dark_alpha().step_5(), ghost_element_disabled: neutral().dark_alpha().step_3(), - text: neutral().dark().step_12(), // todo!("pick the right colors") + text: neutral().dark().step_12(), text_muted: neutral().dark().step_11(), text_placeholder: neutral().dark().step_10(), text_disabled: neutral().dark().step_9(), @@ -140,7 +145,7 @@ impl ThemeColors { scrollbar_thumb_hover_background: neutral().dark_alpha().step_4(), scrollbar_thumb_border: gpui::transparent_black(), scrollbar_track_background: gpui::transparent_black(), - scrollbar_track_border: neutral().dark().step_5(), // todo!(this was inserted by Mikayla) + scrollbar_track_border: neutral().dark().step_5(), editor_foreground: neutral().dark().step_12(), editor_background: neutral().dark().step_1(), editor_gutter_background: neutral().dark().step_1(), diff --git a/crates/theme/src/one_themes.rs b/crates/theme/src/one_themes.rs index d0bae590f6..fab3631d13 100644 --- a/crates/theme/src/one_themes.rs +++ b/crates/theme/src/one_themes.rs @@ -7,6 +7,10 @@ use crate::{ ThemeColors, ThemeFamily, ThemeStyles, }; +// Note: This theme family is not the one you see in Zed at the moment. +// This is a from-scratch rebuild that Nate started work on. We currently +// only use this in the tests, and the One family from the `themes/` directory +// is what gets loaded into Zed when running it. pub fn one_family() -> ThemeFamily { ThemeFamily { id: "one".to_string(), @@ -75,7 +79,7 @@ pub(crate) fn one_dark() -> Theme { tab_bar_background: bg, tab_inactive_background: bg, tab_active_background: editor, - search_match_background: bg, // todo!(this was inserted by Mikayla) + search_match_background: bg, editor_background: editor, editor_gutter_background: editor, From 981858ef3c280043524c30b9d44f47b5c71a7f2e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 10:01:18 -0700 Subject: [PATCH 06/31] Fix panic with many participants --- crates/ui/src/styles/color.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ui/src/styles/color.rs b/crates/ui/src/styles/color.rs index 434183e560..1c9fd789d9 100644 --- a/crates/ui/src/styles/color.rs +++ b/crates/ui/src/styles/color.rs @@ -37,7 +37,7 @@ impl Color { Color::Info => cx.theme().status().info, Color::Placeholder => cx.theme().colors().text_placeholder, Color::Accent => cx.theme().colors().text_accent, - Color::Player(i) => cx.theme().styles.player.0[i.clone() as usize].cursor, + Color::Player(i) => cx.theme().styles.player.color_for_participant(*i).cursor, Color::Error => cx.theme().status().error, Color::Selected => cx.theme().colors().text_accent, Color::Success => cx.theme().status().success, From dc158f708f2334205feee39c8ccb7c57edd573c1 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 10:23:22 -0700 Subject: [PATCH 07/31] Update chat panel with current channel --- crates/call/src/call.rs | 2 ++ crates/call/src/room.rs | 3 +++ crates/collab_ui/src/chat_panel.rs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index 87d2e9aa78..a37cc3bc78 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -442,6 +442,8 @@ impl ActiveCall { .location .as_ref() .and_then(|location| location.upgrade()); + let channel_id = room.update(cx, |room, cx| room.channel_id()); + cx.emit(Event::RoomJoined { channel_id }); room.update(cx, |room, cx| room.set_location(location.as_ref(), cx)) } } else { diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 45c6c15fb0..6dae1e6a4d 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -26,6 +26,9 @@ pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { + RoomJoined { + channel_id: Option, + }, ParticipantLocationChanged { participant_id: proto::PeerId, }, diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index 5786ab10d4..bbe0a6b4fe 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -1,6 +1,6 @@ use crate::{channel_view::ChannelView, is_channels_feature_enabled, ChatPanelSettings}; use anyhow::Result; -use call::ActiveCall; +use call::{room, ActiveCall}; use channel::{ChannelChat, ChannelChatEvent, ChannelMessageId, ChannelStore}; use client::Client; use collections::HashMap; @@ -140,6 +140,18 @@ impl ChatPanel { cx.notify(); }, )); + this.subscriptions.push(cx.subscribe( + &ActiveCall::global(cx), + move |this: &mut Self, _, event: &room::Event, cx| match event { + room::Event::RoomJoined { channel_id } => { + if let Some(channel_id) = channel_id { + this.select_channel(*channel_id, None, cx) + .detach_and_log_err(cx) + } + } + _ => {} + }, + )); this }) From f0d490c671400c75cfb87a267729610bf6998a3e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 10:34:24 -0700 Subject: [PATCH 08/31] Open chat panel for guests --- crates/call/src/call.rs | 6 ++++-- crates/call/src/room.rs | 1 + crates/collab_ui/src/chat_panel.rs | 9 +++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index a37cc3bc78..72bb6a4e6e 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -442,8 +442,10 @@ impl ActiveCall { .location .as_ref() .and_then(|location| location.upgrade()); - let channel_id = room.update(cx, |room, cx| room.channel_id()); - cx.emit(Event::RoomJoined { channel_id }); + let (channel_id, role) = room.update(cx, |room, _| { + (room.channel_id(), room.local_participant().role) + }); + cx.emit(Event::RoomJoined { channel_id, role }); room.update(cx, |room, cx| room.set_location(location.as_ref(), cx)) } } else { diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 6dae1e6a4d..23a6ea4a1c 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -28,6 +28,7 @@ pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); pub enum Event { RoomJoined { channel_id: Option, + role: proto::ChannelRole, }, ParticipantLocationChanged { participant_id: proto::PeerId, diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index bbe0a6b4fe..a170f95697 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -16,6 +16,7 @@ use menu::Confirm; use message_editor::MessageEditor; use project::Fs; use rich_text::RichText; +use rpc::proto; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; use std::sync::Arc; @@ -143,10 +144,14 @@ impl ChatPanel { this.subscriptions.push(cx.subscribe( &ActiveCall::global(cx), move |this: &mut Self, _, event: &room::Event, cx| match event { - room::Event::RoomJoined { channel_id } => { + room::Event::RoomJoined { channel_id, role } => { if let Some(channel_id) = channel_id { this.select_channel(*channel_id, None, cx) - .detach_and_log_err(cx) + .detach_and_log_err(cx); + + if *role == proto::ChannelRole::Guest { + cx.emit(PanelEvent::Activate) + } } } _ => {} From 7dc28aad787ae3f88f2c6c95979358ba170c0a2e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 12 Jan 2024 10:38:05 -0800 Subject: [PATCH 09/31] Forbid paste, undo, redo on read-only editors --- crates/editor/src/editor.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 7fe942f145..66d30b049c 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5443,6 +5443,10 @@ impl Editor { } pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { + if self.read_only(cx) { + return; + } + self.transact(cx, |this, cx| { if let Some(item) = cx.read_from_clipboard() { let clipboard_text = Cow::Borrowed(item.text()); @@ -5515,6 +5519,10 @@ impl Editor { } pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { + if self.read_only(cx) { + return; + } + if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) { if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() { self.change_selections(None, cx, |s| { @@ -5529,6 +5537,10 @@ impl Editor { } pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { + if self.read_only(cx) { + return; + } + if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) { if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned() { From 551fd9ba7ee3d5a4c51da110a140965bb25f8569 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 12:40:09 -0700 Subject: [PATCH 10/31] Boop --- .../gpui/src/platform/mac/metal_renderer.rs | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index a6cdd166d3..2a1f9ef92d 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -18,7 +18,7 @@ use smallvec::SmallVec; use std::{ffi::c_void, mem, ptr, sync::Arc}; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); -const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. +const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. [] pub(crate) struct MetalRenderer { layer: metal::MetalLayer, @@ -429,6 +429,13 @@ impl MetalRenderer { let shadow_bytes_len = std::mem::size_of_val(shadows); let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; + + let next_offset = *offset + shadow_bytes_len; + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); + unsafe { ptr::copy_nonoverlapping( shadows.as_ptr() as *const u8, @@ -437,12 +444,6 @@ impl MetalRenderer { ); } - let next_offset = *offset + shadow_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); - command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, 0, @@ -489,15 +490,15 @@ impl MetalRenderer { let quad_bytes_len = std::mem::size_of_val(quads); let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; - unsafe { - ptr::copy_nonoverlapping(quads.as_ptr() as *const u8, buffer_contents, quad_bytes_len); - } let next_offset = *offset + quad_bytes_len; assert!( next_offset <= INSTANCE_BUFFER_SIZE, "instance buffer exhausted" ); + unsafe { + ptr::copy_nonoverlapping(quads.as_ptr() as *const u8, buffer_contents, quad_bytes_len); + } command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, @@ -586,22 +587,32 @@ impl MetalRenderer { command_encoder .set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture)); + // hypothesis: sprites.as_ptr() does something bogus sometimes? + // let sprite_bytes_len = mem::size_of::() * sprites.len(); - let buffer_contents = - unsafe { (self.instances.contents() as *mut u8).add(*offset) }; - unsafe { - ptr::copy_nonoverlapping( - sprites.as_ptr() as *const u8, - buffer_contents, - sprite_bytes_len, - ); - } - let next_offset = *offset + sprite_bytes_len; assert!( next_offset <= INSTANCE_BUFFER_SIZE, "instance buffer exhausted" ); + let buffer_contents = + unsafe { (self.instances.contents() as *mut u8).add(*offset) }; + + // buffer_contents.len() < spite_bytes_len must be out of range. + // PANIC HERE! + let next_offset = *offset + sprite_bytes_len; + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); + + unsafe { + ptr::copy_nonoverlapping( + sprites.as_ptr() as *const u8, //src + buffer_contents, //dest + sprite_bytes_len, // count + ); + } command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, @@ -723,6 +734,13 @@ impl MetalRenderer { let sprite_bytes_len = std::mem::size_of_val(sprites); let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; + + let next_offset = *offset + sprite_bytes_len; + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); + unsafe { ptr::copy_nonoverlapping( sprites.as_ptr() as *const u8, @@ -731,12 +749,6 @@ impl MetalRenderer { ); } - let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); - command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, 0, @@ -794,6 +806,12 @@ impl MetalRenderer { let sprite_bytes_len = std::mem::size_of_val(sprites); let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; + + let next_offset = *offset + sprite_bytes_len; + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); unsafe { ptr::copy_nonoverlapping( sprites.as_ptr() as *const u8, @@ -802,12 +820,6 @@ impl MetalRenderer { ); } - let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); - command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, 0, From 324d1d119ba4066064bd13505053b308ffc9ae07 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 12:40:37 -0800 Subject: [PATCH 11/31] Add some context to assert --- .../gpui/src/platform/mac/metal_renderer.rs | 70 +++++++------------ 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 2a1f9ef92d..8365525ebd 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -18,7 +18,7 @@ use smallvec::SmallVec; use std::{ffi::c_void, mem, ptr, sync::Arc}; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); -const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. [] +const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. pub(crate) struct MetalRenderer { layer: metal::MetalLayer, @@ -337,10 +337,7 @@ impl MetalRenderer { for (texture_id, vertices) in vertices_by_texture_id { align_offset(offset); let next_offset = *offset + vertices.len() * mem::size_of::>(); - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, vertices.len(), "Path Vertexes"); let render_pass_descriptor = metal::RenderPassDescriptor::new(); let color_attachment = render_pass_descriptor @@ -431,10 +428,7 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + shadow_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, shadows.len(), "Shadows"); unsafe { ptr::copy_nonoverlapping( @@ -492,10 +486,8 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + quad_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, quads.len(), "Quads"); + unsafe { ptr::copy_nonoverlapping(quads.as_ptr() as *const u8, buffer_contents, quad_bytes_len); } @@ -587,30 +579,18 @@ impl MetalRenderer { command_encoder .set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture)); - // hypothesis: sprites.as_ptr() does something bogus sometimes? - // let sprite_bytes_len = mem::size_of::() * sprites.len(); let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Path Sprites"); + let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; - // buffer_contents.len() < spite_bytes_len must be out of range. - // PANIC HERE! - let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); - unsafe { ptr::copy_nonoverlapping( - sprites.as_ptr() as *const u8, //src - buffer_contents, //dest - sprite_bytes_len, // count + sprites.as_ptr() as *const u8, + buffer_contents, + sprite_bytes_len, ); } @@ -672,10 +652,7 @@ impl MetalRenderer { } let next_offset = *offset + quad_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, underlines.len(), "Underlines"); command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, @@ -736,10 +713,7 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Monoschrome Sprites"); unsafe { ptr::copy_nonoverlapping( @@ -808,10 +782,8 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + sprite_bytes_len; - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Polychrome Sprites"); + unsafe { ptr::copy_nonoverlapping( sprites.as_ptr() as *const u8, @@ -886,10 +858,7 @@ impl MetalRenderer { align_offset(offset); let next_offset = *offset + mem::size_of::(); - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); + self.assert_instance_buffer_bounds(next_offset, 1, "Surface"); command_encoder.set_vertex_buffer( SurfaceInputIndex::Surfaces as u64, @@ -926,6 +895,15 @@ impl MetalRenderer { *offset = next_offset; } } + + fn assert_instance_buffer_bounds(&self, next_offset: usize, count: usize, item: &'static str) { + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted attempting to copy {} of {}", + count, + item + ); + } } fn build_pipeline_state( From aa5c6a8aa354e424a60f736559355045b091775c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 14:35:50 -0700 Subject: [PATCH 12/31] Update graphics memory assert to be more helpful --- .../gpui/src/platform/mac/metal_renderer.rs | 192 ++++++++++-------- 1 file changed, 105 insertions(+), 87 deletions(-) diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 8365525ebd..20e749a2f6 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -18,7 +18,7 @@ use smallvec::SmallVec; use std::{ffi::c_void, mem, ptr, sync::Arc}; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); -const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. +const INSTANCE_BUFFER_SIZE: usize = 32 * 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value (maybe even we could adjust dynamically...) pub(crate) struct MetalRenderer { layer: metal::MetalLayer, @@ -204,7 +204,11 @@ impl MetalRenderer { let command_buffer = command_queue.new_command_buffer(); let mut instance_offset = 0; - let path_tiles = self.rasterize_paths(scene.paths(), &mut instance_offset, command_buffer); + let Some(path_tiles) = + self.rasterize_paths(scene.paths(), &mut instance_offset, command_buffer) + else { + panic!("failed to rasterize {} paths", scene.paths().len()); + }; let render_pass_descriptor = metal::RenderPassDescriptor::new(); let color_attachment = render_pass_descriptor @@ -228,67 +232,67 @@ impl MetalRenderer { zfar: 1.0, }); for batch in scene.batches() { - match batch { - PrimitiveBatch::Shadows(shadows) => { - self.draw_shadows( - shadows, - &mut instance_offset, - viewport_size, - command_encoder, - ); - } + let ok = match batch { + PrimitiveBatch::Shadows(shadows) => self.draw_shadows( + shadows, + &mut instance_offset, + viewport_size, + command_encoder, + ), PrimitiveBatch::Quads(quads) => { - self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder); - } - PrimitiveBatch::Paths(paths) => { - self.draw_paths( - paths, - &path_tiles, - &mut instance_offset, - viewport_size, - command_encoder, - ); - } - PrimitiveBatch::Underlines(underlines) => { - self.draw_underlines( - underlines, - &mut instance_offset, - viewport_size, - command_encoder, - ); + self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder) } + PrimitiveBatch::Paths(paths) => self.draw_paths( + paths, + &path_tiles, + &mut instance_offset, + viewport_size, + command_encoder, + ), + PrimitiveBatch::Underlines(underlines) => self.draw_underlines( + underlines, + &mut instance_offset, + viewport_size, + command_encoder, + ), PrimitiveBatch::MonochromeSprites { texture_id, sprites, - } => { - self.draw_monochrome_sprites( - texture_id, - sprites, - &mut instance_offset, - viewport_size, - command_encoder, - ); - } + } => self.draw_monochrome_sprites( + texture_id, + sprites, + &mut instance_offset, + viewport_size, + command_encoder, + ), PrimitiveBatch::PolychromeSprites { texture_id, sprites, - } => { - self.draw_polychrome_sprites( - texture_id, - sprites, - &mut instance_offset, - viewport_size, - command_encoder, - ); - } - PrimitiveBatch::Surfaces(surfaces) => { - self.draw_surfaces( - surfaces, - &mut instance_offset, - viewport_size, - command_encoder, - ); - } + } => self.draw_polychrome_sprites( + texture_id, + sprites, + &mut instance_offset, + viewport_size, + command_encoder, + ), + PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces( + surfaces, + &mut instance_offset, + viewport_size, + command_encoder, + ), + }; + + if !ok { + panic!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces", + scene.paths.len(), + scene.shadows.len(), + scene.quads.len(), + scene.underlines.len(), + scene.monochrome_sprites.len(), + scene.polychrome_sprites.len(), + scene.surfaces.len(), + ) } } @@ -311,7 +315,7 @@ impl MetalRenderer { paths: &[Path], offset: &mut usize, command_buffer: &metal::CommandBufferRef, - ) -> HashMap { + ) -> Option> { let mut tiles = HashMap::default(); let mut vertices_by_texture_id = HashMap::default(); for path in paths { @@ -337,7 +341,9 @@ impl MetalRenderer { for (texture_id, vertices) in vertices_by_texture_id { align_offset(offset); let next_offset = *offset + vertices.len() * mem::size_of::>(); - self.assert_instance_buffer_bounds(next_offset, vertices.len(), "Path Vertexes"); + if next_offset > INSTANCE_BUFFER_SIZE { + return None; + } let render_pass_descriptor = metal::RenderPassDescriptor::new(); let color_attachment = render_pass_descriptor @@ -386,7 +392,7 @@ impl MetalRenderer { *offset = next_offset; } - tiles + Some(tiles) } fn draw_shadows( @@ -395,9 +401,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if shadows.is_empty() { - return; + return true; } align_offset(offset); @@ -428,7 +434,9 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + shadow_bytes_len; - self.assert_instance_buffer_bounds(next_offset, shadows.len(), "Shadows"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } unsafe { ptr::copy_nonoverlapping( @@ -445,6 +453,7 @@ impl MetalRenderer { shadows.len() as u64, ); *offset = next_offset; + true } fn draw_quads( @@ -453,9 +462,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if quads.is_empty() { - return; + return true; } align_offset(offset); @@ -486,7 +495,9 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + quad_bytes_len; - self.assert_instance_buffer_bounds(next_offset, quads.len(), "Quads"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } unsafe { ptr::copy_nonoverlapping(quads.as_ptr() as *const u8, buffer_contents, quad_bytes_len); @@ -499,6 +510,7 @@ impl MetalRenderer { quads.len() as u64, ); *offset = next_offset; + true } fn draw_paths( @@ -508,9 +520,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if paths.is_empty() { - return; + return true; } command_encoder.set_render_pipeline_state(&self.path_sprites_pipeline_state); @@ -581,7 +593,9 @@ impl MetalRenderer { let sprite_bytes_len = mem::size_of::() * sprites.len(); let next_offset = *offset + sprite_bytes_len; - self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Path Sprites"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; @@ -604,6 +618,7 @@ impl MetalRenderer { sprites.clear(); } } + true } fn draw_underlines( @@ -612,9 +627,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if underlines.is_empty() { - return; + return true; } align_offset(offset); @@ -652,7 +667,9 @@ impl MetalRenderer { } let next_offset = *offset + quad_bytes_len; - self.assert_instance_buffer_bounds(next_offset, underlines.len(), "Underlines"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } command_encoder.draw_primitives_instanced( metal::MTLPrimitiveType::Triangle, @@ -661,6 +678,7 @@ impl MetalRenderer { underlines.len() as u64, ); *offset = next_offset; + true } fn draw_monochrome_sprites( @@ -670,9 +688,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if sprites.is_empty() { - return; + return true; } align_offset(offset); @@ -713,7 +731,9 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + sprite_bytes_len; - self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Monoschrome Sprites"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } unsafe { ptr::copy_nonoverlapping( @@ -730,6 +750,7 @@ impl MetalRenderer { sprites.len() as u64, ); *offset = next_offset; + true } fn draw_polychrome_sprites( @@ -739,9 +760,9 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { if sprites.is_empty() { - return; + return true; } align_offset(offset); @@ -782,7 +803,9 @@ impl MetalRenderer { let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; let next_offset = *offset + sprite_bytes_len; - self.assert_instance_buffer_bounds(next_offset, sprites.len(), "Polychrome Sprites"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } unsafe { ptr::copy_nonoverlapping( @@ -799,6 +822,7 @@ impl MetalRenderer { sprites.len() as u64, ); *offset = next_offset; + true } fn draw_surfaces( @@ -807,7 +831,7 @@ impl MetalRenderer { offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, - ) { + ) -> bool { command_encoder.set_render_pipeline_state(&self.surfaces_pipeline_state); command_encoder.set_vertex_buffer( SurfaceInputIndex::Vertices as u64, @@ -858,7 +882,9 @@ impl MetalRenderer { align_offset(offset); let next_offset = *offset + mem::size_of::(); - self.assert_instance_buffer_bounds(next_offset, 1, "Surface"); + if next_offset > INSTANCE_BUFFER_SIZE { + return false; + } command_encoder.set_vertex_buffer( SurfaceInputIndex::Surfaces as u64, @@ -894,15 +920,7 @@ impl MetalRenderer { command_encoder.draw_primitives(metal::MTLPrimitiveType::Triangle, 0, 6); *offset = next_offset; } - } - - fn assert_instance_buffer_bounds(&self, next_offset: usize, count: usize, item: &'static str) { - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted attempting to copy {} of {}", - count, - item - ); + true } } From 50f3bbbc8b38bec8e687db8bcebd1667454450c0 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 15:08:14 -0700 Subject: [PATCH 13/31] Open chat when joining a channel with guests (and close it when leaving a channel again) --- crates/call/src/call.rs | 6 ++---- crates/call/src/room.rs | 17 ++++++++++++--- crates/collab_ui/src/chat_panel.rs | 21 ++++++++++++++++--- .../project_shared_notification.rs | 2 +- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index 72bb6a4e6e..6d57a42ff7 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -442,10 +442,8 @@ impl ActiveCall { .location .as_ref() .and_then(|location| location.upgrade()); - let (channel_id, role) = room.update(cx, |room, _| { - (room.channel_id(), room.local_participant().role) - }); - cx.emit(Event::RoomJoined { channel_id, role }); + let channel_id = room.read(cx).channel_id(); + cx.emit(Event::RoomJoined { channel_id }); room.update(cx, |room, cx| room.set_location(location.as_ref(), cx)) } } else { diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 23a6ea4a1c..e17a3667ba 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -28,7 +28,6 @@ pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); pub enum Event { RoomJoined { channel_id: Option, - role: proto::ChannelRole, }, ParticipantLocationChanged { participant_id: proto::PeerId, @@ -53,7 +52,9 @@ pub enum Event { RemoteProjectInvitationDiscarded { project_id: u64, }, - Left, + Left { + channel_id: Option, + }, } pub struct Room { @@ -361,7 +362,9 @@ impl Room { pub(crate) fn leave(&mut self, cx: &mut ModelContext) -> Task> { cx.notify(); - cx.emit(Event::Left); + cx.emit(Event::Left { + channel_id: self.channel_id(), + }); self.leave_internal(cx) } @@ -602,6 +605,14 @@ impl Room { .map(|participant| participant.role) } + pub fn contains_guests(&self) -> bool { + self.local_participant.role == proto::ChannelRole::Guest + || self + .remote_participants + .values() + .any(|p| p.role == proto::ChannelRole::Guest) + } + pub fn local_participant_is_admin(&self) -> bool { self.local_participant.role == proto::ChannelRole::Admin } diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index a170f95697..f8ee12ef81 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -143,17 +143,26 @@ impl ChatPanel { )); this.subscriptions.push(cx.subscribe( &ActiveCall::global(cx), - move |this: &mut Self, _, event: &room::Event, cx| match event { - room::Event::RoomJoined { channel_id, role } => { + move |this: &mut Self, call, event: &room::Event, cx| match event { + room::Event::RoomJoined { channel_id } => { if let Some(channel_id) = channel_id { this.select_channel(*channel_id, None, cx) .detach_and_log_err(cx); - if *role == proto::ChannelRole::Guest { + if call + .read(cx) + .room() + .is_some_and(|room| room.read(cx).contains_guests()) + { cx.emit(PanelEvent::Activate) } } } + room::Event::Left { channel_id } => { + if channel_id == &this.channel_id(cx) { + cx.emit(PanelEvent::Close) + } + } _ => {} }, )); @@ -162,6 +171,12 @@ impl ChatPanel { }) } + pub fn channel_id(&self, cx: &AppContext) -> Option { + self.active_chat + .as_ref() + .map(|(chat, _)| chat.read(cx).channel_id) + } + pub fn is_scrolled_to_bottom(&self) -> bool { self.is_scrolled_to_bottom } diff --git a/crates/collab_ui/src/notifications/project_shared_notification.rs b/crates/collab_ui/src/notifications/project_shared_notification.rs index 88fe540c39..b8ceefcd76 100644 --- a/crates/collab_ui/src/notifications/project_shared_notification.rs +++ b/crates/collab_ui/src/notifications/project_shared_notification.rs @@ -58,7 +58,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { } } - room::Event::Left => { + room::Event::Left { .. } => { for (_, windows) in notification_windows.drain() { for window in windows { window From cdc227b32fd23f979342a34cd519816ce4b44728 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 12 Jan 2024 17:44:15 -0500 Subject: [PATCH 14/31] Still paint group hover handler for invisible divs Fixes bug where tab close icon show on hover is inconsistent --- crates/gpui/src/elements/div.rs | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 627a2ac339..0c1b0b74bb 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -978,12 +978,31 @@ impl Interactivity { f: impl FnOnce(&Style, Point, &mut WindowContext), ) { let style = self.compute_style(Some(bounds), element_state, cx); + let z_index = style.z_index.unwrap_or(0); + + let paint_hover_group_handler = |cx: &mut WindowContext| { + let hover_group_bounds = self + .group_hover_style + .as_ref() + .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx)); + + if let Some(group_bounds) = hover_group_bounds { + let hovered = group_bounds.contains(&cx.mouse_position()); + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { + if phase == DispatchPhase::Capture + && group_bounds.contains(&event.position) != hovered + { + cx.notify(); + } + }); + } + }; if style.visibility == Visibility::Hidden { + cx.with_z_index(z_index, |cx| paint_hover_group_handler(cx)); return; } - let z_index = style.z_index.unwrap_or(0); cx.with_z_index(z_index, |cx| { style.paint(bounds, cx, |cx| { cx.with_text_style(style.text_style().cloned(), |cx| { @@ -1166,21 +1185,7 @@ impl Interactivity { }) } - let hover_group_bounds = self - .group_hover_style - .as_ref() - .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx)); - - if let Some(group_bounds) = hover_group_bounds { - let hovered = group_bounds.contains(&cx.mouse_position()); - cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { - if phase == DispatchPhase::Capture - && group_bounds.contains(&event.position) != hovered - { - cx.notify(); - } - }); - } + paint_hover_group_handler(cx); if self.hover_style.is_some() || self.base_style.mouse_cursor.is_some() From eafe0944e0b4b8c0a23f6fef9f90e6b56fd06710 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 12 Jan 2024 16:01:51 -0700 Subject: [PATCH 15/31] Some tweaks for chat panels --- crates/collab_ui/src/chat_panel.rs | 189 +++++++++++------------------ 1 file changed, 69 insertions(+), 120 deletions(-) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index f8ee12ef81..ecd7d1a739 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -1,4 +1,4 @@ -use crate::{channel_view::ChannelView, is_channels_feature_enabled, ChatPanelSettings}; +use crate::{collab_panel, is_channels_feature_enabled, ChatPanelSettings, CollabPanel}; use anyhow::Result; use call::{room, ActiveCall}; use channel::{ChannelChat, ChannelChatEvent, ChannelMessageId, ChannelStore}; @@ -7,9 +7,9 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use editor::Editor; use gpui::{ - actions, div, list, prelude::*, px, AnyElement, AppContext, AsyncWindowContext, ClickEvent, - ElementId, EventEmitter, FocusableView, ListOffset, ListScrollEvent, ListState, Model, Render, - Subscription, Task, View, ViewContext, VisualContext, WeakView, + actions, div, list, prelude::*, px, Action, AnyElement, AppContext, AsyncWindowContext, + ClickEvent, ElementId, EventEmitter, FocusHandle, FocusableView, ListOffset, ListScrollEvent, + ListState, Model, Render, Subscription, Task, View, ViewContext, VisualContext, WeakView, }; use language::LanguageRegistry; use menu::Confirm; @@ -21,7 +21,9 @@ use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; use std::sync::Arc; use time::{OffsetDateTime, UtcOffset}; -use ui::{prelude::*, Avatar, Button, IconButton, IconName, Label, TabBar, Tooltip}; +use ui::{ + prelude::*, Avatar, Button, IconButton, IconName, Key, KeyBinding, Label, TabBar, Tooltip, +}; use util::{ResultExt, TryFutureExt}; use workspace::{ dock::{DockPosition, Panel, PanelEvent}, @@ -55,7 +57,6 @@ pub struct ChatPanel { active: bool, pending_serialization: Task>, subscriptions: Vec, - workspace: WeakView, is_scrolled_to_bottom: bool, markdown_data: HashMap, } @@ -90,8 +91,6 @@ impl ChatPanel { ) }); - let workspace_handle = workspace.weak_handle(); - cx.new_view(|cx: &mut ViewContext| { let view = cx.view().downgrade(); let message_list = @@ -123,7 +122,6 @@ impl ChatPanel { message_editor: input_editor, local_timezone: cx.local_timezone(), subscriptions: Vec::new(), - workspace: workspace_handle, is_scrolled_to_bottom: true, active: false, width: None, @@ -291,50 +289,6 @@ impl ChatPanel { } } - fn render_channel(&self, cx: &mut ViewContext) -> AnyElement { - v_stack() - .full() - .on_action(cx.listener(Self::send)) - .child( - h_stack().z_index(1).child( - TabBar::new("chat_header") - .child( - h_stack() - .w_full() - .h(rems(ui::Tab::HEIGHT_IN_REMS)) - .px_2() - .child(Label::new( - self.active_chat - .as_ref() - .and_then(|c| { - Some(format!("#{}", c.0.read(cx).channel(cx)?.name)) - }) - .unwrap_or_default(), - )), - ) - .end_child( - IconButton::new("notes", IconName::File) - .on_click(cx.listener(Self::open_notes)) - .tooltip(|cx| Tooltip::text("Open notes", cx)), - ) - .end_child( - IconButton::new("call", IconName::AudioOn) - .on_click(cx.listener(Self::join_call)) - .tooltip(|cx| Tooltip::text("Join call", cx)), - ), - ), - ) - .child(div().flex_grow().px_2().py_1().map(|this| { - if self.active_chat.is_some() { - this.child(list(self.message_list.clone()).full()) - } else { - this - } - })) - .child(h_stack().p_2().child(self.message_editor.clone())) - .into_any() - } - fn render_message(&mut self, ix: usize, cx: &mut ViewContext) -> impl IntoElement { let active_chat = &self.active_chat.as_ref().unwrap().0; let (message, is_continuation_from_previous, is_continuation_to_next, is_admin) = @@ -453,44 +407,6 @@ impl ChatPanel { rich_text::render_markdown(message.body.clone(), &mentions, language_registry, None) } - fn render_sign_in_prompt(&self, cx: &mut ViewContext) -> impl IntoElement { - v_stack() - .gap_2() - .p_4() - .child( - Button::new("sign-in", "Sign in") - .style(ButtonStyle::Filled) - .icon_color(Color::Muted) - .icon(IconName::Github) - .icon_position(IconPosition::Start) - .full_width() - .on_click(cx.listener(move |this, _, cx| { - let client = this.client.clone(); - cx.spawn(|this, mut cx| async move { - if client - .authenticate_and_connect(true, &cx) - .log_err() - .await - .is_some() - { - this.update(&mut cx, |_, cx| { - cx.focus_self(); - }) - .ok(); - } - }) - .detach(); - })), - ) - .child( - div().flex().w_full().items_center().child( - Label::new("Sign in to chat.") - .color(Color::Muted) - .size(LabelSize::Small), - ), - ) - } - fn send(&mut self, _: &Confirm, cx: &mut ViewContext) { if let Some((chat, _)) = self.active_chat.as_ref() { let message = self @@ -567,24 +483,6 @@ impl ChatPanel { Ok(()) }) } - - fn open_notes(&mut self, _: &ClickEvent, cx: &mut ViewContext) { - if let Some((chat, _)) = &self.active_chat { - let channel_id = chat.read(cx).channel_id; - if let Some(workspace) = self.workspace.upgrade() { - ChannelView::open(channel_id, workspace, cx).detach(); - } - } - } - - fn join_call(&mut self, _: &ClickEvent, cx: &mut ViewContext) { - if let Some((chat, _)) = &self.active_chat { - let channel_id = chat.read(cx).channel_id; - ActiveCall::global(cx) - .update(cx, |call, cx| call.join_channel(channel_id, cx)) - .detach_and_log_err(cx); - } - } } impl EventEmitter for ChatPanel {} @@ -592,19 +490,70 @@ impl EventEmitter for ChatPanel {} impl Render for ChatPanel { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_stack() - .size_full() - .map(|this| match (self.client.user_id(), self.active_chat()) { - (Some(_), Some(_)) => this.child(self.render_channel(cx)), - (Some(_), None) => this.child( - div().p_4().child( - Label::new("Select a channel to chat in.") - .size(LabelSize::Small) - .color(Color::Muted), + .full() + .on_action(cx.listener(Self::send)) + .child( + h_stack().z_index(1).child( + TabBar::new("chat_header").child( + h_stack() + .w_full() + .h(rems(ui::Tab::HEIGHT_IN_REMS)) + .px_2() + .child(Label::new( + self.active_chat + .as_ref() + .and_then(|c| { + Some(format!("#{}", c.0.read(cx).channel(cx)?.name)) + }) + .unwrap_or("Chat".to_string()), + )), ), ), - (None, _) => this.child(self.render_sign_in_prompt(cx)), - }) - .min_w(px(150.)) + ) + .child(div().flex_grow().px_2().py_1().map(|this| { + if self.active_chat.is_some() { + this.child(list(self.message_list.clone()).full()) + } else { + this.child( + div() + .p_4() + .child( + Label::new("Select a channel to chat in.") + .size(LabelSize::Small) + .color(Color::Muted), + ) + .child( + div().pt_1().w_full().items_center().child( + Button::new("toggle-collab", "Open") + .full_width() + .key_binding(KeyBinding::for_action( + &collab_panel::ToggleFocus, + cx, + )) + .on_click(|_, cx| { + cx.dispatch_action( + collab_panel::ToggleFocus.boxed_clone(), + ) + }), + ), + ), + ) + } + })) + .child(h_stack().p_2().map(|el| { + if self.active_chat.is_some() { + el.child(self.message_editor.clone()) + } else { + el.child( + div() + .rounded_md() + .h_7() + .w_full() + .bg(cx.theme().colors().editor_background), + ) + } + })) + .into_any() } } From 3a836b80263b6c05957ac1c625323701e22a0913 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 11 Jan 2024 10:28:22 -0800 Subject: [PATCH 16/31] Remove some comments --- crates/collab_ui/src/collab_ui.rs | 32 ------------------ crates/editor/src/editor.rs | 33 ++++++++----------- crates/gpui/src/color.rs | 10 ------ crates/gpui/src/taffy.rs | 14 -------- crates/gpui/src/view.rs | 10 ------ crates/gpui_macros/src/register_action.rs | 13 -------- .../src/derive_refineable.rs | 11 ------- 7 files changed, 14 insertions(+), 109 deletions(-) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index c8230620b4..779fd121f8 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -41,10 +41,6 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { chat_panel::init(cx); notification_panel::init(cx); notifications::init(&app_state, cx); - - // cx.add_global_action(toggle_screen_sharing); - // cx.add_global_action(toggle_mute); - // cx.add_global_action(toggle_deafen); } pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { @@ -131,34 +127,6 @@ fn notification_window_options( } } -// fn render_avatar( -// avatar: Option>, -// avatar_style: &AvatarStyle, -// container: ContainerStyle, -// ) -> AnyElement { -// avatar -// .map(|avatar| { -// Image::from_data(avatar) -// .with_style(avatar_style.image) -// .aligned() -// .contained() -// .with_corner_radius(avatar_style.outer_corner_radius) -// .constrained() -// .with_width(avatar_style.outer_width) -// .with_height(avatar_style.outer_width) -// .into_any() -// }) -// .unwrap_or_else(|| { -// Empty::new() -// .constrained() -// .with_width(avatar_style.outer_width) -// .into_any() -// }) -// .contained() -// .with_style(container) -// .into_any() -// } - fn is_channels_feature_enabled(cx: &gpui::WindowContext<'_>) -> bool { cx.is_staff() || cx.has_flag::() } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 66d30b049c..0bfd6afa3b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1955,17 +1955,21 @@ impl Editor { } } - // pub fn language_at<'a, T: ToOffset>( - // &self, - // point: T, - // cx: &'a AppContext, - // ) -> Option> { - // self.buffer.read(cx).language_at(point, cx) - // } + pub fn language_at<'a, T: ToOffset>( + &self, + point: T, + cx: &'a AppContext, + ) -> Option> { + self.buffer.read(cx).language_at(point, cx) + } - // pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option> { - // self.buffer.read(cx).read(cx).file_at(point).cloned() - // } + pub fn file_at<'a, T: ToOffset>( + &self, + point: T, + cx: &'a AppContext, + ) -> Option> { + self.buffer.read(cx).read(cx).file_at(point).cloned() + } pub fn active_excerpt( &self, @@ -1976,15 +1980,6 @@ impl Editor { .excerpt_containing(self.selections.newest_anchor().head(), cx) } - // pub fn style(&self, cx: &AppContext) -> EditorStyle { - // build_style( - // settings::get::(cx), - // self.get_field_editor_theme.as_deref(), - // self.override_text_style.as_deref(), - // cx, - // ) - // } - pub fn mode(&self) -> EditorMode { self.mode } diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs index bc764e564c..23fcc25f6a 100644 --- a/crates/gpui/src/color.rs +++ b/crates/gpui/src/color.rs @@ -355,16 +355,6 @@ impl Hsla { } } -// impl From for Rgba { -// fn from(value: Hsla) -> Self { -// let h = value.h; -// let s = value.s; -// let l = value.l; - -// let c = (1 - |2L - 1|) X s -// } -// } - impl From for Hsla { fn from(color: Rgba) -> Self { let r = color.r; diff --git a/crates/gpui/src/taffy.rs b/crates/gpui/src/taffy.rs index 0ebd394217..cf8cb9ec32 100644 --- a/crates/gpui/src/taffy.rs +++ b/crates/gpui/src/taffy.rs @@ -271,20 +271,6 @@ impl ToTaffy for Style { } } -// impl ToTaffy for Bounds { -// type Output = taffy::prelude::Bounds; - -// fn to_taffy( -// &self, -// rem_size: Pixels, -// ) -> taffy::prelude::Bounds { -// taffy::prelude::Bounds { -// origin: self.origin.to_taffy(rem_size), -// size: self.size.to_taffy(rem_size), -// } -// } -// } - impl ToTaffy for Length { fn to_taffy(&self, rem_size: Pixels) -> taffy::prelude::LengthPercentageAuto { match self { diff --git a/crates/gpui/src/view.rs b/crates/gpui/src/view.rs index 4472da02e7..247a564996 100644 --- a/crates/gpui/src/view.rs +++ b/crates/gpui/src/view.rs @@ -60,16 +60,6 @@ impl View { self.model.read(cx) } - // pub fn render_with(&self, component: E) -> RenderViewWith - // where - // E: 'static + Element, - // { - // RenderViewWith { - // view: self.clone(), - // element: Some(component), - // } - // } - pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle where V: FocusableView, diff --git a/crates/gpui_macros/src/register_action.rs b/crates/gpui_macros/src/register_action.rs index c18e4f4b89..2772ec9634 100644 --- a/crates/gpui_macros/src/register_action.rs +++ b/crates/gpui_macros/src/register_action.rs @@ -1,16 +1,3 @@ -// Input: -// -// struct FooBar {} - -// Output: -// -// struct FooBar {} -// -// #[allow(non_snake_case)] -// #[gpui2::ctor] -// fn register_foobar_builder() { -// gpui2::register_action_builder::() -// } use proc_macro::TokenStream; use proc_macro2::Ident; use quote::{format_ident, quote}; diff --git a/crates/refineable/derive_refineable/src/derive_refineable.rs b/crates/refineable/derive_refineable/src/derive_refineable.rs index ad7678b58f..9941820646 100644 --- a/crates/refineable/derive_refineable/src/derive_refineable.rs +++ b/crates/refineable/derive_refineable/src/derive_refineable.rs @@ -69,13 +69,6 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { path: parse_quote!(Clone), })); - // punctuated.push_punct(syn::token::Add::default()); - // punctuated.push_value(TypeParamBound::Trait(TraitBound { - // paren_token: None, - // modifier: syn::TraitBoundModifier::None, - // lifetimes: None, - // path: parse_quote!(Default), - // })); punctuated }, }) @@ -94,10 +87,6 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { }, }; - // refinable_refine_assignments - // refinable_refined_assignments - // refinement_refine_assignments - let refineable_refine_assignments: Vec = fields .iter() .map(|field| { From 5897b18cfd353bebb9a53a4add4530766b8df2b2 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 11:42:03 -0800 Subject: [PATCH 17/31] remove more commented code --- crates/collab/src/tests/channel_tests.rs | 2 - crates/collab_ui/src/collab_panel.rs | 9 -- crates/gpui/src/style.rs | 96 +++++++++---------- crates/gpui/src/window.rs | 7 -- crates/project/src/project.rs | 14 --- crates/project_panel/src/project_panel.rs | 32 +++---- crates/rich_text/src/rich_text.rs | 33 +------ crates/rpc/build.rs | 1 - crates/search/src/buffer_search.rs | 1 - .../src/semantic_index_tests.rs | 2 - 10 files changed, 63 insertions(+), 134 deletions(-) diff --git a/crates/collab/src/tests/channel_tests.rs b/crates/collab/src/tests/channel_tests.rs index 2a88bc4c57..e80fe0fdca 100644 --- a/crates/collab/src/tests/channel_tests.rs +++ b/crates/collab/src/tests/channel_tests.rs @@ -1418,8 +1418,6 @@ async fn test_channel_moving( ) { let mut server = TestServer::start(executor.clone()).await; let client_a = server.create_client(cx_a, "user_a").await; - // let client_b = server.create_client(cx_b, "user_b").await; - // let client_c = server.create_client(cx_c, "user_c").await; let channels = server .make_channel_tree( diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 5ad3d6cfa3..13b378a341 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -1426,14 +1426,6 @@ impl CollabPanel { self.toggle_channel_collapsed(id, cx) } - // fn toggle_channel_collapsed_action( - // &mut self, - // action: &ToggleCollapse, - // cx: &mut ViewContext, - // ) { - // self.toggle_channel_collapsed(action.location, cx); - // } - fn toggle_channel_collapsed<'a>(&mut self, channel_id: ChannelId, cx: &mut ViewContext) { match self.collapsed_channels.binary_search(&channel_id) { Ok(ix) => { @@ -1910,7 +1902,6 @@ impl CollabPanel { let mut channel_link = None; let mut channel_tooltip_text = None; let mut channel_icon = None; - // let mut is_dragged_over = false; let text = match section { Section::ActiveCall => { diff --git a/crates/gpui/src/style.rs b/crates/gpui/src/style.rs index a21957611d..32b749c257 100644 --- a/crates/gpui/src/style.rs +++ b/crates/gpui/src/style.rs @@ -1,10 +1,10 @@ use std::{iter, mem, ops::Range}; use crate::{ - black, phi, point, quad, rems, AbsoluteLength, BorrowWindow, Bounds, ContentMask, Corners, - CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, - FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, SharedString, Size, - SizeRefinement, Styled, TextRun, WindowContext, + black, phi, point, quad, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, + ContentMask, Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, + Font, FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, + SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext, }; use collections::HashSet; use refineable::{Cascade, Refineable}; @@ -308,54 +308,54 @@ impl Style { } } - // pub fn apply_text_style(&self, cx: &mut C, f: F) -> R - // where - // C: BorrowAppContext, - // F: FnOnce(&mut C) -> R, - // { - // if self.text.is_some() { - // cx.with_text_style(Some(self.text.clone()), f) - // } else { - // f(cx) - // } - // } + pub fn apply_text_style(&self, cx: &mut C, f: F) -> R + where + C: BorrowAppContext, + F: FnOnce(&mut C) -> R, + { + if self.text.is_some() { + cx.with_text_style(Some(self.text.clone()), f) + } else { + f(cx) + } + } - // /// Apply overflow to content mask - // pub fn apply_overflow(&self, bounds: Bounds, cx: &mut C, f: F) -> R - // where - // C: BorrowWindow, - // F: FnOnce(&mut C) -> R, - // { - // let current_mask = cx.content_mask(); + /// Apply overflow to content mask + pub fn apply_overflow(&self, bounds: Bounds, cx: &mut C, f: F) -> R + where + C: BorrowWindow, + F: FnOnce(&mut C) -> R, + { + let current_mask = cx.content_mask(); - // let min = current_mask.bounds.origin; - // let max = current_mask.bounds.lower_right(); + let min = current_mask.bounds.origin; + let max = current_mask.bounds.lower_right(); - // let mask_bounds = match ( - // self.overflow.x == Overflow::Visible, - // self.overflow.y == Overflow::Visible, - // ) { - // // x and y both visible - // (true, true) => return f(cx), - // // x visible, y hidden - // (true, false) => Bounds::from_corners( - // point(min.x, bounds.origin.y), - // point(max.x, bounds.lower_right().y), - // ), - // // x hidden, y visible - // (false, true) => Bounds::from_corners( - // point(bounds.origin.x, min.y), - // point(bounds.lower_right().x, max.y), - // ), - // // both hidden - // (false, false) => bounds, - // }; - // let mask = ContentMask { - // bounds: mask_bounds, - // }; + let mask_bounds = match ( + self.overflow.x == Overflow::Visible, + self.overflow.y == Overflow::Visible, + ) { + // x and y both visible + (true, true) => return f(cx), + // x visible, y hidden + (true, false) => Bounds::from_corners( + point(min.x, bounds.origin.y), + point(max.x, bounds.lower_right().y), + ), + // x hidden, y visible + (false, true) => Bounds::from_corners( + point(bounds.origin.x, min.y), + point(bounds.lower_right().x, max.y), + ), + // both hidden + (false, false) => bounds, + }; + let mask = ContentMask { + bounds: mask_bounds, + }; - // cx.with_content_mask(Some(mask), f) - // } + cx.with_content_mask(Some(mask), f) + } /// Paints the background of an element styled with this style. pub fn paint( diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 509a6d8466..470f076d78 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -3137,13 +3137,6 @@ impl AnyWindowHandle { } } -// #[cfg(any(test, feature = "test-support"))] -// impl From> for StackingOrder { -// fn from(small_vec: SmallVec<[u32; 16]>) -> Self { -// StackingOrder(small_vec) -// } -// } - /// An identifier for an [`Element`](crate::Element). /// /// Can be constructed with a string, a number, or both, as well diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 06b6da75b3..5f37bbfce6 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -99,20 +99,6 @@ pub trait Item { fn project_path(&self, cx: &AppContext) -> Option; } -// Language server state is stored across 3 collections: -// language_servers => -// a mapping from unique server id to LanguageServerState which can either be a task for a -// server in the process of starting, or a running server with adapter and language server arcs -// language_server_ids => a mapping from worktreeId and server name to the unique server id -// language_server_statuses => a mapping from unique server id to the current server status -// -// Multiple worktrees can map to the same language server for example when you jump to the definition -// of a file in the standard library. So language_server_ids is used to look up which server is active -// for a given worktree and language server name -// -// When starting a language server, first the id map is checked to make sure a server isn't already available -// for that worktree. If there is one, it finishes early. Otherwise, a new id is allocated and and -// the Starting variant of LanguageServerState is stored in the language_servers map. pub struct Project { worktrees: Vec, active_entry: Option, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 251e26ebfb..ef48cd6832 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -221,10 +221,10 @@ impl ProjectPanel { }) .detach(); - // cx.observe_global::(|_, cx| { - // cx.notify(); - // }) - // .detach(); + cx.observe_global::(|_, cx| { + cx.notify(); + }) + .detach(); let mut this = Self { project: project.clone(), @@ -292,16 +292,16 @@ impl ProjectPanel { } &Event::SplitEntry { entry_id } => { if let Some(worktree) = project.read(cx).worktree_for_entry(entry_id, cx) { - if let Some(_entry) = worktree.read(cx).entry_for_id(entry_id) { - // workspace - // .split_path( - // ProjectPath { - // worktree_id: worktree.read(cx).id(), - // path: entry.path.clone(), - // }, - // cx, - // ) - // .detach_and_log_err(cx); + if let Some(entry) = worktree.read(cx).entry_for_id(entry_id) { + workspace + .split_path( + ProjectPath { + worktree_id: worktree.read(cx).id(), + path: entry.path.clone(), + }, + cx, + ) + .detach_and_log_err(cx); } } } @@ -788,10 +788,6 @@ impl ProjectPanel { cx.notify(); } } - - // cx.update_global(|drag_and_drop: &mut DragAndDrop, cx| { - // drag_and_drop.cancel_dragging::(cx); - // }) } } diff --git a/crates/rich_text/src/rich_text.rs b/crates/rich_text/src/rich_text.rs index b4a87b1e5d..83dd007308 100644 --- a/crates/rich_text/src/rich_text.rs +++ b/crates/rich_text/src/rich_text.rs @@ -1,3 +1,4 @@ +use anyhow::bail; use futures::FutureExt; use gpui::{ AnyElement, ElementId, FontStyle, FontWeight, HighlightStyle, InteractiveText, IntoElement, @@ -85,31 +86,6 @@ impl RichText { }) .into_any_element() } - - // pub fn add_mention( - // &mut self, - // range: Range, - // is_current_user: bool, - // mention_style: HighlightStyle, - // ) -> anyhow::Result<()> { - // if range.end > self.text.len() { - // bail!( - // "Mention in range {range:?} is outside of bounds for a message of length {}", - // self.text.len() - // ); - // } - - // if is_current_user { - // self.region_ranges.push(range.clone()); - // self.regions.push(RenderedRegion { - // background_kind: Some(BackgroundKind::Mention), - // link_url: None, - // }); - // } - // self.highlights - // .push((range, Highlight::Highlight(mention_style))); - // Ok(()) - // } } pub fn render_markdown_mut( @@ -272,13 +248,6 @@ pub fn render_markdown( language_registry: &Arc, language: Option<&Arc>, ) -> RichText { - // let mut data = RichText { - // text: Default::default(), - // highlights: Default::default(), - // region_ranges: Default::default(), - // regions: Default::default(), - // }; - let mut text = String::new(); let mut highlights = Vec::new(); let mut link_ranges = Vec::new(); diff --git a/crates/rpc/build.rs b/crates/rpc/build.rs index 66b289f1db..25dff9b007 100644 --- a/crates/rpc/build.rs +++ b/crates/rpc/build.rs @@ -1,6 +1,5 @@ fn main() { let mut build = prost_build::Config::new(); - // build.protoc_arg("--experimental_allow_proto3_optional"); build .type_attribute(".", "#[derive(serde::Serialize)]") .compile_protos(&["proto/zed.proto"], &["proto"]) diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index f7e36fe696..9cbe49d99e 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -1648,7 +1648,6 @@ mod tests { #[gpui::test] async fn test_search_query_history(cx: &mut TestAppContext) { - //crate::project_search::tests::init_test(cx); init_globals(cx); let buffer_text = r#" A regular expression (shortened as regex or regexp;[1] also referred to as diff --git a/crates/semantic_index/src/semantic_index_tests.rs b/crates/semantic_index/src/semantic_index_tests.rs index ced08f4cbc..e340b44a58 100644 --- a/crates/semantic_index/src/semantic_index_tests.rs +++ b/crates/semantic_index/src/semantic_index_tests.rs @@ -1677,8 +1677,6 @@ fn elixir_lang() -> Arc { #[gpui::test] fn test_subtract_ranges() { - // collapsed_ranges: Vec>, keep_ranges: Vec> - assert_eq!( subtract_ranges(&[0..5, 10..21], &[0..1, 4..5]), vec![1..4, 10..21] From bfb59f1598e8e2497fd7e635c51340c7a40a07f1 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 20:59:19 -0800 Subject: [PATCH 18/31] Remove last stale code --- crates/collab_ui/src/collab_panel.rs | 2 +- crates/storybook/src/storybook.rs | 5 - .../ui/src/components/stories/icon_button.rs | 50 ------- crates/workspace/src/item.rs | 21 --- crates/workspace/src/pane.rs | 137 ------------------ crates/workspace/src/persistence.rs | 2 - crates/workspace/src/workspace.rs | 30 ---- crates/zed/src/languages/python.rs | 2 +- crates/zed/src/zed.rs | 6 - 9 files changed, 2 insertions(+), 253 deletions(-) diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 13b378a341..ca54aa49c8 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -2043,7 +2043,7 @@ impl CollabPanel { }), ) .start_slot( - // todo!() handle contacts with no avatar + // todo handle contacts with no avatar Avatar::new(contact.user.avatar_uri.clone()) .availability_indicator(if online { Some(!busy) } else { None }), ) diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 8d60e29a13..ceab82e12b 100644 --- a/crates/storybook/src/storybook.rs +++ b/crates/storybook/src/storybook.rs @@ -21,11 +21,6 @@ use crate::assets::Assets; use crate::story_selector::{ComponentStory, StorySelector}; pub use indoc::indoc; -// gpui::actions! { -// storybook, -// [ToggleInspector] -// } - #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Args { diff --git a/crates/ui/src/components/stories/icon_button.rs b/crates/ui/src/components/stories/icon_button.rs index 6a67183e97..df9f37b164 100644 --- a/crates/ui/src/components/stories/icon_button.rs +++ b/crates/ui/src/components/stories/icon_button.rs @@ -117,55 +117,5 @@ impl Render for IconButtonStory { ) .children(vec![StorySection::new().children(buttons)]) .into_element() - - // Story::container() - // .child(Story::title_for::()) - // .child(Story::label("Default")) - // .child(div().w_8().child(IconButton::new("icon_a", Icon::Hash))) - // .child(Story::label("Selected")) - // .child( - // div() - // .w_8() - // .child(IconButton::new("icon_a", Icon::Hash).selected(true)), - // ) - // .child(Story::label("Selected with `selected_icon`")) - // .child( - // div().w_8().child( - // IconButton::new("icon_a", Icon::AudioOn) - // .selected(true) - // .selected_icon(Icon::AudioOff), - // ), - // ) - // .child(Story::label("Disabled")) - // .child( - // div() - // .w_8() - // .child(IconButton::new("icon_a", Icon::Hash).disabled(true)), - // ) - // .child(Story::label("With `on_click`")) - // .child( - // div() - // .w_8() - // .child( - // IconButton::new("with_on_click", Icon::Ai).on_click(|_event, _cx| { - // println!("Clicked!"); - // }), - // ), - // ) - // .child(Story::label("With `tooltip`")) - // .child( - // div().w_8().child( - // IconButton::new("with_tooltip", Icon::MessageBubbles) - // .tooltip(|cx| Tooltip::text("Open messages", cx)), - // ), - // ) - // .child(Story::label("Selected with `tooltip`")) - // .child( - // div().w_8().child( - // IconButton::new("selected_with_tooltip", Icon::InlayHint) - // .selected(true) - // .tooltip(|cx| Tooltip::text("Toggle inlay hints", cx)), - // ), - // ) } } diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index c629edc696..fb4ed05f6c 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -809,27 +809,6 @@ pub mod test { Edit, } - // impl Clone for TestItem { - // fn clone(&self) -> Self { - // Self { - // state: self.state.clone(), - // label: self.label.clone(), - // save_count: self.save_count, - // save_as_count: self.save_as_count, - // reload_count: self.reload_count, - // is_dirty: self.is_dirty, - // is_singleton: self.is_singleton, - // has_conflict: self.has_conflict, - // project_items: self.project_items.clone(), - // nav_history: None, - // tab_descriptions: None, - // tab_detail: Default::default(), - // workspace_id: self.workspace_id, - // focus_handle: self.focus_handle.clone(), - // } - // } - // } - impl TestProjectItem { pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Model { let entry_id = Some(ProjectEntryId::from_proto(id)); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index aec33c2dd3..1b95671398 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -60,24 +60,6 @@ pub enum SaveIntent { #[derive(Clone, Deserialize, PartialEq, Debug)] pub struct ActivateItem(pub usize); -// #[derive(Clone, PartialEq)] -// pub struct CloseItemById { -// pub item_id: usize, -// pub pane: WeakView, -// } - -// #[derive(Clone, PartialEq)] -// pub struct CloseItemsToTheLeftById { -// pub item_id: usize, -// pub pane: WeakView, -// } - -// #[derive(Clone, PartialEq)] -// pub struct CloseItemsToTheRightById { -// pub item_id: usize, -// pub pane: WeakView, -// } - #[derive(Clone, PartialEq, Debug, Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct CloseActiveItem { @@ -1226,125 +1208,6 @@ impl Pane { cx.emit(Event::Split(direction)); } - // fn deploy_split_menu(&mut self, cx: &mut ViewContext) { - // self.tab_bar_context_menu.handle.update(cx, |menu, cx| { - // menu.toggle( - // Default::default(), - // AnchorCorner::TopRight, - // vec![ - // ContextMenuItem::action("Split Right", SplitRight), - // ContextMenuItem::action("Split Left", SplitLeft), - // ContextMenuItem::action("Split Up", SplitUp), - // ContextMenuItem::action("Split Down", SplitDown), - // ], - // cx, - // ); - // }); - - // self.tab_bar_context_menu.kind = TabBarContextMenuKind::Split; - // } - - // fn deploy_new_menu(&mut self, cx: &mut ViewContext) { - // self.tab_bar_context_menu.handle.update(cx, |menu, cx| { - // menu.toggle( - // Default::default(), - // AnchorCorner::TopRight, - // vec![ - // ContextMenuItem::action("New File", NewFile), - // ContextMenuItem::action("New Terminal", NewCenterTerminal), - // ContextMenuItem::action("New Search", NewSearch), - // ], - // cx, - // ); - // }); - - // self.tab_bar_context_menu.kind = TabBarContextMenuKind::New; - // } - - // fn deploy_tab_context_menu( - // &mut self, - // position: Vector2F, - // target_item_id: usize, - // cx: &mut ViewContext, - // ) { - // let active_item_id = self.items[self.active_item_index].id(); - // let is_active_item = target_item_id == active_item_id; - // let target_pane = cx.weak_handle(); - - // // The `CloseInactiveItems` action should really be called "CloseOthers" and the behaviour should be dynamically based on the tab the action is ran on. Currently, this is a weird action because you can run it on a non-active tab and it will close everything by the actual active tab - - // self.tab_context_menu.update(cx, |menu, cx| { - // menu.show( - // position, - // AnchorCorner::TopLeft, - // if is_active_item { - // vec![ - // ContextMenuItem::action( - // "Close Active Item", - // CloseActiveItem { save_intent: None }, - // ), - // ContextMenuItem::action("Close Inactive Items", CloseInactiveItems), - // ContextMenuItem::action("Close Clean Items", CloseCleanItems), - // ContextMenuItem::action("Close Items To The Left", CloseItemsToTheLeft), - // ContextMenuItem::action("Close Items To The Right", CloseItemsToTheRight), - // ContextMenuItem::action( - // "Close All Items", - // CloseAllItems { save_intent: None }, - // ), - // ] - // } else { - // // In the case of the user right clicking on a non-active tab, for some item-closing commands, we need to provide the id of the tab, for the others, we can reuse the existing command. - // vec![ - // ContextMenuItem::handler("Close Inactive Item", { - // let pane = target_pane.clone(); - // move |cx| { - // if let Some(pane) = pane.upgrade(cx) { - // pane.update(cx, |pane, cx| { - // pane.close_item_by_id( - // target_item_id, - // SaveIntent::Close, - // cx, - // ) - // .detach_and_log_err(cx); - // }) - // } - // } - // }), - // ContextMenuItem::action("Close Inactive Items", CloseInactiveItems), - // ContextMenuItem::action("Close Clean Items", CloseCleanItems), - // ContextMenuItem::handler("Close Items To The Left", { - // let pane = target_pane.clone(); - // move |cx| { - // if let Some(pane) = pane.upgrade(cx) { - // pane.update(cx, |pane, cx| { - // pane.close_items_to_the_left_by_id(target_item_id, cx) - // .detach_and_log_err(cx); - // }) - // } - // } - // }), - // ContextMenuItem::handler("Close Items To The Right", { - // let pane = target_pane.clone(); - // move |cx| { - // if let Some(pane) = pane.upgrade(cx) { - // pane.update(cx, |pane, cx| { - // pane.close_items_to_the_right_by_id(target_item_id, cx) - // .detach_and_log_err(cx); - // }) - // } - // } - // }), - // ContextMenuItem::action( - // "Close All Items", - // CloseAllItems { save_intent: None }, - // ), - // ] - // }, - // cx, - // ); - // }); - // } - pub fn toolbar(&self) -> &View { &self.toolbar } diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index d03c7b3d0f..56aa6e4322 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -1,5 +1,3 @@ -//#![allow(dead_code)] - pub mod model; use std::path::Path; diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ca463e76e0..efd2c52989 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -3324,36 +3324,6 @@ impl Workspace { workspace } - // fn render_dock(&self, position: DockPosition, cx: &WindowContext) -> Option> { - // let dock = match position { - // DockPosition::Left => &self.left_dock, - // DockPosition::Right => &self.right_dock, - // DockPosition::Bottom => &self.bottom_dock, - // }; - // let active_panel = dock.read(cx).visible_panel()?; - // let element = if Some(active_panel.id()) == self.zoomed.as_ref().map(|zoomed| zoomed.id()) { - // dock.read(cx).render_placeholder(cx) - // } else { - // ChildView::new(dock, cx).into_any() - // }; - - // Some( - // element - // .constrained() - // .dynamically(move |constraint, _, cx| match position { - // DockPosition::Left | DockPosition::Right => SizeConstraint::new( - // Vector2F::new(20., constraint.min.y()), - // Vector2F::new(cx.window_size().x() * 0.8, constraint.max.y()), - // ), - // DockPosition::Bottom => SizeConstraint::new( - // Vector2F::new(constraint.min.x(), 20.), - // Vector2F::new(constraint.max.x(), cx.window_size().y() * 0.8), - // ), - // }) - // .into_any(), - // ) - // } - // } pub fn register_action( &mut self, callback: impl Fn(&mut Self, &A, &mut ViewContext) + 'static, diff --git a/crates/zed/src/languages/python.rs b/crates/zed/src/languages/python.rs index d28cd9f6e4..8a30121d49 100644 --- a/crates/zed/src/languages/python.rs +++ b/crates/zed/src/languages/python.rs @@ -184,7 +184,7 @@ mod tests { #[gpui::test] async fn test_python_autoindent(cx: &mut TestAppContext) { - // cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX); + cx.executor().set_block_on_ticks(usize::MAX..=usize::MAX); let language = crate::languages::language("python", tree_sitter_python::language(), None).await; cx.update(|cx| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index c2725eef64..d7686c425a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -113,12 +113,6 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { }) .detach(); - // cx.emit(workspace::Event::PaneAdded(workspace.active_pane().clone())); - - // let collab_titlebar_item = - // cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx)); - // workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx); - let copilot = cx.new_view(|cx| copilot_ui::CopilotButton::new(app_state.fs.clone(), cx)); let diagnostic_summary = cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx)); From bb35805f9bf0dcd9d505e26613b3ffa1f95b3a4b Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 21:02:01 -0800 Subject: [PATCH 19/31] fmt --- crates/rich_text/src/rich_text.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/rich_text/src/rich_text.rs b/crates/rich_text/src/rich_text.rs index 83dd007308..771f560236 100644 --- a/crates/rich_text/src/rich_text.rs +++ b/crates/rich_text/src/rich_text.rs @@ -1,4 +1,3 @@ -use anyhow::bail; use futures::FutureExt; use gpui::{ AnyElement, ElementId, FontStyle, FontWeight, HighlightStyle, InteractiveText, IntoElement, From 78858d4d11de009a3c54beea87d8c3022707ec1d Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 21:11:17 -0800 Subject: [PATCH 20/31] Disable searches for '.', so that users with large monitors don't accidentally crash the terminal when searching for dot files. --- crates/terminal_view/src/terminal_view.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index ced122402f..98a04eb5f5 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -600,6 +600,9 @@ fn possible_open_targets( pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option { let query = query.as_str(); + if query == "." { + return None; + } let searcher = RegexSearch::new(&query); searcher.ok() } From 1d7dc96135fcf5b7dea358aeaa6d23f52d9eee9f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 21:37:09 -0800 Subject: [PATCH 21/31] Restore temp file initialization in telemetry code --- crates/client/src/telemetry.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index aa0c7c4af5..ee00161440 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -14,6 +14,7 @@ use sysinfo::{ }; use tempfile::NamedTempFile; use util::http::HttpClient; +use util::ResultExt; use util::{channel::ReleaseChannel, TryFutureExt}; use self::event_coalescer::EventCoalescer; @@ -167,6 +168,19 @@ impl Telemetry { event_coalescer: EventCoalescer::new(), })); + cx.background_executor() + .spawn({ + let state = state.clone(); + async move { + if let Some(tempfile) = + NamedTempFile::new_in(util::paths::CONFIG_DIR.as_path()).log_err() + { + state.lock().log_file = Some(tempfile); + } + } + }) + .detach(); + cx.observe_global::({ let state = state.clone(); From 4d6dfa319d5d85211a71d0a0837d94732f0bcaff Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 12 Jan 2024 22:44:07 -0800 Subject: [PATCH 22/31] Don't open files unescessary in dev builds --- crates/client/src/telemetry.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index ee00161440..ca717c9d6a 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -14,6 +14,7 @@ use sysinfo::{ }; use tempfile::NamedTempFile; use util::http::HttpClient; +#[cfg(not(debug_assertions))] use util::ResultExt; use util::{channel::ReleaseChannel, TryFutureExt}; @@ -168,6 +169,7 @@ impl Telemetry { event_coalescer: EventCoalescer::new(), })); + #[cfg(not(debug_assertions))] cx.background_executor() .spawn({ let state = state.clone(); From c2ff9fe2da012be54a78b3d335bb3983aeb424d2 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 14:32:24 -0700 Subject: [PATCH 23/31] Don't lose focus on default panel state --- crates/collab_ui/src/chat_panel.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index ecd7d1a739..20c5857ad2 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -59,6 +59,7 @@ pub struct ChatPanel { subscriptions: Vec, is_scrolled_to_bottom: bool, markdown_data: HashMap, + focus_handle: FocusHandle, } #[derive(Serialize, Deserialize)] @@ -126,6 +127,7 @@ impl ChatPanel { active: false, width: None, markdown_data: Default::default(), + focus_handle: cx.focus_handle(), }; let mut old_dock_position = this.position(cx); @@ -490,6 +492,7 @@ impl EventEmitter for ChatPanel {} impl Render for ChatPanel { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_stack() + .track_focus(&self.focus_handle) .full() .on_action(cx.listener(Self::send)) .child( @@ -559,7 +562,11 @@ impl Render for ChatPanel { impl FocusableView for ChatPanel { fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { - self.message_editor.read(cx).focus_handle(cx) + if self.active_chat.is_some() { + self.message_editor.read(cx).focus_handle(cx) + } else { + self.focus_handle.clone() + } } } From f6ef07e7166eadbb4e65de941e4c5422162319d5 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 21:37:13 -0700 Subject: [PATCH 24/31] Make chat prettier (to my eyes at least) --- crates/channel/src/channel_chat.rs | 4 +- crates/collab_ui/src/chat_panel.rs | 106 ++++++++++++++++++++++------- crates/gpui/src/styled.rs | 11 ++- crates/ui/src/components/avatar.rs | 10 ++- 4 files changed, 101 insertions(+), 30 deletions(-) diff --git a/crates/channel/src/channel_chat.rs b/crates/channel/src/channel_chat.rs index d2250972f3..e9353a1441 100644 --- a/crates/channel/src/channel_chat.rs +++ b/crates/channel/src/channel_chat.rs @@ -144,7 +144,7 @@ impl ChannelChat { message: MessageParams, cx: &mut ModelContext, ) -> Result>> { - if message.text.is_empty() { + if message.text.trim().is_empty() { Err(anyhow!("message body can't be empty"))?; } @@ -174,6 +174,8 @@ impl ChannelChat { let user_store = self.user_store.clone(); let rpc = self.rpc.clone(); let outgoing_messages_lock = self.outgoing_messages_lock.clone(); + + // todo - handle messages that fail to send (e.g. >1024 chars) Ok(cx.spawn(move |this, mut cx| async move { let outgoing_message_guard = outgoing_messages_lock.lock().await; let request = rpc.request(proto::SendChannelMessage { diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index 20c5857ad2..dd3d741522 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -8,8 +8,9 @@ use db::kvp::KEY_VALUE_STORE; use editor::Editor; use gpui::{ actions, div, list, prelude::*, px, Action, AnyElement, AppContext, AsyncWindowContext, - ClickEvent, ElementId, EventEmitter, FocusHandle, FocusableView, ListOffset, ListScrollEvent, - ListState, Model, Render, Subscription, Task, View, ViewContext, VisualContext, WeakView, + ClickEvent, DismissEvent, ElementId, EventEmitter, FocusHandle, FocusableView, FontWeight, + ListOffset, ListScrollEvent, ListState, Model, Render, Subscription, Task, View, ViewContext, + VisualContext, WeakView, }; use language::LanguageRegistry; use menu::Confirm; @@ -22,7 +23,8 @@ use settings::{Settings, SettingsStore}; use std::sync::Arc; use time::{OffsetDateTime, UtcOffset}; use ui::{ - prelude::*, Avatar, Button, IconButton, IconName, Key, KeyBinding, Label, TabBar, Tooltip, + popover_menu, prelude::*, Avatar, Button, ContextMenu, IconButton, IconName, Key, KeyBinding, + Label, TabBar, Tooltip, }; use util::{ResultExt, TryFutureExt}; use workspace::{ @@ -60,6 +62,7 @@ pub struct ChatPanel { is_scrolled_to_bottom: bool, markdown_data: HashMap, focus_handle: FocusHandle, + open_context_menu: Option<(u64, Subscription)>, } #[derive(Serialize, Deserialize)] @@ -128,6 +131,7 @@ impl ChatPanel { width: None, markdown_data: Default::default(), focus_handle: cx.focus_handle(), + open_context_menu: None, }; let mut old_dock_position = this.position(cx); @@ -348,50 +352,100 @@ impl ChatPanel { ChannelMessageId::Saved(id) => ("saved-message", id).into(), ChannelMessageId::Pending(id) => ("pending-message", id).into(), }; + let this = cx.view().clone(); v_stack() .w_full() - .id(element_id) .relative() .overflow_hidden() - .group("") .when(!is_continuation_from_previous, |this| { - this.child( + this.pt_3().child( h_stack() - .gap_2() - .child(Avatar::new(message.sender.avatar_uri.clone())) - .child(Label::new(message.sender.github_login.clone())) + .child( + div().absolute().child( + Avatar::new(message.sender.avatar_uri.clone()) + .size(cx.rem_size() * 1.5), + ), + ) + .child( + div() + .pl(cx.rem_size() * 1.5 + px(6.0)) + .pr(px(8.0)) + .font_weight(FontWeight::BOLD) + .child(Label::new(message.sender.github_login.clone())), + ) .child( Label::new(format_timestamp( message.timestamp, now, self.local_timezone, )) + .size(LabelSize::Small) .color(Color::Muted), ), ) }) - .when(!is_continuation_to_next, |this| - // HACK: This should really be a margin, but margins seem to get collapsed. - this.pb_2()) - .child(text.element("body".into(), cx)) + .when(is_continuation_from_previous, |this| this.pt_1()) .child( - div() - .absolute() - .top_1() - .right_2() - .w_8() - .visible_on_hover("") - .children(message_id_to_remove.map(|message_id| { - IconButton::new(("remove", message_id), IconName::XCircle).on_click( - cx.listener(move |this, _, cx| { - this.remove_message(message_id, cx); - }), - ) - })), + v_stack() + .w_full() + .text_ui_sm() + .id(element_id) + .group("") + .child(text.element("body".into(), cx)) + .child( + div() + .absolute() + .z_index(1) + .right_0() + .w_6() + .bg(cx.theme().colors().panel_background) + .when(!self.has_open_menu(message_id_to_remove), |el| { + el.visible_on_hover("") + }) + .children(message_id_to_remove.map(|message_id| { + popover_menu(("menu", message_id)) + .trigger(IconButton::new( + ("trigger", message_id), + IconName::Ellipsis, + )) + .menu(move |cx| { + Some(Self::render_message_menu(&this, message_id, cx)) + }) + })), + ), ) } + fn has_open_menu(&self, message_id: Option) -> bool { + match self.open_context_menu.as_ref() { + Some((id, _)) => Some(*id) == message_id, + None => false, + } + } + + fn render_message_menu( + this: &View, + message_id: u64, + cx: &mut WindowContext, + ) -> View { + let menu = { + let this = this.clone(); + ContextMenu::build(cx, move |menu, _| { + menu.entry("Delete message", None, move |cx| { + this.update(cx, |this, cx| this.remove_message(message_id, cx)) + }) + }) + }; + this.update(cx, |this, cx| { + let subscription = cx.subscribe(&menu, |this: &mut Self, _, _: &DismissEvent, _| { + this.open_context_menu = None; + }); + this.open_context_menu = Some((message_id, subscription)); + }); + menu + } + fn render_markdown_with_mentions( language_registry: &Arc, current_user_id: u64, diff --git a/crates/gpui/src/styled.rs b/crates/gpui/src/styled.rs index 2749c31a78..0eba1771f5 100644 --- a/crates/gpui/src/styled.rs +++ b/crates/gpui/src/styled.rs @@ -1,7 +1,7 @@ use crate::{ self as gpui, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle, - DefiniteLength, Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position, - SharedString, StyleRefinement, Visibility, WhiteSpace, + DefiniteLength, Display, Fill, FlexDirection, FontWeight, Hsla, JustifyContent, Length, + Position, SharedString, StyleRefinement, Visibility, WhiteSpace, }; use crate::{BoxShadow, TextStyleRefinement}; use smallvec::{smallvec, SmallVec}; @@ -494,6 +494,13 @@ pub trait Styled: Sized { self } + fn font_weight(mut self, weight: FontWeight) -> Self { + self.text_style() + .get_or_insert_with(Default::default) + .font_weight = Some(weight); + self + } + fn text_bg(mut self, bg: impl Into) -> Self { self.text_style() .get_or_insert_with(Default::default) diff --git a/crates/ui/src/components/avatar.rs b/crates/ui/src/components/avatar.rs index 9e64e1223c..a97adb73b7 100644 --- a/crates/ui/src/components/avatar.rs +++ b/crates/ui/src/components/avatar.rs @@ -26,6 +26,7 @@ pub enum AvatarShape { #[derive(IntoElement)] pub struct Avatar { image: Img, + size: Option, border_color: Option, is_available: Option, } @@ -36,7 +37,7 @@ impl RenderOnce for Avatar { self = self.shape(AvatarShape::Circle); } - let size = cx.rem_size(); + let size = self.size.unwrap_or_else(|| cx.rem_size()); div() .size(size + px(2.)) @@ -78,6 +79,7 @@ impl Avatar { image: img(src), is_available: None, border_color: None, + size: None, } } @@ -124,4 +126,10 @@ impl Avatar { self.is_available = is_available.into(); self } + + /// Size overrides the avatar size. By default they are 1rem. + pub fn size(mut self, size: impl Into>) -> Self { + self.size = size.into(); + self + } } From c810af40d3a63ef7c82696101c6023e66b6e1185 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 21:53:22 -0700 Subject: [PATCH 25/31] Fix multiple mentions in one message --- crates/collab/src/db/queries/messages.rs | 1 + crates/rich_text/src/rich_text.rs | 28 +++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/crates/collab/src/db/queries/messages.rs b/crates/collab/src/db/queries/messages.rs index 47bb27df39..96942c052d 100644 --- a/crates/collab/src/db/queries/messages.rs +++ b/crates/collab/src/db/queries/messages.rs @@ -256,6 +256,7 @@ impl Database { message_id = result.last_insert_id; let mentioned_user_ids = mentions.iter().map(|m| m.user_id).collect::>(); + let mentions = mentions .iter() .filter_map(|mention| { diff --git a/crates/rich_text/src/rich_text.rs b/crates/rich_text/src/rich_text.rs index b4a87b1e5d..ac3414555a 100644 --- a/crates/rich_text/src/rich_text.rs +++ b/crates/rich_text/src/rich_text.rs @@ -39,6 +39,7 @@ pub struct RichText { /// Allows one to specify extra links to the rendered markdown, which can be used /// for e.g. mentions. +#[derive(Debug)] pub struct Mention { pub range: Range, pub is_self_mention: bool, @@ -138,20 +139,21 @@ pub fn render_markdown_mut( if let Some(language) = ¤t_language { render_code(text, highlights, t.as_ref(), language); } else { - if let Some(mention) = mentions.first() { - if source_range.contains_inclusive(&mention.range) { - mentions = &mentions[1..]; - let range = (prev_len + mention.range.start - source_range.start) - ..(prev_len + mention.range.end - source_range.start); - highlights.push(( - range.clone(), - if mention.is_self_mention { - Highlight::SelfMention - } else { - Highlight::Mention - }, - )); + while let Some(mention) = mentions.first() { + if !source_range.contains_inclusive(&mention.range) { + break; } + mentions = &mentions[1..]; + let range = (prev_len + mention.range.start - source_range.start) + ..(prev_len + mention.range.end - source_range.start); + highlights.push(( + range.clone(), + if mention.is_self_mention { + Highlight::SelfMention + } else { + Highlight::Mention + }, + )); } text.push_str(t.as_ref()); From 818cbb24157334adac4a448c237e0ab35019e41c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 22:19:21 -0700 Subject: [PATCH 26/31] Show a border when scrolled in chat --- crates/collab_ui/src/chat_panel.rs | 37 ++++++++++++++++++------------ crates/gpui/src/elements/list.rs | 2 ++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index dd3d741522..ee0241eb12 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -112,7 +112,7 @@ impl ChatPanel { if event.visible_range.start < MESSAGE_LOADING_THRESHOLD { this.load_more_messages(cx); } - this.is_scrolled_to_bottom = event.visible_range.end == event.count; + this.is_scrolled_to_bottom = !event.is_scrolled; })); let mut this = Self { @@ -567,7 +567,7 @@ impl Render for ChatPanel { ), ), ) - .child(div().flex_grow().px_2().py_1().map(|this| { + .child(div().flex_grow().px_2().pt_1().map(|this| { if self.active_chat.is_some() { this.child(list(self.message_list.clone()).full()) } else { @@ -597,19 +597,26 @@ impl Render for ChatPanel { ) } })) - .child(h_stack().p_2().map(|el| { - if self.active_chat.is_some() { - el.child(self.message_editor.clone()) - } else { - el.child( - div() - .rounded_md() - .h_7() - .w_full() - .bg(cx.theme().colors().editor_background), - ) - } - })) + .child( + h_stack() + .when(!self.is_scrolled_to_bottom, |el| { + el.border_t_1().border_color(cx.theme().colors().border) + }) + .p_2() + .map(|el| { + if self.active_chat.is_some() { + el.child(self.message_editor.clone()) + } else { + el.child( + div() + .rounded_md() + .h_7() + .w_full() + .bg(cx.theme().colors().editor_background), + ) + } + }), + ) .into_any() } } diff --git a/crates/gpui/src/elements/list.rs b/crates/gpui/src/elements/list.rs index 2a47a16741..50e7af5138 100644 --- a/crates/gpui/src/elements/list.rs +++ b/crates/gpui/src/elements/list.rs @@ -43,6 +43,7 @@ pub enum ListAlignment { pub struct ListScrollEvent { pub visible_range: Range, pub count: usize, + pub is_scrolled: bool, } #[derive(Clone)] @@ -253,6 +254,7 @@ impl StateInner { &ListScrollEvent { visible_range, count: self.items.summary().count, + is_scrolled: self.logical_scroll_top.is_some(), }, cx, ); From fee369bca1571fd00fd9c7b59f8fbc36bb96e6e0 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 22:26:25 -0700 Subject: [PATCH 27/31] Fix re-docking chat panel --- crates/collab_ui/src/chat_panel.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index ee0241eb12..13b217eec4 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -70,13 +70,6 @@ struct SerializedChatPanel { width: Option, } -#[derive(Debug)] -pub enum Event { - DockPositionChanged, - Focus, - Dismissed, -} - actions!(chat_panel, [ToggleFocus]); impl ChatPanel { @@ -140,7 +133,7 @@ impl ChatPanel { let new_dock_position = this.position(cx); if new_dock_position != old_dock_position { old_dock_position = new_dock_position; - cx.emit(Event::DockPositionChanged); + cx.emit(PanelEvent::ChangePosition); } cx.notify(); }, @@ -541,8 +534,6 @@ impl ChatPanel { } } -impl EventEmitter for ChatPanel {} - impl Render for ChatPanel { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_stack() @@ -662,7 +653,7 @@ impl Panel for ChatPanel { if active { self.acknowledge_last_message(cx); if !is_channels_feature_enabled(cx) { - cx.emit(Event::Dismissed); + cx.emit(PanelEvent::Close); } } } From e90ddba2c3ba63e6025fac42a0abdc7e1afdbc9c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 22:38:22 -0700 Subject: [PATCH 28/31] Default to Zed Sans for UI --- assets/settings/default.json | 2 +- crates/gpui/src/text_system.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index bd157c3e61..87cf0517a2 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -36,7 +36,7 @@ // }, "buffer_line_height": "comfortable", // The name of a font to use for rendering text in the UI - "ui_font_family": "Zed Mono", + "ui_font_family": "Zed Sans", // The OpenType features to enable for text in the UI "ui_font_features": { // Disable ligatures: diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs index d80c9163a9..6c84a7716f 100644 --- a/crates/gpui/src/text_system.rs +++ b/crates/gpui/src/text_system.rs @@ -59,7 +59,7 @@ impl TextSystem { fallback_font_stack: smallvec![ // TODO: This is currently Zed-specific. // We should allow GPUI users to provide their own fallback font stack. - font("Zed Mono"), + font("Zed Sans"), font("Helvetica") ], } From 898645681fe6e14e746988b376bdeffbebcb7090 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 22:35:33 -0700 Subject: [PATCH 29/31] Move settings subscription to dock Reduces likelihood of panels being unable to move themselves --- crates/assistant/src/assistant_panel.rs | 11 ----------- crates/collab_ui/src/chat_panel.rs | 11 ----------- crates/collab_ui/src/collab_panel.rs | 13 ------------- crates/project_panel/src/project_panel.rs | 12 ------------ crates/terminal_view/src/terminal_panel.rs | 9 --------- crates/workspace/src/dock.rs | 19 +++++++++++++------ 6 files changed, 13 insertions(+), 62 deletions(-) diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index d4743afb71..9519cfacdb 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -192,17 +192,6 @@ impl AssistantPanel { retrieve_context_in_next_inline_assist: false, }; - let mut old_dock_position = this.position(cx); - this.subscriptions = - vec![cx.observe_global::(move |this, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(PanelEvent::ChangePosition); - } - cx.notify(); - })]; - this }) }) diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index 13b217eec4..e5c3a13442 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -127,17 +127,6 @@ impl ChatPanel { open_context_menu: None, }; - let mut old_dock_position = this.position(cx); - this.subscriptions.push(cx.observe_global::( - move |this: &mut Self, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(PanelEvent::ChangePosition); - } - cx.notify(); - }, - )); this.subscriptions.push(cx.subscribe( &ActiveCall::global(cx), move |this: &mut Self, call, event: &room::Event, cx| match event { diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 5ad3d6cfa3..bbd24136ad 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -254,19 +254,6 @@ impl CollabPanel { this.update_entries(false, cx); - // Update the dock position when the setting changes. - let mut old_dock_position = this.position(cx); - this.subscriptions.push(cx.observe_global::( - move |this: &mut Self, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(PanelEvent::ChangePosition); - } - cx.notify(); - }, - )); - let active_call = ActiveCall::global(cx); this.subscriptions .push(cx.observe(&this.user_store, |this, _, cx| { diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 251e26ebfb..5fa8fb102d 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -246,18 +246,6 @@ impl ProjectPanel { }; this.update_visible_entries(None, cx); - // Update the dock position when the setting changes. - let mut old_dock_position = this.position(cx); - ProjectPanelSettings::register(cx); - cx.observe_global::(move |this, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(PanelEvent::ChangePosition); - } - }) - .detach(); - this }); diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index d0b52f5eb2..2156aad18a 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -159,15 +159,6 @@ impl TerminalPanel { height: None, _subscriptions: subscriptions, }; - let mut old_dock_position = this.position(cx); - cx.observe_global::(move |this, cx| { - let new_dock_position = this.position(cx); - if new_dock_position != old_dock_position { - old_dock_position = new_dock_position; - cx.emit(PanelEvent::ChangePosition); - } - }) - .detach(); this } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 0c75259726..742ff3b6f8 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -7,6 +7,7 @@ use gpui::{ }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use settings::SettingsStore; use std::sync::Arc; use ui::{h_stack, ContextMenu, IconButton, Tooltip}; use ui::{prelude::*, right_click_menu}; @@ -14,7 +15,6 @@ use ui::{prelude::*, right_click_menu}; const RESIZE_HANDLE_SIZE: Pixels = Pixels(6.); pub enum PanelEvent { - ChangePosition, ZoomIn, ZoomOut, Activate, @@ -177,7 +177,7 @@ impl DockPosition { struct PanelEntry { panel: Arc, - _subscriptions: [Subscription; 2], + _subscriptions: [Subscription; 3], } pub struct PanelButtons { @@ -321,9 +321,15 @@ impl Dock { ) { let subscriptions = [ cx.observe(&panel, |_, _, cx| cx.notify()), - cx.subscribe(&panel, move |this, panel, event, cx| match event { - PanelEvent::ChangePosition => { + cx.observe_global::({ + let workspace = workspace.clone(); + let panel = panel.clone(); + + move |this, cx| { let new_position = panel.read(cx).position(cx); + if new_position == this.position { + return; + } let Ok(new_dock) = workspace.update(cx, |workspace, cx| { if panel.is_zoomed(cx) { @@ -354,6 +360,8 @@ impl Dock { } }); } + }), + cx.subscribe(&panel, move |this, panel, event, cx| match event { PanelEvent::ZoomIn => { this.set_panel_zoomed(&panel.to_any(), true, cx); if !panel.focus_handle(cx).contains_focused(cx) { @@ -735,9 +743,8 @@ pub mod test { true } - fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, _: &mut ViewContext) { self.position = position; - cx.emit(PanelEvent::ChangePosition); } fn size(&self, _: &WindowContext) -> Pixels { From 4d87a67af8626a43f37c3458c4e9f04ed2414d4e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sat, 13 Jan 2024 22:44:47 -0700 Subject: [PATCH 30/31] Remove unused imports --- crates/assistant/src/assistant_panel.rs | 9 +++---- crates/collab_ui/src/chat_panel.rs | 29 +++++++--------------- crates/collab_ui/src/collab_panel.rs | 2 +- crates/project_panel/src/project_panel.rs | 2 +- crates/terminal_view/src/terminal_panel.rs | 2 +- 5 files changed, 16 insertions(+), 28 deletions(-) diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 9519cfacdb..2b0a0941c0 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -40,7 +40,7 @@ use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset a use project::Project; use search::{buffer_search::DivRegistrar, BufferSearchBar}; use semantic_index::{SemanticIndex, SemanticIndexStatus}; -use settings::{Settings, SettingsStore}; +use settings::Settings; use std::{ cell::Cell, cmp, @@ -165,7 +165,7 @@ impl AssistantPanel { cx.on_focus_in(&focus_handle, Self::focus_in).detach(); cx.on_focus_out(&focus_handle, Self::focus_out).detach(); - let mut this = Self { + Self { workspace: workspace_handle, active_editor_index: Default::default(), prev_active_editor_index: Default::default(), @@ -190,9 +190,7 @@ impl AssistantPanel { _watch_saved_conversations, semantic_index, retrieve_context_in_next_inline_assist: false, - }; - - this + } }) }) }) @@ -3122,6 +3120,7 @@ mod tests { use crate::MessageId; use ai::test::FakeCompletionProvider; use gpui::AppContext; + use settings::SettingsStore; #[gpui::test] fn test_inserting_and_removing_messages(cx: &mut AppContext) { diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index e5c3a13442..c919ceac9f 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -1,4 +1,4 @@ -use crate::{collab_panel, is_channels_feature_enabled, ChatPanelSettings, CollabPanel}; +use crate::{collab_panel, is_channels_feature_enabled, ChatPanelSettings}; use anyhow::Result; use call::{room, ActiveCall}; use channel::{ChannelChat, ChannelChatEvent, ChannelMessageId, ChannelStore}; @@ -7,24 +7,22 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use editor::Editor; use gpui::{ - actions, div, list, prelude::*, px, Action, AnyElement, AppContext, AsyncWindowContext, - ClickEvent, DismissEvent, ElementId, EventEmitter, FocusHandle, FocusableView, FontWeight, - ListOffset, ListScrollEvent, ListState, Model, Render, Subscription, Task, View, ViewContext, - VisualContext, WeakView, + actions, div, list, prelude::*, px, Action, AppContext, AsyncWindowContext, DismissEvent, + ElementId, EventEmitter, FocusHandle, FocusableView, FontWeight, ListOffset, ListScrollEvent, + ListState, Model, Render, Subscription, Task, View, ViewContext, VisualContext, WeakView, }; use language::LanguageRegistry; use menu::Confirm; use message_editor::MessageEditor; use project::Fs; use rich_text::RichText; -use rpc::proto; use serde::{Deserialize, Serialize}; -use settings::{Settings, SettingsStore}; +use settings::Settings; use std::sync::Arc; use time::{OffsetDateTime, UtcOffset}; use ui::{ - popover_menu, prelude::*, Avatar, Button, ContextMenu, IconButton, IconName, Key, KeyBinding, - Label, TabBar, Tooltip, + popover_menu, prelude::*, Avatar, Button, ContextMenu, IconButton, IconName, KeyBinding, Label, + TabBar, }; use util::{ResultExt, TryFutureExt}; use workspace::{ @@ -279,7 +277,7 @@ impl ChatPanel { fn render_message(&mut self, ix: usize, cx: &mut ViewContext) -> impl IntoElement { let active_chat = &self.active_chat.as_ref().unwrap().0; - let (message, is_continuation_from_previous, is_continuation_to_next, is_admin) = + let (message, is_continuation_from_previous, is_admin) = active_chat.update(cx, |active_chat, cx| { let is_admin = self .channel_store @@ -288,13 +286,9 @@ impl ChatPanel { let last_message = active_chat.message(ix.saturating_sub(1)); let this_message = active_chat.message(ix).clone(); - let next_message = - active_chat.message(ix.saturating_add(1).min(active_chat.message_count() - 1)); let is_continuation_from_previous = last_message.id != this_message.id && last_message.sender.id == this_message.sender.id; - let is_continuation_to_next = this_message.id != next_message.id - && this_message.sender.id == next_message.sender.id; if let ChannelMessageId::Saved(id) = this_message.id { if this_message @@ -306,12 +300,7 @@ impl ChatPanel { } } - ( - this_message, - is_continuation_from_previous, - is_continuation_to_next, - is_admin, - ) + (this_message, is_continuation_from_previous, is_admin) }); let _is_pending = message.is_pending(); diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index bbd24136ad..38569adb20 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -26,7 +26,7 @@ use menu::{Cancel, Confirm, SelectNext, SelectPrev}; use project::{Fs, Project}; use rpc::proto::{self, PeerId}; use serde_derive::{Deserialize, Serialize}; -use settings::{Settings, SettingsStore}; +use settings::Settings; use smallvec::SmallVec; use std::{mem, sync::Arc}; use theme::{ActiveTheme, ThemeSettings}; diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 5fa8fb102d..113900dcd2 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1,6 +1,6 @@ pub mod file_associations; mod project_panel_settings; -use settings::{Settings, SettingsStore}; +use settings::Settings; use db::kvp::KEY_VALUE_STORE; use editor::{scroll::autoscroll::Autoscroll, Cancel, Editor}; diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 2156aad18a..dee18ea73b 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use project::{Fs, ProjectEntryId}; use search::{buffer_search::DivRegistrar, BufferSearchBar}; use serde::{Deserialize, Serialize}; -use settings::{Settings, SettingsStore}; +use settings::Settings; use terminal::terminal_settings::{TerminalDockPosition, TerminalSettings}; use ui::{h_stack, ButtonCommon, Clickable, IconButton, IconSize, Selectable, Tooltip}; use util::{ResultExt, TryFutureExt}; From b34c78016fe051cef04547c89b5a74b1181c5ec3 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Sun, 14 Jan 2024 12:26:54 -0700 Subject: [PATCH 31/31] Fix tests for TestPanel --- crates/workspace/src/dock.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 742ff3b6f8..52f768e03f 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -743,8 +743,9 @@ pub mod test { true } - fn set_position(&mut self, position: DockPosition, _: &mut ViewContext) { + fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { self.position = position; + cx.update_global::(|_, _| {}); } fn size(&self, _: &WindowContext) -> Pixels {