From 77a15f7376b945acf144428bc12f679b3c1cf420 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 21:48:23 +0800 Subject: [PATCH 1/6] Add auto format & edtor wrap configurations --- src/app_shell.rs | 8 ++ src/models.rs | 10 +++ src/storage/workspace_repo.rs | 60 +++++++++++++ src/ui.rs | 155 +++++++++++++++++++++++++++++++--- 4 files changed, 223 insertions(+), 10 deletions(-) diff --git a/src/app_shell.rs b/src/app_shell.rs index 4f5b3ca..c9a5417 100644 --- a/src/app_shell.rs +++ b/src/app_shell.rs @@ -633,6 +633,8 @@ pub struct LocalEnvironmentSelectionState { pub struct LocalThemeState { pub theme_name: Option, pub font_size: AppFontSize, + pub auto_format_response: bool, + pub wrap_body_editor: bool, } #[derive(Debug, Clone, PartialEq, Eq, Default)] @@ -2283,6 +2285,8 @@ where theme: LocalThemeState { theme_name: app_settings.app_settings.theme_name.clone(), font_size: app_settings.app_settings.font_size, + auto_format_response: app_settings.app_settings.auto_format_response, + wrap_body_editor: app_settings.app_settings.wrap_body_editor, }, workspace: WorkspaceState { workspace_id: workspace_entry.map(|e| e.workspace_id), @@ -4078,6 +4082,8 @@ expanded_item_ids = ["{folder_id}"] app_settings: crate::models::AppSettings { theme_name: Some("One Dark".to_string()), font_size: AppFontSize::Large, + auto_format_response: true, + wrap_body_editor: false, updated_at: Utc::now(), }, }) @@ -4180,6 +4186,8 @@ post_response = "console.log(response.status)" ); assert_eq!(state.theme.theme_name.as_deref(), Some("One Dark")); assert_eq!(state.theme.font_size, AppFontSize::Large); + assert!(state.theme.auto_format_response); + assert!(!state.theme.wrap_body_editor); assert_eq!( state .shared_store diff --git a/src/models.rs b/src/models.rs index 458ff11..cbfdc1e 100644 --- a/src/models.rs +++ b/src/models.rs @@ -338,9 +338,17 @@ pub struct AppSettings { pub theme_name: Option, #[serde(default)] pub font_size: AppFontSize, + #[serde(default = "default_auto_format_response")] + pub auto_format_response: bool, + #[serde(default)] + pub wrap_body_editor: bool, pub updated_at: DateTime, } +const fn default_auto_format_response() -> bool { + true +} + impl WorkspacesRegistryFile { pub fn new_with_default_workspace( workspace_name: impl Into, @@ -385,6 +393,8 @@ impl Default for AppSettingsFile { app_settings: AppSettings { theme_name: None, font_size: AppFontSize::default(), + auto_format_response: default_auto_format_response(), + wrap_body_editor: false, updated_at: Utc::now(), }, } diff --git a/src/storage/workspace_repo.rs b/src/storage/workspace_repo.rs index 342e514..48a8bb9 100644 --- a/src/storage/workspace_repo.rs +++ b/src/storage/workspace_repo.rs @@ -1193,6 +1193,36 @@ impl WorkspaceRepository { self.save_app_settings(&app_settings) } + pub fn persist_auto_format_response_state(&self, auto_format_response: bool) -> Result<()> { + let mut app_settings = match self.load_app_settings() { + Ok(state) => state, + Err(_) => AppSettingsFile::default(), + }; + + if app_settings.app_settings.auto_format_response == auto_format_response { + return Ok(()); + } + + app_settings.app_settings.auto_format_response = auto_format_response; + app_settings.app_settings.updated_at = Utc::now(); + self.save_app_settings(&app_settings) + } + + pub fn persist_wrap_body_editor_state(&self, wrap_body_editor: bool) -> Result<()> { + let mut app_settings = match self.load_app_settings() { + Ok(state) => state, + Err(_) => AppSettingsFile::default(), + }; + + if app_settings.app_settings.wrap_body_editor == wrap_body_editor { + return Ok(()); + } + + app_settings.app_settings.wrap_body_editor = wrap_body_editor; + app_settings.app_settings.updated_at = Utc::now(); + self.save_app_settings(&app_settings) + } + fn seed_app_settings_file(&self) -> Result { let mut app_settings = AppSettingsFile::default(); let local_state_path = &self.backend.paths().local_state_file; @@ -1904,6 +1934,34 @@ mod tests { assert_eq!(loaded.app_settings.font_size, AppFontSize::Large); } + #[test] + fn persist_auto_format_response_state_updates_app_settings() { + let dir = tempdir().expect("tempdir"); + let backend = FileSystemStorage::new(BeamPaths::from_root(dir.path().to_path_buf())); + let storage = WorkspaceRepository::new(backend).expect("load workspace into memory"); + + storage + .persist_auto_format_response_state(false) + .expect("persist auto format response state"); + let loaded = storage.load_app_settings().expect("load app settings"); + + assert!(!loaded.app_settings.auto_format_response); + } + + #[test] + fn persist_wrap_body_editor_state_updates_app_settings() { + let dir = tempdir().expect("tempdir"); + let backend = FileSystemStorage::new(BeamPaths::from_root(dir.path().to_path_buf())); + let storage = WorkspaceRepository::new(backend).expect("load workspace into memory"); + + storage + .persist_wrap_body_editor_state(true) + .expect("persist wrap body editor state"); + let loaded = storage.load_app_settings().expect("load app settings"); + + assert!(loaded.app_settings.wrap_body_editor); + } + #[test] fn load_app_settings_seeds_from_existing_local_state_fields() { let dir = tempdir().expect("tempdir"); @@ -1927,6 +1985,8 @@ updated_at = "2026-05-01T03:42:36.157016+00:00" assert_eq!(loaded.app_settings.theme_name.as_deref(), Some("One Dark")); assert_eq!(loaded.app_settings.font_size, AppFontSize::Large); + assert!(loaded.app_settings.auto_format_response); + assert!(!loaded.app_settings.wrap_body_editor); assert!(backend.paths.app_settings_file.exists()); } diff --git a/src/ui.rs b/src/ui.rs index 09797f4..a28e3f9 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -844,6 +844,13 @@ impl Render for SettingsDialogView { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let active_theme_name = cx.theme().theme_name().clone(); let active_font_size = AppFontSize::from_pixels_value(cx.theme().font_size.as_f32()); + let (auto_format_response, wrap_body_editor) = { + let beam_view = self.beam_view.read(cx); + ( + beam_view.shell.theme.auto_format_response, + beam_view.shell.theme.wrap_body_editor, + ) + }; let theme_options: Vec = ThemeRegistry::global(cx) .sorted_themes() .into_iter() @@ -856,6 +863,8 @@ impl Render for SettingsDialogView { SettingsSection::Theme => { let beam_view = self.beam_view.clone(); let font_size_beam_view = beam_view.clone(); + let auto_format_beam_view = beam_view.clone(); + let wrap_body_editor_beam_view = beam_view.clone(); let active_theme_name_for_menu = active_theme_name.clone(); let theme_options_for_menu = theme_options.clone(); let font_size_options_for_menu = font_size_options; @@ -952,6 +961,77 @@ impl Render for SettingsDialogView { }, ) }), + ) + .child(div().mt_4().text_sm().font_semibold().child("Response")) + .child( + h_flex() + .items_start() + .gap_3() + .rounded(px(8.0)) + .border_1() + .border_color(cx.theme().border) + .p_3() + .child( + gpui_component::checkbox::Checkbox::new( + "settings-auto-format-response", + ) + .checked(auto_format_response) + .on_click(cx.listener(move |_, checked: &bool, window, cx| { + auto_format_beam_view.update(cx, |this, cx| { + this.apply_auto_format_response_setting( + *checked, window, cx, + ); + }); + })), + ) + .child( + v_flex() + .gap_1() + .child(div().text_sm().font_medium().child("Auto format response")) + .child( + div() + .text_xs() + .text_color(cx.theme().muted_foreground) + .child("Automatically formats the response body after a request completes."), + ), + ), + ) + .child(div().mt_4().text_sm().font_semibold().child("Editors")) + .child( + h_flex() + .items_start() + .gap_3() + .rounded(px(8.0)) + .border_1() + .border_color(cx.theme().border) + .p_3() + .child( + gpui_component::checkbox::Checkbox::new( + "settings-wrap-body-editor", + ) + .checked(wrap_body_editor) + .on_click(cx.listener(move |_, checked: &bool, window, cx| { + wrap_body_editor_beam_view.update(cx, |this, cx| { + this.apply_wrap_body_editor_setting(*checked, window, cx); + }); + })), + ) + .child( + v_flex() + .gap_1() + .child( + div() + .text_sm() + .font_medium() + .child("Wrap the request/response body editor"), + ) + .child( + div() + .text_xs() + .text_color(cx.theme().muted_foreground) + .child("Wraps long lines in the request and response body editors."), + ), + ), ); } } @@ -2524,6 +2604,38 @@ impl BeamView { cx.notify(); } + fn apply_auto_format_response_setting( + &mut self, + auto_format_response: bool, + window: &mut Window, + cx: &mut Context, + ) { + self.shell.theme.auto_format_response = auto_format_response; + if let Err(error) = self.persist_auto_format_response_state(auto_format_response) { + window.push_notification(error, cx); + } + cx.notify(); + } + + fn apply_wrap_body_editor_setting( + &mut self, + wrap_body_editor: bool, + window: &mut Window, + cx: &mut Context, + ) { + self.shell.theme.wrap_body_editor = wrap_body_editor; + self.request_body_editor.update(cx, |input, cx| { + input.set_soft_wrap(wrap_body_editor, window, cx); + }); + self.response_body_editor.update(cx, |input, cx| { + input.set_soft_wrap(wrap_body_editor, window, cx); + }); + if let Err(error) = self.persist_wrap_body_editor_state(wrap_body_editor) { + window.push_notification(error, cx); + } + cx.notify(); + } + fn apply_named_theme_by_name(theme_name: &str, cx: &mut App, persist: bool) -> bool { let stored_theme_name: SharedString = theme_name.to_string().into(); let theme_config = ThemeRegistry::global(cx) @@ -2973,7 +3085,7 @@ impl BeamView { ) { let content_type = snapshot.content_type.clone(); let formatted_body = - Self::auto_format_response_body(&snapshot.body, content_type.as_deref()); + self.response_body_for_display(&snapshot.body, content_type.as_deref()); self.response_status = snapshot.status.clone(); self.response_status_code = snapshot.status_code; self.response_time = snapshot.time.clone(); @@ -4614,6 +4726,24 @@ impl BeamView { .map_err(|error| format!("Failed to save local state: {error}")) } + fn persist_auto_format_response_state(&self, auto_format_response: bool) -> Result<(), String> { + let backend = FileSystemStorage::new(self.current_workspace_paths.clone()); + let storage = WorkspaceRepository::new(backend) + .map_err(|error| format!("Failed to load workspace: {error}"))?; + storage + .persist_auto_format_response_state(auto_format_response) + .map_err(|error| format!("Failed to save local state: {error}")) + } + + fn persist_wrap_body_editor_state(&self, wrap_body_editor: bool) -> Result<(), String> { + let backend = FileSystemStorage::new(self.current_workspace_paths.clone()); + let storage = WorkspaceRepository::new(backend) + .map_err(|error| format!("Failed to load workspace: {error}"))?; + storage + .persist_wrap_body_editor_state(wrap_body_editor) + .map_err(|error| format!("Failed to save local state: {error}")) + } + fn persist_theme_state_from_app(cx: &App) -> Result<(), String> { let paths = BeamPaths::default_user_config(); let backend = FileSystemStorage::new(paths); @@ -5534,6 +5664,7 @@ impl BeamView { let request_body_text = Self::body_editor_text(&request.body); let request_body_language = Self::body_editor_language(&request.body); let post_script_text = request.post_script.clone().unwrap_or_default(); + let wrap_body_editor = shell.theme.wrap_body_editor; let request_body_editor = cx.new(|cx| { InputState::new(window, cx) @@ -5543,7 +5674,7 @@ impl BeamView { tab_size: 2, hard_tabs: false, }) - .soft_wrap(false) + .soft_wrap(wrap_body_editor) .searchable(true) .placeholder("Enter request body...") .default_value(request_body_text) @@ -5559,7 +5690,7 @@ impl BeamView { hard_tabs: false, }) .searchable(true) - .soft_wrap(false) + .soft_wrap(wrap_body_editor) .placeholder("Response body will appear here...") .default_value("aa") }); @@ -5847,10 +5978,8 @@ impl BeamView { let response_status_code = response.status_code; let response_time = response.time.clone(); let response_size = response.size.clone(); - let response_body = Self::auto_format_response_body( - &response.body, - response.content_type.as_deref(), - ); + let response_body = this + .response_body_for_display(&response.body, response.content_type.as_deref()); let response_headers = response.headers.clone(); if should_update_visible_response { this.response_status = response_status; @@ -6492,6 +6621,14 @@ impl BeamView { body.to_string() } + fn response_body_for_display(&self, body: &str, content_type: Option<&str>) -> String { + if self.shell.theme.auto_format_response { + Self::auto_format_response_body(body, content_type) + } else { + body.to_string() + } + } + fn format_response_body(&mut self, window: &mut Window, cx: &mut Context) { let current_text = self.response_body_editor.read(cx).value().to_string(); let trimmed = current_text.trim(); @@ -7926,9 +8063,7 @@ impl BeamView { has_selection: bool, muted_color: Hsla, ) -> NativeMenu { - let menu = menu - .menu("Find", Box::new(input::Search)) - .separator(); + let menu = menu.menu("Find", Box::new(input::Search)).separator(); Self::build_text_edit_context_menu(menu, has_selection, muted_color) } From afb2fffab3c907cca998d7342663ae2d7dd90d07 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 21:57:55 +0800 Subject: [PATCH 2/6] Rename func to be generic --- src/ui.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index a28e3f9..6eff236 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -6598,7 +6598,7 @@ impl BeamView { } } - fn auto_format_response_body(body: &str, content_type: Option<&str>) -> String { + fn format_body_by_content_type(body: &str, content_type: Option<&str>) -> String { let trimmed = body.trim(); if trimmed.is_empty() { return body.to_string(); @@ -6623,7 +6623,7 @@ impl BeamView { fn response_body_for_display(&self, body: &str, content_type: Option<&str>) -> String { if self.shell.theme.auto_format_response { - Self::auto_format_response_body(body, content_type) + Self::format_body_by_content_type(body, content_type) } else { body.to_string() } @@ -6637,7 +6637,7 @@ impl BeamView { } let formatted = - Self::auto_format_response_body(¤t_text, self.response_content_type.as_deref()); + Self::format_body_by_content_type(¤t_text, self.response_content_type.as_deref()); if formatted == current_text { return; From 7b87c665c83371b8918dcfff2880340cace03661 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 22:20:59 +0800 Subject: [PATCH 3/6] Move the new configs to new panel --- src/ui.rs | 103 +++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 6eff236..47997b8 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -20,6 +20,7 @@ use gpui_component::{ native_menu::NativeMenu, resizable::{h_resizable, resizable_panel}, scroll::ScrollableElement, + switch::Switch, tag::Tag, text::{html, markdown}, v_flex, v_virtual_list, @@ -824,6 +825,7 @@ struct EnvironmentManagerDialogView { #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum SettingsSection { Theme, + Editor, } struct SettingsDialogView { @@ -863,8 +865,6 @@ impl Render for SettingsDialogView { SettingsSection::Theme => { let beam_view = self.beam_view.clone(); let font_size_beam_view = beam_view.clone(); - let auto_format_beam_view = beam_view.clone(); - let wrap_body_editor_beam_view = beam_view.clone(); let active_theme_name_for_menu = active_theme_name.clone(); let theme_options_for_menu = theme_options.clone(); let font_size_options_for_menu = font_size_options; @@ -961,76 +961,71 @@ impl Render for SettingsDialogView { }, ) }), - ) - .child(div().mt_4().text_sm().font_semibold().child("Response")) + ); + } + SettingsSection::Editor => { + let auto_format_beam_view = self.beam_view.clone(); + let wrap_body_editor_beam_view = self.beam_view.clone(); + right_panel = right_panel .child( h_flex() .items_start() + .justify_between() .gap_3() - .rounded(px(8.0)) - .border_1() - .border_color(cx.theme().border) - .p_3() - .child( - gpui_component::checkbox::Checkbox::new( - "settings-auto-format-response", - ) - .checked(auto_format_response) - .on_click(cx.listener(move |_, checked: &bool, window, cx| { - auto_format_beam_view.update(cx, |this, cx| { - this.apply_auto_format_response_setting( - *checked, window, cx, - ); - }); - })), - ) .child( v_flex() + .flex_1() .gap_1() - .child(div().text_sm().font_medium().child("Auto format response")) + .child( + div() + .text_sm() + .font_semibold() + .child("Editor soft wrap"), + ) .child( div() .text_xs() .text_color(cx.theme().muted_foreground) - .child("Automatically formats the response body after a request completes."), + .child("Wraps long lines in the body editor."), ), + ) + .child( + Switch::new("settings-wrap-body-editor") + .checked(wrap_body_editor) + .on_click(cx.listener(move |_, checked: &bool, window, cx| { + wrap_body_editor_beam_view.update(cx, |this, cx| { + this.apply_wrap_body_editor_setting(*checked, window, cx); + }); + })), ), ) - .child(div().mt_4().text_sm().font_semibold().child("Editors")) .child( h_flex() + .mt_4() .items_start() - .gap_3() - .rounded(px(8.0)) - .border_1() - .border_color(cx.theme().border) - .p_3() - .child( - gpui_component::checkbox::Checkbox::new( - "settings-wrap-body-editor", - ) - .checked(wrap_body_editor) - .on_click(cx.listener(move |_, checked: &bool, window, cx| { - wrap_body_editor_beam_view.update(cx, |this, cx| { - this.apply_wrap_body_editor_setting(*checked, window, cx); - }); - })), - ) + .justify_between() .child( v_flex() + .flex_1() .gap_1() - .child( - div() - .text_sm() - .font_medium() - .child("Wrap the request/response body editor"), - ) + .child(div().text_sm().font_semibold().child("Auto format response")) .child( div() .text_xs() .text_color(cx.theme().muted_foreground) - .child("Wraps long lines in the request and response body editors."), + .child("Automatically formats the response body after a request completes."), ), + ) + .child( + Switch::new("settings-auto-format-response") + .checked(auto_format_response) + .on_click(cx.listener(move |_, checked: &bool, window, cx| { + auto_format_beam_view.update(cx, |this, cx| { + this.apply_auto_format_response_setting( + *checked, window, cx, + ); + }); + })), ), ); } @@ -1069,6 +1064,20 @@ impl Render for SettingsDialogView { cx.notify(); })) .child("Appearance"), + ) + .child( + ListItem::new("settings-section-editor") + .w_full() + .cursor_pointer() + .rounded(px(8.0)) + .px_2() + .py_1() + .selected(self.selected_section == SettingsSection::Editor) + .on_click(cx.listener(|this, _, _, cx| { + this.selected_section = SettingsSection::Editor; + cx.notify(); + })) + .child("Editor"), ), ) .child( From 1db3190bf9b91e63182638b3da014742e1c0eb24 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 22:44:47 +0800 Subject: [PATCH 4/6] Consolidate editor content formatting --- src/ui.rs | 103 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 37 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index 47997b8..f36f850 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2379,6 +2379,11 @@ impl Render for WorkspaceDeleteDialogView { } } +enum BodyFormatHint<'a> { + FromConfig(&'a BodyConfig), + FromContentType(Option<&'a str>), +} + impl BeamView { fn begin_request_run_for(&mut self, request_id: Ulid) -> u64 { let run_id = self.next_request_run_id; @@ -6414,7 +6419,16 @@ impl BeamView { cx.notify(); } - fn format_request_body_text(body: &BodyConfig, text: &str) -> Result { + fn format_body_text(text: &str, hint: BodyFormatHint<'_>) -> Result { + match hint { + BodyFormatHint::FromConfig(body) => Self::format_body_text_from_config(body, text), + BodyFormatHint::FromContentType(content_type) => { + Self::format_body_text_from_content_type(text, content_type) + } + } + } + + fn format_body_text_from_config(body: &BodyConfig, text: &str) -> Result { match body { BodyConfig::Json { .. } => { let value = serde_json::from_str::(text) @@ -6460,6 +6474,32 @@ impl BeamView { } } + fn format_body_text_from_content_type( + body: &str, + content_type: Option<&str>, + ) -> Result { + let trimmed = body.trim(); + if trimmed.is_empty() { + return Err("Body is empty.".into()); + } + + let ct = content_type.unwrap_or("").to_lowercase(); + + if ct.contains("json") || trimmed.starts_with('{') || trimmed.starts_with('[') { + if let Ok(value) = serde_json::from_str::(trimmed) { + if let Ok(pretty) = serde_json::to_string_pretty(&value) { + return Ok(pretty); + } + } + } else if ct.contains("xml") || ct.contains("html") { + if let Some(formatted) = Self::format_xml_or_html(trimmed) { + return Ok(formatted); + } + } + + Err("Unable to format body for the detected content type.".into()) + } + fn format_request_body(&mut self, window: &mut Window, cx: &mut Context) { let view = cx.entity(); let body = self.request.body.clone(); @@ -6469,7 +6509,9 @@ impl BeamView { cx.spawn_in(window, async move |_, cx| { let result = cx .background_executor() - .spawn(async move { Self::format_request_body_text(&body, ¤t_text) }) + .spawn(async move { + Self::format_body_text(¤t_text, BodyFormatHint::FromConfig(&body)) + }) .await; let _ = view.update_in(cx, |this, window, cx| { @@ -6511,8 +6553,7 @@ impl BeamView { Self::body_with_updated_text(&this.request.body, formatted.clone()); this.request.active_tab = RequestTab::Body; this.request_body_editor.update(cx, |input, cx| { - input.set_value(formatted, window, cx); - input.focus(window, cx); + Self::replace_editor_text(input, formatted, window, cx); }); this.schedule_request_save(cx); cx.notify(); @@ -6607,46 +6648,25 @@ impl BeamView { } } - fn format_body_by_content_type(body: &str, content_type: Option<&str>) -> String { - let trimmed = body.trim(); - if trimmed.is_empty() { - return body.to_string(); - } - - let ct = content_type.unwrap_or("").to_lowercase(); - - if ct.contains("json") || trimmed.starts_with('{') || trimmed.starts_with('[') { - if let Ok(value) = serde_json::from_str::(trimmed) { - if let Ok(pretty) = serde_json::to_string_pretty(&value) { - return pretty; - } - } - } else if ct.contains("xml") || ct.contains("html") { - if let Some(formatted) = Self::format_xml_or_html(trimmed) { - return formatted; - } - } - - body.to_string() - } - fn response_body_for_display(&self, body: &str, content_type: Option<&str>) -> String { - if self.shell.theme.auto_format_response { - Self::format_body_by_content_type(body, content_type) - } else { - body.to_string() + if !self.shell.theme.auto_format_response { + return body.to_string(); } + Self::format_body_text(body, BodyFormatHint::FromContentType(content_type)) + .unwrap_or_else(|_| body.to_string()) } fn format_response_body(&mut self, window: &mut Window, cx: &mut Context) { let current_text = self.response_body_editor.read(cx).value().to_string(); - let trimmed = current_text.trim(); - if trimmed.is_empty() { + if current_text.trim().is_empty() { return; } - let formatted = - Self::format_body_by_content_type(¤t_text, self.response_content_type.as_deref()); + let formatted = Self::format_body_text( + ¤t_text, + BodyFormatHint::FromContentType(self.response_content_type.as_deref()), + ) + .unwrap_or_else(|_| current_text.clone()); if formatted == current_text { return; @@ -6656,13 +6676,22 @@ impl BeamView { window, cx, |input, window, cx| { - input.set_value(formatted, window, cx); - input.focus(window, cx); + Self::replace_editor_text(input, formatted, window, cx); }, ); cx.notify(); } + fn replace_editor_text( + input: &mut InputState, + text: String, + window: &mut Window, + cx: &mut Context, + ) { + input.set_value(text, window, cx); + input.focus(window, cx); + } + fn body_editor_language(body: &BodyConfig) -> &'static str { match body { BodyConfig::Json { .. } => "json", From 49e3817563fc4f16434e466d1f500b52237502d1 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 22:46:27 +0800 Subject: [PATCH 5/6] Add pointer cursor for toggles --- src/ui.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ui.rs b/src/ui.rs index f36f850..7947dfb 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -991,6 +991,7 @@ impl Render for SettingsDialogView { ) .child( Switch::new("settings-wrap-body-editor") + .cursor_pointer() .checked(wrap_body_editor) .on_click(cx.listener(move |_, checked: &bool, window, cx| { wrap_body_editor_beam_view.update(cx, |this, cx| { @@ -1018,6 +1019,7 @@ impl Render for SettingsDialogView { ) .child( Switch::new("settings-auto-format-response") + .cursor_pointer() .checked(auto_format_response) .on_click(cx.listener(move |_, checked: &bool, window, cx| { auto_format_beam_view.update(cx, |this, cx| { From 496f670da1e9d20ba01f87cb37ee8461d0279c46 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 17 Jun 2026 22:47:20 +0800 Subject: [PATCH 6/6] Update soft wrap description --- src/ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui.rs b/src/ui.rs index 7947dfb..be0f068 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -986,7 +986,7 @@ impl Render for SettingsDialogView { div() .text_xs() .text_color(cx.theme().muted_foreground) - .child("Wraps long lines in the body editor."), + .child("Wraps long lines in the editor."), ), ) .child(