Skip to main content

twrite_gpui/editor/
render.rs

1use gpui::prelude::*;
2use gpui::{Context, MouseButton, Render, div};
3
4use crate::canvas::EditorCanvas;
5use crate::prompt_bar::PromptBar;
6
7use super::{Editor, SelectionGranularity};
8
9impl Render for Editor {
10    fn render(
11        &mut self,
12        _window: &mut gpui::Window,
13        cx: &mut Context<Self>,
14    ) -> impl gpui::prelude::IntoElement {
15        let cursor_style = if self.is_hovering_task || self.hovered_link.is_some() {
16            gpui::CursorStyle::PointingHand
17        } else {
18            gpui::CursorStyle::IBeam
19        };
20
21        let root = div()
22            .track_focus(&self.focus_handle)
23            .key_context("Editor")
24            .size_full()
25            .flex()
26            .flex_col()
27            .overflow_hidden()
28            .cursor(cursor_style)
29            .bg(self.theme.background);
30        let root = if let Some(family) = self
31            .config
32            .font_family
33            .clone()
34            .or_else(|| self.selected_font_family.clone())
35        {
36            root.font_family(family)
37        } else {
38            root
39        };
40
41        let root = root
42            .on_key_down(cx.listener(Self::handle_key_down))
43            .on_mouse_down(MouseButton::Left, cx.listener(Self::handle_mouse_down))
44            .on_mouse_down(MouseButton::Right, cx.listener(Self::handle_right_click))
45            .on_mouse_up(MouseButton::Left, cx.listener(Self::handle_mouse_up))
46            .on_mouse_up_out(
47                MouseButton::Left,
48                cx.listener(|this, _, _, cx| {
49                    this.is_selecting = false;
50                    this.drag_initial_range = None;
51                    this.selection_granularity = SelectionGranularity::Character;
52                    if let Some(sel) = this.selection
53                        && sel.is_empty()
54                    {
55                        this.selection = None;
56                    }
57                    for hook in &mut this.hooks {
58                        hook.on_selection_change(&this.buffer, this.selection.as_ref());
59                    }
60                    let changed = this.is_hovering_task || this.hovered_link.is_some();
61                    this.is_hovering_task = false;
62                    this.hovered_link = None;
63                    if changed {
64                        cx.notify();
65                    }
66                }),
67            )
68            .on_mouse_move(cx.listener(Self::handle_mouse_move))
69            .on_scroll_wheel(cx.listener(Self::handle_scroll_wheel))
70            .child(
71                div()
72                    .flex_1()
73                    .overflow_hidden()
74                    .child(EditorCanvas::new(cx.entity().clone())),
75            );
76
77        let root = root.child(self.render_context_menu(cx));
78        if !self.prompt.is_open() {
79            return root;
80        }
81        let snapshot = self.search_snapshot();
82        let placement = self
83            .prompt
84            .spec()
85            .map(|s| s.placement)
86            .unwrap_or(twrite_core::PromptPlacement::BottomBar);
87        match placement {
88            twrite_core::PromptPlacement::TopPalette => {
89                root.child(PromptBar::palette(&self.prompt, snapshot, cx))
90            }
91            twrite_core::PromptPlacement::BottomBar => {
92                root.child(PromptBar::bottom_bar(&self.prompt, snapshot, cx))
93            }
94        }
95    }
96}