markdown_preview: Add max-width setting (#59512)
This PR introduces a markdown preview max-width setting in which we allow to limit by a given pixel number how wide the content within the preview tab should go. Before this, content would render edge-to-edge and if you're reading long markdown docs with no split panes, having it be full width like that was a horrible reading experience. So, right now, you can control that through the `zed://settings/markdown_preview.max_width` setting. <img width="600" alt="Screenshot 2026-06-18 at 1 24@2x" src="https://github.com/user-attachments/assets/7f0216e1-e4ac-47f7-975b-5de7a0dd4c6d" /> Release Notes: - Added setting to control max-width of content within the markdown preview.
This commit is contained in:
1 parent
aed5023e80
commit
fb2e66f61b
7 files changed
+122
-3
No files matched your search
@@ -104,6 +104,16 @@
|
||||
// The unit for image file sizes: "binary" (KiB, MiB) or decimal (KB, MB)
|
||||
"unit": "binary",
|
||||
},
|
||||
// Markdown preview settings
|
||||
"markdown_preview": {
|
||||
// Whether to limit the width of the rendered markdown content. When
|
||||
// enabled, content is constrained to `max_width` and centered
|
||||
// horizontally within the preview pane.
|
||||
"limit_content_width": true,
|
||||
// The maximum width, in pixels, of the rendered markdown content when
|
||||
// limit_content_width is enabled.
|
||||
"max_width": 800,
|
||||
},
|
||||
// Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier.
|
||||
//
|
||||
// 1. Maps to `Alt` on Linux and Windows and to `Option` on MacOS:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use gpui::{App, actions};
|
||||
use workspace::Workspace;
|
||||
|
||||
pub mod markdown_preview_settings;
|
||||
pub mod markdown_preview_view;
|
||||
|
||||
pub use zed_actions::preview::markdown::{OpenPreview, OpenPreviewToTheSide};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
use gpui::{Pixels, px};
|
||||
use settings::{RegisterSetting, Settings};
|
||||
|
||||
/// The settings for the markdown preview.
|
||||
#[derive(Clone, Copy, Debug, Default, RegisterSetting)]
|
||||
pub struct MarkdownPreviewSettings {
|
||||
/// The maximum width of the rendered markdown content, or `None` to render
|
||||
/// content edge to edge.
|
||||
pub max_width: Option<Pixels>,
|
||||
}
|
||||
|
||||
impl Settings for MarkdownPreviewSettings {
|
||||
fn from_settings(content: &settings::SettingsContent) -> Self {
|
||||
let content = content.markdown_preview.clone().unwrap_or_default();
|
||||
let max_width = if content.limit_content_width.unwrap_or(true) {
|
||||
content.max_width.map(px)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self { max_width }
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ use workspace::searchable::{
|
||||
};
|
||||
use workspace::{ItemId, Pane, Workspace, WorkspaceId, delete_unloaded_items};
|
||||
|
||||
use crate::markdown_preview_settings::MarkdownPreviewSettings;
|
||||
use crate::{
|
||||
OpenFollowingPreview, OpenPreview, OpenPreviewToTheSide, ScrollDown, ScrollDownByItem,
|
||||
};
|
||||
@@ -1132,7 +1133,8 @@ impl Render for MarkdownPreviewView {
|
||||
let markdown_element =
|
||||
self.render_markdown_element(&preview_theme, window, cx);
|
||||
let markdown = self.markdown.clone();
|
||||
right_click_menu("markdown-preview-context-menu")
|
||||
let max_width = MarkdownPreviewSettings::get_global(cx).max_width;
|
||||
let content = right_click_menu("markdown-preview-context-menu")
|
||||
.trigger(move |_, _, _| markdown_element)
|
||||
.menu(move |window, cx| {
|
||||
let focus = window.focused(cx);
|
||||
@@ -1148,7 +1150,11 @@ impl Render for MarkdownPreviewView {
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
div()
|
||||
.w_full()
|
||||
.when_some(max_width, |this, max_width| this.max_w(max_width).mx_auto())
|
||||
.child(content)
|
||||
}),
|
||||
)
|
||||
.vertical_scrollbar_for(&self.scroll_handle, window, cx)
|
||||
|
||||
@@ -194,6 +194,7 @@ impl VsCodeSettings {
|
||||
helix_mode: None,
|
||||
hide_mouse: None,
|
||||
image_viewer: None,
|
||||
markdown_preview: None,
|
||||
journal: None,
|
||||
language_models: None,
|
||||
line_indicator_format: None,
|
||||
|
||||
@@ -178,6 +178,9 @@ pub struct SettingsContent {
|
||||
/// The settings for the image viewer.
|
||||
pub image_viewer: Option<ImageViewerSettingsContent>,
|
||||
|
||||
/// The settings for the markdown preview.
|
||||
pub markdown_preview: Option<MarkdownPreviewSettingsContent>,
|
||||
|
||||
pub repl: Option<ReplSettingsContent>,
|
||||
|
||||
/// Whether or not to enable Helix mode.
|
||||
@@ -1094,6 +1097,23 @@ pub enum LineIndicatorFormat {
|
||||
Long,
|
||||
}
|
||||
|
||||
/// The settings for the markdown preview.
|
||||
#[with_fallible_options]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, Default, PartialEq)]
|
||||
pub struct MarkdownPreviewSettingsContent {
|
||||
/// Whether to limit the width of the rendered markdown content. When
|
||||
/// enabled, content is constrained to `max_width` and centered
|
||||
/// horizontally within the preview pane, for optimal readability.
|
||||
///
|
||||
/// Default: true
|
||||
pub limit_content_width: Option<bool>,
|
||||
/// The maximum width, in pixels, of the rendered markdown content when
|
||||
/// `limit_content_width` is enabled.
|
||||
///
|
||||
/// Default: 800
|
||||
pub max_width: Option<f32>,
|
||||
}
|
||||
|
||||
/// The settings for the image viewer.
|
||||
#[with_fallible_options]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, Default, PartialEq)]
|
||||
|
||||
@@ -9654,7 +9654,7 @@ fn language_settings_data() -> Box<[SettingsPageItem]> {
|
||||
]
|
||||
}
|
||||
|
||||
fn global_only_miscellaneous_sub_section() -> [SettingsPageItem; 3] {
|
||||
fn global_only_miscellaneous_sub_section() -> [SettingsPageItem; 4] {
|
||||
[
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Image Viewer",
|
||||
@@ -9675,6 +9675,65 @@ fn language_settings_data() -> Box<[SettingsPageItem]> {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::DynamicItem(DynamicItem {
|
||||
discriminant: SettingItem {
|
||||
files: USER,
|
||||
title: "Limit Markdown Preview Width",
|
||||
description: "Whether to constrain the markdown preview content to a maximum width, centering it when the pane is wider, for optimal readability.",
|
||||
field: Box::new(SettingField::<bool> {
|
||||
organization_override: None,
|
||||
json_path: Some("markdown_preview.limit_content_width"),
|
||||
pick: |settings_content| {
|
||||
settings_content
|
||||
.markdown_preview
|
||||
.as_ref()?
|
||||
.limit_content_width
|
||||
.as_ref()
|
||||
},
|
||||
write: |settings_content, value, _| {
|
||||
settings_content
|
||||
.markdown_preview
|
||||
.get_or_insert_default()
|
||||
.limit_content_width = value;
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
},
|
||||
pick_discriminant: |settings_content| {
|
||||
let enabled = settings_content
|
||||
.markdown_preview
|
||||
.as_ref()?
|
||||
.limit_content_width
|
||||
.unwrap_or(true);
|
||||
Some(if enabled { 1 } else { 0 })
|
||||
},
|
||||
fields: vec![
|
||||
vec![],
|
||||
vec![SettingItem {
|
||||
files: USER,
|
||||
title: "Max Width",
|
||||
description: "Maximum content width in pixels. Content will be centered when the pane is wider than this value.",
|
||||
field: Box::new(SettingField {
|
||||
organization_override: None,
|
||||
json_path: Some("markdown_preview.max_width"),
|
||||
pick: |settings_content| {
|
||||
settings_content
|
||||
.markdown_preview
|
||||
.as_ref()?
|
||||
.max_width
|
||||
.as_ref()
|
||||
},
|
||||
write: |settings_content, value, _| {
|
||||
settings_content
|
||||
.markdown_preview
|
||||
.get_or_insert_default()
|
||||
.max_width = value;
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
}],
|
||||
],
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Auto Replace Emoji Shortcode",
|
||||
description: "Whether to automatically replace emoji shortcodes with emoji characters.",
|
||||
|
||||
Reference in new issue
Block a user