Detailed changes
@@ -366,13 +366,26 @@ impl ChatPanel {
};
let is_pending = message.is_pending();
- let text = self
- .markdown_data
- .entry(message.id)
- .or_insert_with(|| rich_text::render_markdown(message.body, &self.languages, None));
+ let theme = theme::current(cx);
+ let text = self.markdown_data.entry(message.id).or_insert_with(|| {
+ let mut markdown =
+ rich_text::render_markdown(message.body.clone(), &self.languages, None);
+ let self_client_id = self.client.id();
+ for (mention_range, user_id) in message.mentions {
+ let is_current_user = self_client_id == user_id;
+ markdown
+ .add_mention(
+ mention_range,
+ is_current_user,
+ theme.chat_panel.mention_highlight.clone(),
+ )
+ .log_err();
+ }
+ markdown
+ });
let now = OffsetDateTime::now_utc();
- let theme = theme::current(cx);
+
let style = if is_pending {
&theme.chat_panel.pending_message
} else if is_continuation {
@@ -400,6 +413,7 @@ impl ChatPanel {
theme.editor.syntax.clone(),
style.body.clone(),
theme.editor.document_highlight_read_background,
+ theme.chat_panel.self_mention_background,
cx,
)
.flex(1., true),
@@ -456,6 +470,7 @@ impl ChatPanel {
theme.editor.syntax.clone(),
style.body.clone(),
theme.editor.document_highlight_read_background,
+ theme.chat_panel.self_mention_background,
cx,
)
.flex(1., true),
@@ -1,5 +1,6 @@
use std::{ops::Range, sync::Arc};
+use anyhow::bail;
use futures::FutureExt;
use gpui::{
color::Color,
@@ -25,9 +26,15 @@ pub struct RichText {
pub regions: Vec<RenderedRegion>,
}
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum BackgroundKind {
+ Code,
+ Mention,
+}
+
#[derive(Debug, Clone)]
pub struct RenderedRegion {
- code: bool,
+ background_kind: Option<BackgroundKind>,
link_url: Option<String>,
}
@@ -37,6 +44,7 @@ impl RichText {
syntax: Arc<SyntaxTheme>,
style: TextStyle,
code_span_background_color: Color,
+ self_mention_span_background_color: Color,
cx: &mut ViewContext<V>,
) -> AnyElement<V> {
let mut region_id = 0;
@@ -73,18 +81,49 @@ impl RichText {
}),
);
}
- if region.code {
+ if region.background_kind == Some(BackgroundKind::Code) {
cx.scene().push_quad(gpui::Quad {
bounds,
background: Some(code_span_background_color),
border: Default::default(),
corner_radii: (2.0).into(),
});
+ } else if region.background_kind == Some(BackgroundKind::Mention) {
+ cx.scene().push_quad(gpui::Quad {
+ bounds,
+ background: Some(self_mention_span_background_color),
+ border: Default::default(),
+ corner_radii: (2.0).into(),
+ });
}
})
.with_soft_wrap(true)
.into_any()
}
+ pub fn add_mention(
+ &mut self,
+ range: Range<usize>,
+ 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(
@@ -101,7 +140,11 @@ pub fn render_markdown_mut(
let mut current_language = None;
let mut list_stack = Vec::new();
- for event in Parser::new_ext(&block, Options::all()) {
+ // Smart Punctuation is disabled as that messes with offsets within the message.
+ let mut options = Options::all();
+ options.remove(Options::ENABLE_SMART_PUNCTUATION);
+
+ for event in Parser::new_ext(&block, options) {
let prev_len = data.text.len();
match event {
Event::Text(t) => {
@@ -121,7 +164,7 @@ pub fn render_markdown_mut(
data.region_ranges.push(prev_len..data.text.len());
data.regions.push(RenderedRegion {
link_url: Some(link_url),
- code: false,
+ background_kind: None,
});
style.underline = Some(Underline {
thickness: 1.0.into(),
@@ -162,7 +205,7 @@ pub fn render_markdown_mut(
));
}
data.regions.push(RenderedRegion {
- code: true,
+ background_kind: Some(BackgroundKind::Code),
link_url: link_url.clone(),
});
}
@@ -641,6 +641,7 @@ pub struct ChatPanel {
pub avatar_container: ContainerStyle,
pub message: ChatMessage,
pub mention_highlight: HighlightStyle,
+ pub self_mention_background: Color,
pub continuation_message: ChatMessage,
pub last_message_bottom_spacing: f32,
pub pending_message: ChatMessage,
@@ -1,11 +1,8 @@
-import {
- background,
- border,
- text,
-} from "./components"
+import { background, border, text } from "./components"
import { icon_button } from "../component/icon_button"
import { useTheme } from "../theme"
import { interactive } from "../element"
+import { Color } from "ayu/dist/color"
export default function chat_panel(): any {
const theme = useTheme()
@@ -41,15 +38,13 @@ export default function chat_panel(): any {
left: 2,
top: 2,
bottom: 2,
- }
- },
- list: {
-
+ },
},
+ list: {},
channel_select: {
header: {
...channel_name,
- border: border(layer, { bottom: true })
+ border: border(layer, { bottom: true }),
},
item: channel_name,
active_item: {
@@ -62,8 +57,8 @@ export default function chat_panel(): any {
},
menu: {
background: background(layer, "on"),
- border: border(layer, { bottom: true })
- }
+ border: border(layer, { bottom: true }),
+ },
},
icon_button: icon_button({
variant: "ghost",
@@ -91,7 +86,8 @@ export default function chat_panel(): any {
top: 4,
},
},
- mention_highlight: { weight: 'bold' },
+ mention_highlight: { weight: "bold" },
+ self_mention_background: background(layer, "active"),
message: {
...interactive({
base: {
@@ -101,7 +97,7 @@ export default function chat_panel(): any {
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
- }
+ },
},
state: {
hovered: {
@@ -135,7 +131,7 @@ export default function chat_panel(): any {
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
- }
+ },
},
state: {
hovered: {
@@ -160,7 +156,7 @@ export default function chat_panel(): any {
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
- }
+ },
},
state: {
hovered: {
@@ -171,6 +167,6 @@ export default function chat_panel(): any {
},
sign_in_prompt: {
default: text(layer, "sans", "base"),
- }
+ },
}
}