ui/components/
code_editor.rs1use gpui::{AnyElement, Context, Entity, Render, rgb};
2
3use crate::prelude::*;
4use crate::TextInput;
5
6const GUTTER_WIDTH: Pixels = px(44.);
8const CODE_FONT_FAMILY: &str = "IBM Plex Mono";
10const CODE_FONT_SIZE: Pixels = px(12.5);
12const CODE_LINE_HEIGHT: f32 = 1.7;
14
15pub struct CodeEditor {
23 input: Entity<TextInput>,
24}
25
26impl CodeEditor {
27 pub fn new(cx: &mut Context<Self>) -> Self {
28 let input = cx.new(|cx| TextInput::new(cx).multiline(true));
29 cx.observe(&input, |_, _, cx| cx.notify()).detach();
30 Self { input }
31 }
32
33 pub fn read_only(mut self, cx: &mut Context<Self>, read_only: bool) -> Self {
39 self.set_read_only(read_only, cx);
40 self
41 }
42
43 pub fn set_read_only(&mut self, read_only: bool, cx: &mut Context<Self>) {
45 self.input.update(cx, |input, cx| input.set_read_only(read_only, cx));
46 cx.notify();
47 }
48
49 pub fn text(&self, cx: &App) -> String {
51 self.input.read(cx).text().to_string()
52 }
53
54 pub fn set_text(&mut self, text: impl Into<String>, cx: &mut Context<Self>) {
57 self.input.update(cx, |input, cx| input.set_text(text, cx));
58 cx.notify();
59 }
60}
61
62impl Render for CodeEditor {
63 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
64 let line_count = self.input.read(cx).text().matches('\n').count() + 1;
65
66 let gutter = v_flex()
67 .flex_none()
68 .w(GUTTER_WIDTH)
69 .pr(px(16.))
70 .text_right()
71 .text_color(rgb(0x3A424E))
73 .font_family(CODE_FONT_FAMILY)
74 .text_size(CODE_FONT_SIZE)
75 .line_height(relative(CODE_LINE_HEIGHT))
76 .children((1..=line_count).map(|line| div().child(line.to_string())));
77
78 h_flex()
79 .id(("code-editor", cx.entity_id()))
80 .w_full()
81 .items_start()
82 .overflow_y_scroll()
83 .child(gutter)
84 .child(
85 div()
86 .flex_1()
87 .min_w_0()
88 .text_color(rgb(0xB7BEC7))
90 .font_family(CODE_FONT_FAMILY)
91 .text_size(CODE_FONT_SIZE)
92 .line_height(relative(CODE_LINE_HEIGHT))
93 .child(self.input.clone()),
94 )
95 }
96}
97
98pub fn code_editor_preview(_window: &mut Window, cx: &mut App) -> AnyElement {
102 v_flex()
103 .gap_4()
104 .child(cx.new(|cx| CodeEditor::new(cx)))
105 .into_any_element()
106}