Skip to content

Commit

Permalink
Updates to chat after Hack#2 (zed-industries#4175)
Browse files Browse the repository at this point in the history
Release Notes:

- Channels: Improved font sizes in chat
- Channels: Added a link preview when hovering over links in chat
- Channels: Fixed rendering of newlines in chat messages
- Added a new setting "use_autoclose" (defaulting to true) that lets you
disable autoclose per language.
([zed-industries#1420](https://github.com/zed-industries/community/issues/1420))
([zed-industries#1903](https://github.com/zed-industries/community/issues/1903))
  • Loading branch information
ConradIrwin authored Jan 21, 2024
2 parents 76d3852 + 29ac1fd commit 3b84291
Show file tree
Hide file tree
Showing 11 changed files with 242 additions and 43 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions assets/settings/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
// Whether to use additional LSP queries to format (and amend) the code after
// every "trigger" symbol input, defined by LSP server capabilities.
"use_on_type_format": true,
// Whether to automatically type closing characters for you. For example,
// when you type (, Zed will automatically add a closing ) at the correct position.
"use_autoclose": true,
// Controls whether copilot provides suggestion immediately
// or waits for a `copilot::Toggle`
"show_copilot_suggestions": true,
Expand Down
14 changes: 6 additions & 8 deletions crates/collab_ui/src/chat_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,13 @@ impl ChatPanel {
.when(!is_continuation_from_previous, |this| {
this.pt_3().child(
h_flex()
.child(
div().absolute().child(
Avatar::new(message.sender.avatar_uri.clone())
.size(cx.rem_size() * 1.5),
),
)
.text_ui_sm()
.child(div().absolute().child(
Avatar::new(message.sender.avatar_uri.clone()).size(cx.rem_size()),
))
.child(
div()
.pl(cx.rem_size() * 1.5 + px(6.0))
.pl(cx.rem_size() + px(6.0))
.pr(px(8.0))
.font_weight(FontWeight::BOLD)
.child(Label::new(message.sender.github_login.clone())),
Expand Down Expand Up @@ -597,7 +595,7 @@ impl Render for ChatPanel {
el.child(
div()
.rounded_md()
.h_7()
.h_6()
.w_full()
.bg(cx.theme().colors().editor_background),
)
Expand Down
5 changes: 3 additions & 2 deletions crates/collab_ui/src/chat_panel/message_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use project::search::SearchQuery;
use settings::Settings;
use std::{sync::Arc, time::Duration};
use theme::ThemeSettings;
use ui::prelude::*;
use ui::{prelude::*, UiTextSize};

const MENTIONS_DEBOUNCE_INTERVAL: Duration = Duration::from_millis(50);

Expand Down Expand Up @@ -83,6 +83,7 @@ impl MessageEditor {
let this = cx.view().downgrade();
editor.update(cx, |editor, cx| {
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
editor.set_use_autoclose(false);
editor.set_completion_provider(Box::new(MessageEditorCompletionProvider(this)));
});

Expand Down Expand Up @@ -325,7 +326,7 @@ impl Render for MessageEditor {
},
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features,
font_size: rems(0.875).into(),
font_size: UiTextSize::Small.rems().into(),
font_weight: FontWeight::NORMAL,
font_style: FontStyle::Normal,
line_height: relative(1.3).into(),
Expand Down
13 changes: 12 additions & 1 deletion crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ pub struct Editor {
style: Option<EditorStyle>,
editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
show_copilot_suggestions: bool,
use_autoclose: bool,
}

pub struct EditorSnapshot {
Expand Down Expand Up @@ -1411,6 +1412,7 @@ impl Editor {
keymap_context_layers: Default::default(),
input_enabled: true,
read_only: false,
use_autoclose: true,
leader_peer_id: None,
remote_id: None,
hover_state: Default::default(),
Expand Down Expand Up @@ -1692,6 +1694,10 @@ impl Editor {
self.read_only = read_only;
}

pub fn set_use_autoclose(&mut self, autoclose: bool) {
self.use_autoclose = autoclose;
}

pub fn set_show_copilot_suggestions(&mut self, show_copilot_suggestions: bool) {
self.show_copilot_suggestions = show_copilot_suggestions;
}
Expand Down Expand Up @@ -2290,7 +2296,12 @@ impl Editor {
),
&bracket_pair.start[..prefix_len],
));
if following_text_allows_autoclose && preceding_text_matches_prefix {
let autoclose = self.use_autoclose
&& snapshot.settings_at(selection.start, cx).use_autoclose;
if autoclose
&& following_text_allows_autoclose
&& preceding_text_matches_prefix
{
let anchor = snapshot.anchor_before(selection.end);
new_selections.push((selection.map(|_| anchor), text.len()));
new_autoclose_regions.push((
Expand Down
6 changes: 3 additions & 3 deletions crates/gpui/src/elements/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use taffy::style::Overflow;
use util::ResultExt;

const DRAG_THRESHOLD: f64 = 2.;
const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
pub(crate) const TOOLTIP_DELAY: Duration = Duration::from_millis(500);

pub struct GroupStyle {
pub group: SharedString,
Expand Down Expand Up @@ -1718,8 +1718,8 @@ pub struct InteractiveElementState {
}

pub struct ActiveTooltip {
tooltip: Option<AnyTooltip>,
_task: Option<Task<()>>,
pub(crate) tooltip: Option<AnyTooltip>,
pub(crate) _task: Option<Task<()>>,
}

/// Whether or not the element or a group that contains it is clicked by the mouse.
Expand Down
128 changes: 123 additions & 5 deletions crates/gpui/src/elements/text.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use crate::{
Bounds, DispatchPhase, Element, ElementId, HighlightStyle, IntoElement, LayoutId,
MouseDownEvent, MouseUpEvent, Pixels, Point, SharedString, Size, TextRun, TextStyle,
WhiteSpace, WindowContext, WrappedLine,
ActiveTooltip, AnyTooltip, AnyView, Bounds, DispatchPhase, Element, ElementId, HighlightStyle,
IntoElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
SharedString, Size, TextRun, TextStyle, WhiteSpace, WindowContext, WrappedLine, TOOLTIP_DELAY,
};
use anyhow::anyhow;
use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
use std::{cell::Cell, mem, ops::Range, rc::Rc, sync::Arc};
use std::{
cell::{Cell, RefCell},
mem,
ops::Range,
rc::Rc,
sync::Arc,
};
use util::ResultExt;

impl Element for &'static str {
Expand Down Expand Up @@ -289,6 +295,8 @@ pub struct InteractiveText {
text: StyledText,
click_listener:
Option<Box<dyn Fn(&[Range<usize>], InteractiveTextClickEvent, &mut WindowContext<'_>)>>,
hover_listener: Option<Box<dyn Fn(Option<usize>, MouseMoveEvent, &mut WindowContext<'_>)>>,
tooltip_builder: Option<Rc<dyn Fn(usize, &mut WindowContext<'_>) -> Option<AnyView>>>,
clickable_ranges: Vec<Range<usize>>,
}

Expand All @@ -300,18 +308,25 @@ struct InteractiveTextClickEvent {
pub struct InteractiveTextState {
text_state: TextState,
mouse_down_index: Rc<Cell<Option<usize>>>,
hovered_index: Rc<Cell<Option<usize>>>,
active_tooltip: Rc<RefCell<Option<ActiveTooltip>>>,
}

/// InteractiveTest is a wrapper around StyledText that adds mouse interactions.
impl InteractiveText {
pub fn new(id: impl Into<ElementId>, text: StyledText) -> Self {
Self {
element_id: id.into(),
text,
click_listener: None,
hover_listener: None,
tooltip_builder: None,
clickable_ranges: Vec::new(),
}
}

/// on_click is called when the user clicks on one of the given ranges, passing the index of
/// the clicked range.
pub fn on_click(
mut self,
ranges: Vec<Range<usize>>,
Expand All @@ -328,6 +343,25 @@ impl InteractiveText {
self.clickable_ranges = ranges;
self
}

/// on_hover is called when the mouse moves over a character within the text, passing the
/// index of the hovered character, or None if the mouse leaves the text.
pub fn on_hover(
mut self,
listener: impl Fn(Option<usize>, MouseMoveEvent, &mut WindowContext<'_>) + 'static,
) -> Self {
self.hover_listener = Some(Box::new(listener));
self
}

/// tooltip lets you specify a tooltip for a given character index in the string.
pub fn tooltip(
mut self,
builder: impl Fn(usize, &mut WindowContext<'_>) -> Option<AnyView> + 'static,
) -> Self {
self.tooltip_builder = Some(Rc::new(builder));
self
}
}

impl Element for InteractiveText {
Expand All @@ -339,20 +373,27 @@ impl Element for InteractiveText {
cx: &mut WindowContext,
) -> (LayoutId, Self::State) {
if let Some(InteractiveTextState {
mouse_down_index, ..
mouse_down_index,
hovered_index,
active_tooltip,
..
}) = state
{
let (layout_id, text_state) = self.text.request_layout(None, cx);
let element_state = InteractiveTextState {
text_state,
mouse_down_index,
hovered_index,
active_tooltip,
};
(layout_id, element_state)
} else {
let (layout_id, text_state) = self.text.request_layout(None, cx);
let element_state = InteractiveTextState {
text_state,
mouse_down_index: Rc::default(),
hovered_index: Rc::default(),
active_tooltip: Rc::default(),
};
(layout_id, element_state)
}
Expand Down Expand Up @@ -408,6 +449,83 @@ impl Element for InteractiveText {
});
}
}
if let Some(hover_listener) = self.hover_listener.take() {
let text_state = state.text_state.clone();
let hovered_index = state.hovered_index.clone();
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Bubble {
let current = hovered_index.get();
let updated = text_state.index_for_position(bounds, event.position);
if current != updated {
hovered_index.set(updated);
hover_listener(updated, event.clone(), cx);
cx.refresh();
}
}
});
}
if let Some(tooltip_builder) = self.tooltip_builder.clone() {
let active_tooltip = state.active_tooltip.clone();
let pending_mouse_down = state.mouse_down_index.clone();
let text_state = state.text_state.clone();

cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
let position = text_state.index_for_position(bounds, event.position);
let is_hovered = position.is_some() && pending_mouse_down.get().is_none();
if !is_hovered {
active_tooltip.take();
return;
}
let position = position.unwrap();

if phase != DispatchPhase::Bubble {
return;
}

if active_tooltip.borrow().is_none() {
let task = cx.spawn({
let active_tooltip = active_tooltip.clone();
let tooltip_builder = tooltip_builder.clone();

move |mut cx| async move {
cx.background_executor().timer(TOOLTIP_DELAY).await;
cx.update(|_, cx| {
let new_tooltip =
tooltip_builder(position, cx).map(|tooltip| ActiveTooltip {
tooltip: Some(AnyTooltip {
view: tooltip,
cursor_offset: cx.mouse_position(),
}),
_task: None,
});
*active_tooltip.borrow_mut() = new_tooltip;
cx.refresh();
})
.ok();
}
});
*active_tooltip.borrow_mut() = Some(ActiveTooltip {
tooltip: None,
_task: Some(task),
});
}
});

let active_tooltip = state.active_tooltip.clone();
cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
active_tooltip.take();
});

if let Some(tooltip) = state
.active_tooltip
.clone()
.borrow()
.as_ref()
.and_then(|at| at.tooltip.clone())
{
cx.set_tooltip(tooltip);
}
}

self.text.paint(bounds, &mut state.text_state, cx)
}
Expand Down
8 changes: 8 additions & 0 deletions crates/language/src/language_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ pub struct LanguageSettings {
pub extend_comment_on_newline: bool,
/// Inlay hint related settings.
pub inlay_hints: InlayHintSettings,
/// Whether to automatically close brackets.
pub use_autoclose: bool,
}

/// The settings for [GitHub Copilot](https://github.com/features/copilot).
Expand Down Expand Up @@ -208,6 +210,11 @@ pub struct LanguageSettingsContent {
/// Inlay hint related settings.
#[serde(default)]
pub inlay_hints: Option<InlayHintSettings>,
/// Whether to automatically type closing characters for you. For example,
/// when you type (, Zed will automatically add a closing ) at the correct position.
///
/// Default: true
pub use_autoclose: Option<bool>,
}

/// The contents of the GitHub Copilot settings.
Expand Down Expand Up @@ -540,6 +547,7 @@ fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent
merge(&mut settings.tab_size, src.tab_size);
merge(&mut settings.hard_tabs, src.hard_tabs);
merge(&mut settings.soft_wrap, src.soft_wrap);
merge(&mut settings.use_autoclose, src.use_autoclose);
merge(&mut settings.show_wrap_guides, src.show_wrap_guides);
merge(&mut settings.wrap_guides, src.wrap_guides.clone());

Expand Down
1 change: 1 addition & 0 deletions crates/rich_text/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sum_tree = { path = "../sum_tree" }
theme = { path = "../theme" }
language = { path = "../language" }
util = { path = "../util" }
ui = { path = "../ui" }
anyhow.workspace = true
futures.workspace = true
lazy_static.workspace = true
Expand Down
Loading

0 comments on commit 3b84291

Please sign in to comment.