Skip to main content

kitchen_ui/widgets/
text_view.rs

1//! The text view: wrapped, selectable text with light markdown, for agent messages and notes.
2
3use gpui_kit::component::text::{TextView as KitTextView, TextViewState};
4use gpui_kit::{AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, Styled as _, Window, div};
5
6/// Wrapped, selectable text with light markdown: headings, emphasis, `code` spans, bullet and
7/// numbered lists, links, and fenced code highlighted with the same grammars and colours as
8/// [`crate::widgets::CodeView`] (` ```rust `, ` ```python `, ` ```json `). As tall as its text.
9///
10/// Text can stream in ([`TextView::push_str`]), as an agent's reply does. Built on gpui-kit's
11/// markdown view; selection and copy (Ctrl/Cmd+C) come with it.
12pub struct TextView {
13    text: String,
14    state: Entity<TextViewState>,
15}
16
17impl TextView {
18    /// A view of `markdown`.
19    pub fn new(markdown: impl Into<String>, cx: &mut Context<Self>) -> Self {
20        let text = markdown.into();
21        let state = cx.new(|cx| TextViewState::markdown(&text, cx).selectable(true));
22        Self { text, state }
23    }
24
25    /// Appends `more` (a streamed chunk).
26    pub fn push_str(&mut self, more: &str, cx: &mut Context<Self>) {
27        self.text.push_str(more);
28        self.state.update(cx, |s, cx| s.push_str(more, cx));
29        cx.notify();
30    }
31
32    /// Replaces the text.
33    pub fn set_text(&mut self, markdown: impl Into<String>, cx: &mut Context<Self>) {
34        self.text = markdown.into();
35        let text = self.text.clone();
36        self.state.update(cx, |s, cx| s.set_text(&text, cx));
37        cx.notify();
38    }
39
40    /// The markdown source.
41    pub fn text(&self) -> &str {
42        &self.text
43    }
44
45    /// The text selected, as shown (no markdown marks).
46    pub fn selected_text(&self, cx: &gpui_kit::App) -> String {
47        self.state.read(cx).selected_text()
48    }
49}
50
51impl Render for TextView {
52    fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
53        div().w_full().min_w_0().text_sm().child(KitTextView::new(&self.state).selectable(true).w_full())
54    }
55}