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 5dc7c42b02f387fe76295e9ae110f28972ef8450..e6eed28b66b9fe73ceb8c1c40fb2f5a6a298ec15 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 e6eed28b66b9fe73ceb8c1c40fb2f5a6a298ec15..3174376736c79817fe077702a1483a61a283d04e 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 3174376736c79817fe077702a1483a61a283d04e..d2f648ea8fa1e0cc7d2a1d9b0eb508d7088b3455 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 d2f648ea8fa1e0cc7d2a1d9b0eb508d7088b3455..25020e4e4c5399026c1ab32622903a3779ba86b2 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 0000000000000000000000000000000000000000..e4ade6fbed6e77dd7fc791ed33988c02020f0078 --- /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 8cbfc23fa34655283ddaa5418e15922929c1b5bc..fb88afb7dacf79d947a170e26136b293d093542b 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 d0bae590f6d32797ec65b34eb39de13d4befe177..fab3631d13ca890ca3ccb9fa2e06605534602abd 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 434183e5606135cdcb7e420c023c1108d0aa0a42..1c9fd789d958a1d0b886ab23e62232fc219589d3 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 87d2e9aa78df53676d003de0fd044cbab797bc5a..a37cc3bc789a569e86e770712a1cc8ec58820352 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 45c6c15fb00a4cc42131d7b3acfa8524201044c1..6dae1e6a4d5e7ad5ba0b8b96a5622fa323f4194c 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 5786ab10d4ca59b998b1b16ea7bb3c53611b4399..bbe0a6b4fe39541c12bf66db246f6a039fe6850d 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 a37cc3bc789a569e86e770712a1cc8ec58820352..72bb6a4e6e81ddd6dad6bcd78a8e4125130fa37e 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 6dae1e6a4d5e7ad5ba0b8b96a5622fa323f4194c..23a6ea4a1cd44eba03db92f40dca867eafb7a9f3 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 bbe0a6b4fe39541c12bf66db246f6a039fe6850d..a170f956978f1a8a999f3c5460db4d103f18cb3e 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 7fe942f14561c8781b17c9ae66ea356190425422..66d30b049cb396651368d77c345c7b50e5c6554d 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 | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index a6cdd166d312d5eb97fc749a645a8cb09ea0dd8a..2a1f9ef92def62b85b436f053c37e74c9600c00e 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,23 +587,33 @@ 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" + ); 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, - ); - } + // 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, 0, @@ -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 2a1f9ef92def62b85b436f053c37e74c9600c00e..8365525ebd905902dbed3a8eea815ca298566a82 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 8365525ebd905902dbed3a8eea815ca298566a82..20e749a2f607fa96ec6fbdfc76574307648a621d 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 72bb6a4e6e81ddd6dad6bcd78a8e4125130fa37e..6d57a42ff7e689cb51140f89d0ef7f8863e394d2 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 23a6ea4a1cd44eba03db92f40dca867eafb7a9f3..e17a3667bae639186063685923a53a71867ffa27 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 a170f956978f1a8a999f3c5460db4d103f18cb3e..f8ee12ef814d3ebb98e69bad087252fda7a621d9 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 88fe540c397b65c8ddc3ad0230c47210b8bc0e7e..b8ceefcd765f4e1797bcf1584ac93594a1fffdaa 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 627a2ac339d631c666926d4fc8e1354396cb36f7..0c1b0b74bb33fd6d06068463dee0c80b87573e98 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 f8ee12ef814d3ebb98e69bad087252fda7a621d9..ecd7d1a739e957bfa7c7bf7b19de774e97675e64 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 | 35 ++++++++----------- 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, 15 insertions(+), 110 deletions(-) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index c8230620b4c7756dbfee2b26011c32634f3b005a..779fd121f8afbfa59eac556c17e7abba605e8eee 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 66d30b049cb396651368d77c345c7b50e5c6554d..0bfd6afa3b265dfb3845e944b6d7a916ca066261 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 file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option> { - // self.buffer.read(cx).read(cx).file_at(point).cloned() - // } + 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 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 bc764e564c3340957f947ef669243be0a7d27e4d..23fcc25f6aeed436309a3670393d4cbca10536e6 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 0ebd394217ae06c6a2256281f389ab506bfca934..cf8cb9ec327d66176ced0d6aaa51bb71a91c20b8 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 4472da02e71fda1bb17d4353056b67ad58639813..247a5649967bc8cc1ca0c0a7ff369e78912bdd03 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 c18e4f4b89a68859b1c413357649cf6ad025e8d5..2772ec963485852e570ee27a8e7e3381dcd465d2 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 ad7678b58fe696f61c14776c316bb9d159044b2f..99418206462a0dc7bc3babd2f9bda534a69a0f39 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 | 104 +++++++++--------- 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, 67 insertions(+), 138 deletions(-) diff --git a/crates/collab/src/tests/channel_tests.rs b/crates/collab/src/tests/channel_tests.rs index 2a88bc4c579db9855184e278d1fef37200d1f470..e80fe0fdca312bed54d98fce0a1ea69a8a4a6e86 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 5ad3d6cfa3213119551ed341be33816336f8ca5c..13b378a341b419ce66a7685e11490e46f850f6b1 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 a21957611d09feb25f59d4a842ab9b998e83b4d4..32b749c257b0def7913c835141ce25801dcf4afd 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) - // } - // } - - // /// 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 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) - // } + 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(); + + 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, + }; + + 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 509a6d8466609b5041f4f958ca1676107b639a14..470f076d78c4a06a2d3b0856974a8ce0bf8a7612 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 06b6da75b3ed382d03becbb5a418ddf28cbc05c0..5f37bbfce6483e359866a0dadb1d63b2e32b4651 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 251e26ebfba004b81a49c1ce28956e01f42bbce5..ef48cd683207db2a8e51790dc5026133c68cb2df 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 b4a87b1e5de3ed3c71af8c1dcaf9a3ab7a2e4e96..83dd007308721f38cf9305f0b9739f0901fc2942 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 66b289f1db83ab47d9ffaeaff8ec172838b4921f..25dff9b007c148c25aab0f4bd87e07bcb543d08a 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 f7e36fe696258fa1a361bc6bd212f1d888efc2f8..9cbe49d99ea65414a89649be17fb3c5dc196cd83 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 ced08f4cbc30a991bfad0577af24f96c8ff81d8b..e340b44a58377b8a9bda52786dea660637ce54c1 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 13b378a341b419ce66a7685e11490e46f850f6b1..ca54aa49c80f134da3f17c51ba124324f8845c69 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 8d60e29a136013a8e38e33f8ebb5ce8044d4b2d6..ceab82e12b02d0080c2374517317bb2401e1556b 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 6a67183e97c73b3795fc14a71c11a16b6012f549..df9f37b164782f35c9a2ca1cfba6aa96d8783d60 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 c629edc696b87e0552ca05956e2a1c5cf3b5e6b0..fb4ed05f6c006d8118304418a76dd6dcffc67576 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 aec33c2dd32ee9bda77e7fe7927e1346a86178df..1b95671398a613a01f41590bdce20e0a846592d0 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 d03c7b3d0f73c21bde176d416060ccc200aaa62e..56aa6e4322bce652aacda0ddb1f0c77cef61b7ee 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 ca463e76e058c645839f853eadd8e0877ecca6da..efd2c52989edb51cff2559382f0ec62a2ce2702e 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 d28cd9f6e410cec04b3a3081e65166fea80ec159..8a30121d49c2ba350a42e5352065e1b7f886f0c7 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 c2725eef64029a11cbf449769ee5f025ae7b0535..d7686c425ad6a40663aeb6552e790d00aab50f77 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 83dd007308721f38cf9305f0b9739f0901fc2942..771f5602369093454b8252bd76dacf5e5002a5f8 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 ced122402f138e5f5b964792d7a1561260b063b6..98a04eb5f5598edab5010125da60d6a171994422 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 aa0c7c4af58be6c181a04e2b73cff55230096bf9..ee001614400def4fe40f1d5328027704e76b0141 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 ee001614400def4fe40f1d5328027704e76b0141..ca717c9d6a6463b0351c0aa312f8aeeefab8c8ac 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 ecd7d1a739e957bfa7c7bf7b19de774e97675e64..20c5857ad2e07d84c03f54793571851e5783bac5 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 d2250972f3095893458a873980d26ceb13240cf3..e9353a14419adf069a6319ed76997754008caa18 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 20c5857ad2e07d84c03f54793571851e5783bac5..dd3d7415225b4aae56bd8927c6884981a6681c74 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 2749c31a788f8d1fd83fe1353aaae15179b859cb..0eba1771f52d47bde32f465a887e52547f3a89b2 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 9e64e1223c346f4d153fb7d2955b606ff53736ae..a97adb73b7d88ae0dfb1c60c25eff3942c5ad52d 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 47bb27df39060a7fff27bd50218e9b3626d13dd6..96942c052df75c9406272da3a563533342f64406 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 b4a87b1e5de3ed3c71af8c1dcaf9a3ab7a2e4e96..ac3414555aeff0bec698e788da485517259c8ad1 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 dd3d7415225b4aae56bd8927c6884981a6681c74..ee0241eb1209dc6a36150c7d68b68250476c59e5 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 2a47a16741cf67c0cefb8a094d2f9e506cacbdf4..50e7af5138480562212c8d182352bfebdc88db36 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 ee0241eb1209dc6a36150c7d68b68250476c59e5..13b217eec48a9f6380facc5539b1d58831ebd84a 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 bd157c3e6137ccf5e990b94a3085896563931e60..87cf0517a2b6f1a32ca8b0d33dadda2d3418f3db 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 d80c9163a996be96580f459c13e0e8eba8e71d10..6c84a7716f48e62fbd64dc8872dc68a7c6a7dcb2 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 d4743afb714ab47be3e38b196a45174fb33c2aa5..9519cfacdb1715afd9cdd618d723547d40c231a5 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 13b217eec48a9f6380facc5539b1d58831ebd84a..e5c3a13442b8e27c60e6352130d46724fa57a069 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 5ad3d6cfa3213119551ed341be33816336f8ca5c..bbd24136ad3ba34f9a994f2c05e455a681931588 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 251e26ebfba004b81a49c1ce28956e01f42bbce5..5fa8fb102d2370d0d0e056008173b287103208d3 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 d0b52f5eb217ed60cc9b62e20657e5033506f133..2156aad18af283c0c9176856db38cfbf9a7f7adc 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 0c752597262ca1f64a996d09795db289941a30b2..742ff3b6f859988a74d34c9f1625167a78d76927 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 9519cfacdb1715afd9cdd618d723547d40c231a5..2b0a0941c0f014e306d522100477b1e9a9477399 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 e5c3a13442b8e27c60e6352130d46724fa57a069..c919ceac9fd679f734e3a72b2596af72d0191b56 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 bbd24136ad3ba34f9a994f2c05e455a681931588..38569adb20586308c5236cd67216e13cbc466e3c 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 5fa8fb102d2370d0d0e056008173b287103208d3..113900dcd20360ef3f418adedf624a6e951eafcd 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 2156aad18af283c0c9176856db38cfbf9a7f7adc..dee18ea73b55f7d17c9cc742de179ed580f3d596 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 742ff3b6f859988a74d34c9f1625167a78d76927..52f768e03f9c53460b539d53be1729a7d68c81ae 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 {