Release Notes: - The git diff diff view now automatically switches from split mode to unified mode when the pane is narrower than a configurable minimum column count. You can configure this via the new `minimum_split_diff_width` setting.
Unified · Split
| @@ -299,6 +299,13 @@ · 298 unmodified lines | |||
| 299 | // | 299 | // |
| 300 | // Default: split | 300 | // Default: split |
| 301 | "diff_view_style": "split", | 301 | "diff_view_style": "split", |
| 302 | // The minimum width (in em-widths) at which the split diff view is used. | ||
| 303 | // When the editor is narrower than this, the diff view automatically | ||
| 304 | // switches to unified mode and switches back when the editor is wide | ||
| 305 | // enough. Set to 0 to disable automatic switching. | ||
| 306 | // | ||
| 307 | // Default: 100 | ||
| 308 | "minimum_split_diff_width": 100, | ||
| 302 | // Show method signatures in the editor, when inside parentheses. | 309 | // Show method signatures in the editor, when inside parentheses. |
| 303 | "auto_signature_help": false, | 310 | "auto_signature_help": false, |
| 304 | // Whether to show the signature help after completion or a bracket pair inserted. | 311 | // Whether to show the signature help after completion or a bracket pair inserted. |
| @@ -60,6 +60,7 @@ pub struct EditorSettings { · 59 unmodified lines | |||
| 60 | pub completion_menu_scrollbar: ShowScrollbar, | 60 | pub completion_menu_scrollbar: ShowScrollbar, |
| 61 | pub completion_detail_alignment: CompletionDetailAlignment, | 61 | pub completion_detail_alignment: CompletionDetailAlignment, |
| 62 | pub diff_view_style: DiffViewStyle, | 62 | pub diff_view_style: DiffViewStyle, |
| 63 | pub minimum_split_diff_width: f32, | ||
| 63 | } | 64 | } |
| 64 | #[derive(Debug, Clone)] | 65 | #[derive(Debug, Clone)] |
| 65 | pub struct Jupyter { | 66 | pub struct Jupyter { |
| @@ -294,6 +295,7 @@ impl Settings for EditorSettings { · 228 unmodified lines | |||
| 294 | .unwrap(), | 295 | .unwrap(), |
| 295 | completion_detail_alignment: editor.completion_detail_alignment.unwrap(), | 296 | completion_detail_alignment: editor.completion_detail_alignment.unwrap(), |
| 296 | diff_view_style: editor.diff_view_style.unwrap(), | 297 | diff_view_style: editor.diff_view_style.unwrap(), |
| 298 | minimum_split_diff_width: editor.minimum_split_diff_width.unwrap(), | ||
| 297 | } | 299 | } |
| 298 | } | 300 | } |
| 299 | } | 301 | } |
| @@ -7,7 +7,8 @@ use buffer_diff::{BufferDiff, BufferDiffSnapshot}; · 6 unmodified lines | |||
| 7 | use collections::HashMap; | 7 | use collections::HashMap; |
| 8 | 8 | ||
| 9 | use gpui::{ | 9 | use gpui::{ |
| 10 | Action, AppContext as _, Entity, EventEmitter, Focusable, Font, Subscription, WeakEntity, | 10 | Action, AppContext as _, Entity, EventEmitter, Focusable, Font, Pixels, Subscription, |
| 11 | WeakEntity, canvas, | ||
| 11 | }; | 12 | }; |
| 12 | use itertools::Itertools; | 13 | use itertools::Itertools; |
| 13 | use language::{Buffer, Capability, HighlightedText}; | 14 | use language::{Buffer, Capability, HighlightedText}; |
| @@ -17,7 +18,7 @@ use multi_buffer::{ · 3 unmodified lines | |||
| 17 | }; | 18 | }; |
| 18 | use project::Project; | 19 | use project::Project; |
| 19 | use rope::Point; | 20 | use rope::Point; |
| 20 | use settings::DiffViewStyle; | 21 | use settings::{DiffViewStyle, Settings}; |
| 21 | use text::{Bias, BufferId, OffsetRangeExt as _, Patch, ToPoint as _}; | 22 | use text::{Bias, BufferId, OffsetRangeExt as _, Patch, ToPoint as _}; |
| 22 | use ui::{ | 23 | use ui::{ |
| 23 | App, Context, InteractiveElement as _, IntoElement as _, ParentElement as _, Render, | 24 | App, Context, InteractiveElement as _, IntoElement as _, ParentElement as _, Render, |
| @@ -36,7 +37,7 @@ use workspace::{ · 12 unmodified lines | |||
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | use crate::{ | 39 | use crate::{ |
| 39 | Autoscroll, Editor, EditorEvent, RenderDiffHunkControlsFn, ToggleSoftWrap, | 40 | Autoscroll, Editor, EditorEvent, EditorSettings, RenderDiffHunkControlsFn, ToggleSoftWrap, |
| 40 | actions::{DisableBreakpoint, EditLogBreakpoint, EnableBreakpoint, ToggleBreakpoint}, | 41 | actions::{DisableBreakpoint, EditLogBreakpoint, EnableBreakpoint, ToggleBreakpoint}, |
| 41 | display_map::Companion, | 42 | display_map::Companion, |
| 42 | }; | 43 | }; |
| @@ -377,6 +378,12 @@ pub struct SplittableEditor { · 334 unmodified lines | |||
| 377 | workspace: WeakEntity<Workspace>, | 378 | workspace: WeakEntity<Workspace>, |
| 378 | split_state: Entity<SplitEditorState>, | 379 | split_state: Entity<SplitEditorState>, |
| 379 | searched_side: Option<SplitSide>, | 380 | searched_side: Option<SplitSide>, |
| 381 | /// The preferred diff style. | ||
| 382 | diff_view_style: DiffViewStyle, | ||
| 383 | /// True when the current width is below the minimum threshold for split | ||
| 384 | /// mode, regardless of the current diff view style setting. | ||
| 385 | too_narrow_for_split: bool, | ||
| 386 | last_width: Option<Pixels>, | ||
| 380 | _subscriptions: Vec<Subscription>, | 387 | _subscriptions: Vec<Subscription>, |
| 381 | } | 388 | } |
| 382 | 389 | ||
| @@ -396,6 +403,10 @@ impl SplittableEditor { · 13 unmodified lines | |||
| 396 | self.lhs.as_ref().map(|s| &s.editor) | 403 | self.lhs.as_ref().map(|s| &s.editor) |
| 397 | } | 404 | } |
| 398 | 405 | ||
| 406 | pub fn diff_view_style(&self) -> DiffViewStyle { | ||
| 407 | self.diff_view_style | ||
| 408 | } | ||
| 409 | |||
| 399 | pub fn is_split(&self) -> bool { | 410 | pub fn is_split(&self) -> bool { |
| 400 | self.lhs.is_some() | 411 | self.lhs.is_some() |
| 401 | } | 412 | } |
| @@ -499,12 +510,15 @@ impl SplittableEditor { · 97 unmodified lines | |||
| 499 | }); | 510 | }); |
| 500 | let split_state = cx.new(|cx| SplitEditorState::new(cx)); | 511 | let split_state = cx.new(|cx| SplitEditorState::new(cx)); |
| 501 | Self { | 512 | Self { |
| 513 | diff_view_style: style, | ||
| 502 | rhs_editor, | 514 | rhs_editor, |
| 503 | rhs_multibuffer, | 515 | rhs_multibuffer, |
| 504 | lhs: None, | 516 | lhs: None, |
| 505 | workspace: workspace.downgrade(), | 517 | workspace: workspace.downgrade(), |
| 506 | split_state, | 518 | split_state, |
| 507 | searched_side: None, | 519 | searched_side: None, |
| 520 | too_narrow_for_split: false, | ||
| 521 | last_width: None, | ||
| 508 | _subscriptions: subscriptions, | 522 | _subscriptions: subscriptions, |
| 509 | } | 523 | } |
| 510 | } | 524 | } |
| @@ -826,10 +840,19 @@ impl SplittableEditor { · 315 unmodified lines | |||
| 826 | window: &mut Window, | 840 | window: &mut Window, |
| 827 | cx: &mut Context<Self>, | 841 | cx: &mut Context<Self>, |
| 828 | ) { | 842 | ) { |
| 829 | if self.lhs.is_some() { | 843 | match self.diff_view_style { |
| 830 | self.unsplit(window, cx); | 844 | DiffViewStyle::Unified => { |
| 831 | } else { | 845 | self.diff_view_style = DiffViewStyle::Split; |
| 832 | self.split(window, cx); | 846 | if !self.too_narrow_for_split { |
| 847 | self.split(window, cx); | ||
| 848 | } | ||
| 849 | } | ||
| 850 | DiffViewStyle::Split => { | ||
| 851 | self.diff_view_style = DiffViewStyle::Unified; | ||
| 852 | if self.is_split() { | ||
| 853 | self.unsplit(window, cx); | ||
| 854 | } | ||
| 855 | } | ||
| 833 | } | 856 | } |
| 834 | } | 857 | } |
| 835 | 858 | ||
| @@ -1249,6 +1272,35 @@ impl SplittableEditor { · 413 unmodified lines | |||
| 1249 | } | 1272 | } |
| 1250 | }); | 1273 | }); |
| 1251 | } | 1274 | } |
| 1275 | |||
| 1276 | fn width_changed(&mut self, width: Pixels, window: &mut Window, cx: &mut Context<Self>) { | ||
| 1277 | self.last_width = Some(width); | ||
| 1278 | |||
| 1279 | let min_ems = EditorSettings::get_global(cx).minimum_split_diff_width; | ||
| 1280 | |||
| 1281 | let style = self.rhs_editor.read(cx).create_style(cx); | ||
| 1282 | let font_id = window.text_system().resolve_font(&style.text.font()); | ||
| 1283 | let font_size = style.text.font_size.to_pixels(window.rem_size()); | ||
| 1284 | let em_advance = window | ||
| 1285 | .text_system() | ||
| 1286 | .em_advance(font_id, font_size) | ||
| 1287 | .unwrap_or(font_size); | ||
| 1288 | let min_width = em_advance * min_ems; | ||
| 1289 | let is_split = self.lhs.is_some(); | ||
| 1290 | |||
| 1291 | self.too_narrow_for_split = min_ems > 0.0 && width < min_width; | ||
| 1292 | |||
| 1293 | match self.diff_view_style { | ||
| 1294 | DiffViewStyle::Unified => {} | ||
| 1295 | DiffViewStyle::Split => { | ||
| 1296 | if self.too_narrow_for_split && is_split { | ||
| 1297 | self.unsplit(window, cx); | ||
| 1298 | } else if !self.too_narrow_for_split && !is_split { | ||
| 1299 | self.split(window, cx); | ||
| 1300 | } | ||
| 1301 | } | ||
| 1302 | } | ||
| 1303 | } | ||
| 1252 | } | 1304 | } |
| 1253 | 1305 | ||
| 1254 | #[cfg(test)] | 1306 | #[cfg(test)] |
| @@ -2042,30 +2094,23 @@ impl Focusable for SplittableEditor { · 787 unmodified lines | |||
| 2042 | } | 2094 | } |
| 2043 | } | 2095 | } |
| 2044 | 2096 | ||
| 2045 | // impl Item for SplittableEditor { | ||
| 2046 | // type Event = EditorEvent; | ||
| 2047 | |||
| 2048 | // fn tab_content_text(&self, detail: usize, cx: &App) -> ui::SharedString { | ||
| 2049 | // self.rhs_editor().tab_content_text(detail, cx) | ||
| 2050 | // } | ||
| 2051 | |||
| 2052 | // fn as_searchable(&self, _this: &Entity<Self>, cx: &App) -> Option<Box<dyn workspace::searchable::SearchableItemHandle>> { | ||
| 2053 | // Some(Box::new(self.last_selected_editor().clone())) | ||
| 2054 | // } | ||
| 2055 | // } | ||
| 2056 | |||
| 2057 | impl Render for SplittableEditor { | 2097 | impl Render for SplittableEditor { |
| 2058 | fn render( | 2098 | fn render( |
| 2059 | &mut self, | 2099 | &mut self, |
| 2060 | _window: &mut ui::Window, | 2100 | _window: &mut ui::Window, |
| 2061 | cx: &mut ui::Context<Self>, | 2101 | cx: &mut ui::Context<Self>, |
| 2062 | ) -> impl ui::IntoElement { | 2102 | ) -> impl ui::IntoElement { |
| 2063 | let inner = if self.lhs.is_some() { | 2103 | let is_split = self.lhs.is_some(); |
| 2104 | let inner = if is_split { | ||
| 2064 | let style = self.rhs_editor.read(cx).create_style(cx); | 2105 | let style = self.rhs_editor.read(cx).create_style(cx); |
| 2065 | SplitEditorView::new(cx.entity(), style, self.split_state.clone()).into_any_element() | 2106 | SplitEditorView::new(cx.entity(), style, self.split_state.clone()).into_any_element() |
| 2066 | } else { | 2107 | } else { |
| 2067 | self.rhs_editor.clone().into_any_element() | 2108 | self.rhs_editor.clone().into_any_element() |
| 2068 | }; | 2109 | }; |
| 2110 | |||
| 2111 | let this = cx.entity().downgrade(); | ||
| 2112 | let last_width = self.last_width; | ||
| 2113 | |||
| 2069 | div() | 2114 | div() |
| 2070 | .id("splittable-editor") | 2115 | .id("splittable-editor") |
| 2071 | .on_action(cx.listener(Self::toggle_split)) | 2116 | .on_action(cx.listener(Self::toggle_split)) |
| @@ -2079,6 +2124,25 @@ impl Render for SplittableEditor { · 7 unmodified lines | |||
| 2079 | .capture_action(cx.listener(Self::toggle_soft_wrap)) | 2124 | .capture_action(cx.listener(Self::toggle_soft_wrap)) |
| 2080 | .size_full() | 2125 | .size_full() |
| 2081 | .child(inner) | 2126 | .child(inner) |
| 2127 | .child( | ||
| 2128 | canvas( | ||
| 2129 | move |bounds, window, cx| { | ||
| 2130 | let width = bounds.size.width; | ||
| 2131 | if last_width == Some(width) { | ||
| 2132 | return; | ||
| 2133 | } | ||
| 2134 | window.defer(cx, move |window, cx| { | ||
| 2135 | this.update(cx, |this, cx| { | ||
| 2136 | this.width_changed(width, window, cx); | ||
| 2137 | }) | ||
| 2138 | .ok(); | ||
| 2139 | }); | ||
| 2140 | }, | ||
| 2141 | |_, _, _, _| {}, | ||
| 2142 | ) | ||
| 2143 | .absolute() | ||
| 2144 | .size_full(), | ||
| 2145 | ) | ||
| 2082 | } | 2146 | } |
| 2083 | } | 2147 | } |
| 2084 | 2148 | ||
| @@ -20,9 +20,9 @@ use editor::{ · 19 unmodified lines | |||
| 20 | }; | 20 | }; |
| 21 | use futures::channel::oneshot; | 21 | use futures::channel::oneshot; |
| 22 | use gpui::{ | 22 | use gpui::{ |
| 23 | App, ClickEvent, Context, Entity, EventEmitter, Focusable, InteractiveElement as _, | 23 | Action as _, App, ClickEvent, Context, Entity, EventEmitter, Focusable, |
| 24 | IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle, Styled, Subscription, Task, | 24 | InteractiveElement as _, IntoElement, KeyContext, ParentElement as _, Render, ScrollHandle, |
| 25 | WeakEntity, Window, div, | 25 | Styled, Subscription, Task, WeakEntity, Window, div, |
| 26 | }; | 26 | }; |
| 27 | use language::{Language, LanguageRegistry}; | 27 | use language::{Language, LanguageRegistry}; |
| 28 | use project::{ | 28 | use project::{ |
| @@ -33,7 +33,9 @@ use project::{ · 4 unmodified lines | |||
| 33 | use fs::Fs; | 33 | use fs::Fs; |
| 34 | use settings::{DiffViewStyle, Settings, update_settings_file}; | 34 | use settings::{DiffViewStyle, Settings, update_settings_file}; |
| 35 | use std::{any::TypeId, sync::Arc}; | 35 | use std::{any::TypeId, sync::Arc}; |
| 36 | use zed_actions::{outline::ToggleOutline, workspace::CopyPath, workspace::CopyRelativePath}; | 36 | use zed_actions::{ |
| 37 | OpenSettingsAt, outline::ToggleOutline, workspace::CopyPath, workspace::CopyRelativePath, | ||
| 38 | }; | ||
| 37 | 39 | ||
| 38 | use ui::{ | 40 | use ui::{ |
| 39 | BASE_REM_SIZE_IN_PX, IconButtonShape, PlatformStyle, TextSize, Tooltip, prelude::*, | 41 | BASE_REM_SIZE_IN_PX, IconButtonShape, PlatformStyle, TextSize, Tooltip, prelude::*, |
| @@ -110,96 +112,97 @@ impl Render for BufferSearchBar { · 70 unmodified lines | |||
| 110 | .as_ref() | 112 | .as_ref() |
| 111 | .and_then(|weak| weak.upgrade()) | 113 | .and_then(|weak| weak.upgrade()) |
| 112 | .map(|splittable_editor| { | 114 | .map(|splittable_editor| { |
| 113 | let is_split = splittable_editor.read(cx).is_split(); | 115 | let editor_ref = splittable_editor.read(cx); |
| 116 | let diff_view_style = editor_ref.diff_view_style(); | ||
| 117 | let is_split = editor_ref.is_split(); | ||
| 118 | let min_columns = | ||
| 119 | EditorSettings::get_global(cx).minimum_split_diff_width as u32; | ||
| 120 | |||
| 121 | let mut split_button = IconButton::new("diff-split", IconName::DiffSplit) | ||
| 122 | .shape(IconButtonShape::Square) | ||
| 123 | .tooltip(Tooltip::element(move |_, cx| { | ||
| 124 | let message = if min_columns == 0 { | ||
| 125 | SharedString::from("Split") | ||
| 126 | } else { | ||
| 127 | format!("Split when wider than {} columns", min_columns).into() | ||
| 128 | }; | ||
| 129 | |||
| 130 | v_flex() | ||
| 131 | .child(message) | ||
| 132 | .child( | ||
| 133 | h_flex() | ||
| 134 | .gap_0p5() | ||
| 135 | .text_ui_sm(cx) | ||
| 136 | .text_color(Color::Muted.color(cx)) | ||
| 137 | .children(render_modifiers( | ||
| 138 | &gpui::Modifiers::secondary_key(), | ||
| 139 | PlatformStyle::platform(), | ||
| 140 | None, | ||
| 141 | Some(TextSize::Small.rems(cx).into()), | ||
| 142 | false, | ||
| 143 | )) | ||
| 144 | .child("click to change min width"), | ||
| 145 | ) | ||
| 146 | .into_any() | ||
| 147 | })) | ||
| 148 | .on_click({ | ||
| 149 | let splittable_editor = splittable_editor.downgrade(); | ||
| 150 | move |_, window, cx| { | ||
| 151 | if window.modifiers().secondary() { | ||
| 152 | window.dispatch_action( | ||
| 153 | OpenSettingsAt { | ||
| 154 | path: "minimum_split_diff_width".to_string(), | ||
| 155 | } | ||
| 156 | .boxed_clone(), | ||
| 157 | cx, | ||
| 158 | ); | ||
| 159 | } else { | ||
| 160 | update_settings_file( | ||
| 161 | <dyn Fs>::global(cx), | ||
| 162 | cx, | ||
| 163 | |settings, _| { | ||
| 164 | settings.editor.diff_view_style = | ||
| 165 | Some(DiffViewStyle::Split); | ||
| 166 | }, | ||
| 167 | ); | ||
| 168 | if diff_view_style == DiffViewStyle::Unified { | ||
| 169 | splittable_editor | ||
| 170 | .update(cx, |editor, cx| { | ||
| 171 | editor.toggle_split(&ToggleSplitDiff, window, cx); | ||
| 172 | }) | ||
| 173 | .ok(); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
| 177 | }); | ||
| 178 | |||
| 179 | if diff_view_style == DiffViewStyle::Split { | ||
| 180 | if !is_split { | ||
| 181 | split_button = split_button.icon_color(Color::Disabled) | ||
| 182 | } else { | ||
| 183 | split_button = split_button.toggle_state(true) | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 114 | h_flex() | 187 | h_flex() |
| 115 | .gap_1() | 188 | .gap_1() |
| 116 | .child( | 189 | .child( |
| 117 | IconButton::new("diff-unified", IconName::DiffUnified) | 190 | IconButton::new("diff-unified", IconName::DiffUnified) |
| 118 | .shape(IconButtonShape::Square) | 191 | .shape(IconButtonShape::Square) |
| 119 | .toggle_state(!is_split) | 192 | .toggle_state(diff_view_style == DiffViewStyle::Unified) |
| 120 | .tooltip(Tooltip::element(move |_, cx| { | 193 | .tooltip(Tooltip::text("Unified")) |
| 121 | v_flex() | ||
| 122 | .child("Unified") | ||
| 123 | .child( | ||
| 124 | h_flex() | ||
| 125 | .gap_0p5() | ||
| 126 | .text_ui_sm(cx) | ||
| 127 | .text_color(Color::Muted.color(cx)) | ||
| 128 | .children(render_modifiers( | ||
| 129 | &gpui::Modifiers::secondary_key(), | ||
| 130 | PlatformStyle::platform(), | ||
| 131 | None, | ||
| 132 | Some(TextSize::Small.rems(cx).into()), | ||
| 133 | false, | ||
| 134 | )) | ||
| 135 | .child("click to set as default"), | ||
| 136 | ) | ||
| 137 | .into_any() | ||
| 138 | })) | ||
| 139 | .on_click({ | ||
| 140 | let splittable_editor = splittable_editor.downgrade(); | ||
| 141 | move |_, window, cx| { | ||
| 142 | if window.modifiers().secondary() { | ||
| 143 | update_settings_file( | ||
| 144 | <dyn Fs>::global(cx), | ||
| 145 | cx, | ||
| 146 | |settings, _| { | ||
| 147 | settings.editor.diff_view_style = | ||
| 148 | Some(DiffViewStyle::Unified); | ||
| 149 | }, | ||
| 150 | ); | ||
| 151 | } | ||
| 152 | if is_split { | ||
| 153 | splittable_editor | ||
| 154 | .update(cx, |editor, cx| { | ||
| 155 | editor.toggle_split( | ||
| 156 | &ToggleSplitDiff, | ||
| 157 | window, | ||
| 158 | cx, | ||
| 159 | ); | ||
| 160 | }) | ||
| 161 | .ok(); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | }), | ||
| 165 | ) | ||
| 166 | .child( | ||
| 167 | IconButton::new("diff-split", IconName::DiffSplit) | ||
| 168 | .shape(IconButtonShape::Square) | ||
| 169 | .toggle_state(is_split) | ||
| 170 | .tooltip(Tooltip::element(move |_, cx| { | ||
| 171 | v_flex() | ||
| 172 | .child("Split") | ||
| 173 | .child( | ||
| 174 | h_flex() | ||
| 175 | .gap_0p5() | ||
| 176 | .text_ui_sm(cx) | ||
| 177 | .text_color(Color::Muted.color(cx)) | ||
| 178 | .children(render_modifiers( | ||
| 179 | &gpui::Modifiers::secondary_key(), | ||
| 180 | PlatformStyle::platform(), | ||
| 181 | None, | ||
| 182 | Some(TextSize::Small.rems(cx).into()), | ||
| 183 | false, | ||
| 184 | )) | ||
| 185 | .child("click to set as default"), | ||
| 186 | ) | ||
| 187 | .into_any() | ||
| 188 | })) | ||
| 189 | .on_click({ | 194 | .on_click({ |
| 190 | let splittable_editor = splittable_editor.downgrade(); | 195 | let splittable_editor = splittable_editor.downgrade(); |
| 191 | move |_, window, cx| { | 196 | move |_, window, cx| { |
| 192 | if window.modifiers().secondary() { | 197 | update_settings_file( |
| 193 | update_settings_file( | 198 | <dyn Fs>::global(cx), |
| 194 | <dyn Fs>::global(cx), | 199 | cx, |
| 195 | cx, | 200 | |settings, _| { |
| 196 | |settings, _| { | 201 | settings.editor.diff_view_style = |
| 197 | settings.editor.diff_view_style = | 202 | Some(DiffViewStyle::Unified); |
| 198 | Some(DiffViewStyle::Split); | 203 | }, |
| 199 | }, | 204 | ); |
| 200 | ); | 205 | if diff_view_style == DiffViewStyle::Split { |
| 201 | } | ||
| 202 | if !is_split { | ||
| 203 | splittable_editor | 206 | splittable_editor |
| 204 | .update(cx, |editor, cx| { | 207 | .update(cx, |editor, cx| { |
| 205 | editor.toggle_split( | 208 | editor.toggle_split( |
| @@ -213,6 +216,7 @@ impl Render for BufferSearchBar { · 7 unmodified lines | |||
| 213 | } | 216 | } |
| 214 | }), | 217 | }), |
| 215 | ) | 218 | ) |
| 219 | .child(split_button) | ||
| 216 | }) | 220 | }) |
| 217 | } else { | 221 | } else { |
| 218 | None | 222 | None |
| @@ -308,6 +308,7 @@ impl VsCodeSettings { · 307 unmodified lines | |||
| 308 | completion_menu_scrollbar: None, | 308 | completion_menu_scrollbar: None, |
| 309 | completion_detail_alignment: None, | 309 | completion_detail_alignment: None, |
| 310 | diff_view_style: None, | 310 | diff_view_style: None, |
| 311 | minimum_split_diff_width: None, | ||
| 311 | } | 312 | } |
| 312 | } | 313 | } |
| 313 | 314 | ||
| @@ -226,6 +226,14 @@ pub struct EditorSettingsContent { · 225 unmodified lines | |||
| 226 | /// | 226 | /// |
| 227 | /// Default: split | 227 | /// Default: split |
| 228 | pub diff_view_style: Option<DiffViewStyle>, | 228 | pub diff_view_style: Option<DiffViewStyle>, |
| 229 | |||
| 230 | /// The minimum width (in em-widths) at which the split diff view is used. | ||
| 231 | /// When the editor is narrower than this, the diff view automatically | ||
| 232 | /// switches to unified mode and switches back when the editor is wide | ||
| 233 | /// enough. Set to 0 to disable automatic switching. | ||
| 234 | /// | ||
| 235 | /// Default: 100 | ||
| 236 | pub minimum_split_diff_width: Option<f32>, | ||
| 229 | } | 237 | } |
| 230 | 238 | ||
| 231 | #[derive( | 239 | #[derive( |
| @@ -1474,7 +1474,7 @@ fn editor_page() -> SettingsPage { · 1473 unmodified lines | |||
| 1474 | ] | 1474 | ] |
| 1475 | } | 1475 | } |
| 1476 | 1476 | ||
| 1477 | fn multibuffer_section() -> [SettingsPageItem; 6] { | 1477 | fn multibuffer_section() -> [SettingsPageItem; 7] { |
| 1478 | [ | 1478 | [ |
| 1479 | SettingsPageItem::SectionHeader("Multibuffer"), | 1479 | SettingsPageItem::SectionHeader("Multibuffer"), |
| 1480 | SettingsPageItem::SettingItem(SettingItem { | 1480 | SettingsPageItem::SettingItem(SettingItem { |
| @@ -1554,6 +1554,21 @@ fn editor_page() -> SettingsPage { · 73 unmodified lines | |||
| 1554 | metadata: None, | 1554 | metadata: None, |
| 1555 | files: USER, | 1555 | files: USER, |
| 1556 | }), | 1556 | }), |
| 1557 | SettingsPageItem::SettingItem(SettingItem { | ||
| 1558 | title: "Minimum Split Diff Width", | ||
| 1559 | description: "The minimum width (in columns) at which the split diff view is used. When the editor is narrower, the diff view automatically switches to unified mode. Set to 0 to disable.", | ||
| 1560 | field: Box::new(SettingField { | ||
| 1561 | json_path: Some("minimum_split_diff_width"), | ||
| 1562 | pick: |settings_content| { | ||
| 1563 | settings_content.editor.minimum_split_diff_width.as_ref() | ||
| 1564 | }, | ||
| 1565 | write: |settings_content, value| { | ||
| 1566 | settings_content.editor.minimum_split_diff_width = value; | ||
| 1567 | }, | ||
| 1568 | }), | ||
| 1569 | metadata: None, | ||
| 1570 | files: USER, | ||
| 1571 | }), | ||
| 1557 | ] | 1572 | ] |
| 1558 | } | 1573 | } |
| 1559 | 1574 | ||