Highlight mentions in the Saved chat messages

This commit is contained in:
Piotr Osiewicz 2023-10-20 15:15:39 +02:00
parent 44cb55fbe9
commit 6844bb6510
4 changed files with 82 additions and 27 deletions

View file

@ -366,13 +366,26 @@ impl ChatPanel {
}; };
let is_pending = message.is_pending(); let is_pending = message.is_pending();
let text = self let theme = theme::current(cx);
.markdown_data let text = self.markdown_data.entry(message.id).or_insert_with(|| {
.entry(message.id) let mut markdown =
.or_insert_with(|| rich_text::render_markdown(message.body, &self.languages, None)); 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 now = OffsetDateTime::now_utc();
let theme = theme::current(cx);
let style = if is_pending { let style = if is_pending {
&theme.chat_panel.pending_message &theme.chat_panel.pending_message
} else if is_continuation { } else if is_continuation {
@ -400,6 +413,7 @@ impl ChatPanel {
theme.editor.syntax.clone(), theme.editor.syntax.clone(),
style.body.clone(), style.body.clone(),
theme.editor.document_highlight_read_background, theme.editor.document_highlight_read_background,
theme.chat_panel.self_mention_background,
cx, cx,
) )
.flex(1., true), .flex(1., true),
@ -456,6 +470,7 @@ impl ChatPanel {
theme.editor.syntax.clone(), theme.editor.syntax.clone(),
style.body.clone(), style.body.clone(),
theme.editor.document_highlight_read_background, theme.editor.document_highlight_read_background,
theme.chat_panel.self_mention_background,
cx, cx,
) )
.flex(1., true), .flex(1., true),

View file

@ -1,5 +1,6 @@
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
use anyhow::bail;
use futures::FutureExt; use futures::FutureExt;
use gpui::{ use gpui::{
color::Color, color::Color,
@ -25,9 +26,15 @@ pub struct RichText {
pub regions: Vec<RenderedRegion>, pub regions: Vec<RenderedRegion>,
} }
#[derive(Clone, Copy, Debug, PartialEq)]
enum BackgroundKind {
Code,
Mention,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RenderedRegion { pub struct RenderedRegion {
code: bool, background_kind: Option<BackgroundKind>,
link_url: Option<String>, link_url: Option<String>,
} }
@ -37,6 +44,7 @@ impl RichText {
syntax: Arc<SyntaxTheme>, syntax: Arc<SyntaxTheme>,
style: TextStyle, style: TextStyle,
code_span_background_color: Color, code_span_background_color: Color,
self_mention_span_background_color: Color,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> AnyElement<V> { ) -> AnyElement<V> {
let mut region_id = 0; 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 { cx.scene().push_quad(gpui::Quad {
bounds, bounds,
background: Some(code_span_background_color), background: Some(code_span_background_color),
border: Default::default(), border: Default::default(),
corner_radii: (2.0).into(), 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) .with_soft_wrap(true)
.into_any() .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( pub fn render_markdown_mut(
@ -101,7 +140,11 @@ pub fn render_markdown_mut(
let mut current_language = None; let mut current_language = None;
let mut list_stack = Vec::new(); 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(); let prev_len = data.text.len();
match event { match event {
Event::Text(t) => { Event::Text(t) => {
@ -121,7 +164,7 @@ pub fn render_markdown_mut(
data.region_ranges.push(prev_len..data.text.len()); data.region_ranges.push(prev_len..data.text.len());
data.regions.push(RenderedRegion { data.regions.push(RenderedRegion {
link_url: Some(link_url), link_url: Some(link_url),
code: false, background_kind: None,
}); });
style.underline = Some(Underline { style.underline = Some(Underline {
thickness: 1.0.into(), thickness: 1.0.into(),
@ -162,7 +205,7 @@ pub fn render_markdown_mut(
)); ));
} }
data.regions.push(RenderedRegion { data.regions.push(RenderedRegion {
code: true, background_kind: Some(BackgroundKind::Code),
link_url: link_url.clone(), link_url: link_url.clone(),
}); });
} }

View file

@ -641,6 +641,7 @@ pub struct ChatPanel {
pub avatar_container: ContainerStyle, pub avatar_container: ContainerStyle,
pub message: ChatMessage, pub message: ChatMessage,
pub mention_highlight: HighlightStyle, pub mention_highlight: HighlightStyle,
pub self_mention_background: Color,
pub continuation_message: ChatMessage, pub continuation_message: ChatMessage,
pub last_message_bottom_spacing: f32, pub last_message_bottom_spacing: f32,
pub pending_message: ChatMessage, pub pending_message: ChatMessage,

View file

@ -1,11 +1,8 @@
import { import { background, border, text } from "./components"
background,
border,
text,
} from "./components"
import { icon_button } from "../component/icon_button" import { icon_button } from "../component/icon_button"
import { useTheme } from "../theme" import { useTheme } from "../theme"
import { interactive } from "../element" import { interactive } from "../element"
import { Color } from "ayu/dist/color"
export default function chat_panel(): any { export default function chat_panel(): any {
const theme = useTheme() const theme = useTheme()
@ -41,15 +38,13 @@ export default function chat_panel(): any {
left: 2, left: 2,
top: 2, top: 2,
bottom: 2, bottom: 2,
} },
},
list: {
}, },
list: {},
channel_select: { channel_select: {
header: { header: {
...channel_name, ...channel_name,
border: border(layer, { bottom: true }) border: border(layer, { bottom: true }),
}, },
item: channel_name, item: channel_name,
active_item: { active_item: {
@ -62,8 +57,8 @@ export default function chat_panel(): any {
}, },
menu: { menu: {
background: background(layer, "on"), background: background(layer, "on"),
border: border(layer, { bottom: true }) border: border(layer, { bottom: true }),
} },
}, },
icon_button: icon_button({ icon_button: icon_button({
variant: "ghost", variant: "ghost",
@ -91,7 +86,8 @@ export default function chat_panel(): any {
top: 4, top: 4,
}, },
}, },
mention_highlight: { weight: 'bold' }, mention_highlight: { weight: "bold" },
self_mention_background: background(layer, "active"),
message: { message: {
...interactive({ ...interactive({
base: { base: {
@ -101,7 +97,7 @@ export default function chat_panel(): any {
bottom: 4, bottom: 4,
left: SPACING / 2, left: SPACING / 2,
right: SPACING / 3, right: SPACING / 3,
} },
}, },
state: { state: {
hovered: { hovered: {
@ -135,7 +131,7 @@ export default function chat_panel(): any {
bottom: 4, bottom: 4,
left: SPACING / 2, left: SPACING / 2,
right: SPACING / 3, right: SPACING / 3,
} },
}, },
state: { state: {
hovered: { hovered: {
@ -160,7 +156,7 @@ export default function chat_panel(): any {
bottom: 4, bottom: 4,
left: SPACING / 2, left: SPACING / 2,
right: SPACING / 3, right: SPACING / 3,
} },
}, },
state: { state: {
hovered: { hovered: {
@ -171,6 +167,6 @@ export default function chat_panel(): any {
}, },
sign_in_prompt: { sign_in_prompt: {
default: text(layer, "sans", "base"), default: text(layer, "sans", "base"),
} },
} }
} }