1use editor::Editor;
2use gpui::div;
3use ui::{
4 ActiveTheme as _, App, FluentBuilder as _, InteractiveElement as _, IntoElement,
5 ParentElement as _, RenderOnce, Styled as _, Window,
6};
7
8#[derive(IntoElement)]
9pub struct SettingsEditor {
10 initial_text: Option<String>,
11 placeholder: Option<&'static str>,
12 confirm: Option<Box<dyn Fn(Option<String>, &mut App)>>,
13}
14
15impl SettingsEditor {
16 pub fn new() -> Self {
17 Self {
18 initial_text: None,
19 placeholder: None,
20 confirm: None,
21 }
22 }
23
24 pub fn with_initial_text(mut self, initial_text: String) -> Self {
25 self.initial_text = Some(initial_text);
26 self
27 }
28
29 pub fn with_placeholder(mut self, placeholder: &'static str) -> Self {
30 self.placeholder = Some(placeholder);
31 self
32 }
33
34 pub fn on_confirm(mut self, confirm: impl Fn(Option<String>, &mut App) + 'static) -> Self {
35 self.confirm = Some(Box::new(confirm));
36 self
37 }
38}
39
40impl RenderOnce for SettingsEditor {
41 fn render(self, window: &mut Window, cx: &mut App) -> impl ui::IntoElement {
42 let editor = window.use_state(cx, {
43 move |window, cx| {
44 let mut editor = Editor::single_line(window, cx);
45 if let Some(text) = self.initial_text {
46 editor.set_text(text, window, cx);
47 }
48
49 if let Some(placeholder) = self.placeholder {
50 editor.set_placeholder_text(placeholder, window, cx);
51 }
52 // todo(settings_ui): We should have an observe global use for settings store
53 // so whenever a settings file is updated, the settings ui updates too
54 editor
55 }
56 });
57
58 let weak_editor = editor.downgrade();
59 let theme_colors = cx.theme().colors();
60
61 div()
62 .py_1()
63 .px_2()
64 .min_w_64()
65 .rounded_md()
66 .border_1()
67 .border_color(theme_colors.border)
68 .bg(theme_colors.editor_background)
69 .child(editor)
70 .when_some(self.confirm, |this, confirm| {
71 this.on_action::<menu::Confirm>({
72 move |_, _, cx| {
73 let Some(editor) = weak_editor.upgrade() else {
74 return;
75 };
76 let new_value = editor.read_with(cx, |editor, cx| editor.text(cx));
77 let new_value = (!new_value.is_empty()).then_some(new_value);
78 confirm(new_value, cx);
79 }
80 })
81 })
82 }
83}