From e752ec1a92642a645ff371c7d31bda013693cfd3 Mon Sep 17 00:00:00 2001
From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Date: Wed, 28 Jan 2026 00:19:13 -0300
Subject: [PATCH] Add item for opening Markdown/SVG files in preview tab in
right-click menu (#47821)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Following user feedback, this should help making the Markdown Preview
more discoverable.
| Buffer Right-click | Tab Right-click |
|--------|--------|
|
|
|
Release Notes:
- Workspace: Added a menu item in the buffer and tab right-click menu
for opening Markdown and SVG files in the preview tab.
---
Cargo.lock | 2 +
crates/editor/src/items.rs | 45 +++++++++++++++++++
crates/editor/src/mouse_context_menu.rs | 27 +++++++++++
crates/markdown_preview/Cargo.toml | 1 +
.../markdown_preview/src/markdown_preview.rs | 6 +--
crates/svg_preview/Cargo.toml | 1 +
crates/svg_preview/src/svg_preview.rs | 6 +--
crates/zed_actions/src/lib.rs | 30 +++++++++++++
8 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0989967dd5696e667b6b4a4f7477e52469834ce9..fdc2a0c224167de908eedf4921d898169a365df4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9857,6 +9857,7 @@ dependencies = [
"urlencoding",
"util",
"workspace",
+ "zed_actions",
]
[[package]]
@@ -16155,6 +16156,7 @@ dependencies = [
"multi_buffer",
"ui",
"workspace",
+ "zed_actions",
]
[[package]]
diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs
index 14b736acff64ac855b79ce54dcb56d09c7afb868..047be5b9f29d4e20a1047e0366b6f554264547f5 100644
--- a/crates/editor/src/items.rs
+++ b/crates/editor/src/items.rs
@@ -59,6 +59,9 @@ use workspace::{
item::{BreadcrumbText, FollowEvent, ProjectItemKind},
searchable::SearchOptions,
};
+use zed_actions::preview::{
+ markdown::OpenPreview as OpenMarkdownPreview, svg::OpenPreview as OpenSvgPreview,
+};
pub const MAX_TAB_TITLE_LEN: usize = 24;
@@ -1033,6 +1036,48 @@ impl Item for Editor {
}
}
+ fn tab_extra_context_menu_actions(
+ &self,
+ _window: &mut Window,
+ cx: &mut Context,
+ ) -> Vec<(SharedString, Box)> {
+ let mut actions = Vec::new();
+
+ let is_markdown = self
+ .buffer()
+ .read(cx)
+ .as_singleton()
+ .and_then(|buffer| buffer.read(cx).language())
+ .is_some_and(|language| language.name().as_ref() == "Markdown");
+
+ let is_svg = self
+ .buffer()
+ .read(cx)
+ .as_singleton()
+ .and_then(|buffer| buffer.read(cx).file())
+ .is_some_and(|file| {
+ std::path::Path::new(file.file_name(cx))
+ .extension()
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("svg"))
+ });
+
+ if is_markdown {
+ actions.push((
+ "Open Markdown Preview".into(),
+ Box::new(OpenMarkdownPreview) as Box,
+ ));
+ }
+
+ if is_svg {
+ actions.push((
+ "Open SVG Preview".into(),
+ Box::new(OpenSvgPreview) as Box,
+ ));
+ }
+
+ actions
+ }
+
fn preserve_preview(&self, cx: &App) -> bool {
self.buffer.read(cx).preserve_preview(cx)
}
diff --git a/crates/editor/src/mouse_context_menu.rs b/crates/editor/src/mouse_context_menu.rs
index ae1d81da50511ecd61b3e6342ac71351feb1f41b..2cc050dae8be73fda89a6b9982b052bddd639063 100644
--- a/crates/editor/src/mouse_context_menu.rs
+++ b/crates/editor/src/mouse_context_menu.rs
@@ -14,6 +14,9 @@ use std::ops::Range;
use text::PointUtf16;
use workspace::OpenInTerminal;
use zed_actions::agent::AddSelectionToThread;
+use zed_actions::preview::{
+ markdown::OpenPreview as OpenMarkdownPreview, svg::OpenPreview as OpenSvgPreview,
+};
#[derive(Debug)]
pub enum MenuPosition {
@@ -218,6 +221,24 @@ pub fn deploy_context_menu(
let run_to_cursor = window.is_action_available(&RunToCursor, cx);
let disable_ai = DisableAiSettings::get_global(cx).disable_ai;
+ let is_markdown = editor
+ .buffer()
+ .read(cx)
+ .as_singleton()
+ .and_then(|buffer| buffer.read(cx).language())
+ .is_some_and(|language| language.name().as_ref() == "Markdown");
+
+ let is_svg = editor
+ .buffer()
+ .read(cx)
+ .as_singleton()
+ .and_then(|buffer| buffer.read(cx).file())
+ .is_some_and(|file| {
+ std::path::Path::new(file.file_name(cx))
+ .extension()
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("svg"))
+ });
+
ui::ContextMenu::build(window, cx, |menu, _window, _cx| {
let builder = menu
.on_blur_subscription(Subscription::new(|| {}))
@@ -272,6 +293,12 @@ pub fn deploy_context_menu(
},
Box::new(RevealInFileManager),
)
+ .when(is_markdown, |builder| {
+ builder.action("Open Markdown Preview", Box::new(OpenMarkdownPreview))
+ })
+ .when(is_svg, |builder| {
+ builder.action("Open SVG Preview", Box::new(OpenSvgPreview))
+ })
.action_disabled_when(
!has_reveal_target,
"Open in Terminal",
diff --git a/crates/markdown_preview/Cargo.toml b/crates/markdown_preview/Cargo.toml
index d61ec00cc8cfd5e04768381b64d5230682924623..c9cce94de1f10ac85a93663dea09a947586da282 100644
--- a/crates/markdown_preview/Cargo.toml
+++ b/crates/markdown_preview/Cargo.toml
@@ -34,6 +34,7 @@ ui.workspace = true
urlencoding.workspace = true
util.workspace = true
workspace.workspace = true
+zed_actions.workspace = true
[dev-dependencies]
editor = { workspace = true, features = ["test-support"] }
diff --git a/crates/markdown_preview/src/markdown_preview.rs b/crates/markdown_preview/src/markdown_preview.rs
index 61c99764add0a96135730d3cccfe4ef744a63d40..c7e8e9e9272e196da25be086640316129fb819bd 100644
--- a/crates/markdown_preview/src/markdown_preview.rs
+++ b/crates/markdown_preview/src/markdown_preview.rs
@@ -7,6 +7,8 @@ pub mod markdown_parser;
pub mod markdown_preview_view;
pub mod markdown_renderer;
+pub use zed_actions::preview::markdown::{OpenPreview, OpenPreviewToTheSide};
+
actions!(
markdown,
[
@@ -24,10 +26,6 @@ actions!(
ScrollUpByItem,
/// Scrolls down by one markdown element in the markdown preview
ScrollDownByItem,
- /// Opens a markdown preview for the current file.
- OpenPreview,
- /// Opens a markdown preview in a split pane.
- OpenPreviewToTheSide,
/// Opens a following markdown preview that syncs with the editor.
OpenFollowingPreview
]
diff --git a/crates/svg_preview/Cargo.toml b/crates/svg_preview/Cargo.toml
index 18f55e28d5d1364d75492455508bb34a5e24422b..9ee085ee07355a3f5c8cf31768b44610be7b50dd 100644
--- a/crates/svg_preview/Cargo.toml
+++ b/crates/svg_preview/Cargo.toml
@@ -18,3 +18,4 @@ gpui.workspace = true
language.workspace = true
ui.workspace = true
workspace.workspace = true
+zed_actions.workspace = true
diff --git a/crates/svg_preview/src/svg_preview.rs b/crates/svg_preview/src/svg_preview.rs
index ca1891394d693b5a9817fcc43f462a4f611b94f2..060639db5fa29a552bd606dca0c470aab5116a43 100644
--- a/crates/svg_preview/src/svg_preview.rs
+++ b/crates/svg_preview/src/svg_preview.rs
@@ -3,13 +3,11 @@ use workspace::Workspace;
pub mod svg_preview_view;
+pub use zed_actions::preview::svg::{OpenPreview, OpenPreviewToTheSide};
+
actions!(
svg,
[
- /// Opens an SVG preview for the current file.
- OpenPreview,
- /// Opens an SVG preview in a split pane.
- OpenPreviewToTheSide,
/// Opens a following SVG preview that syncs with the editor.
OpenFollowingPreview
]
diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs
index 1d3e8fabeec0cd05480a332ef65fdc288adc9654..84746cfb03ebf9c86b1d6206175201630005b9e1 100644
--- a/crates/zed_actions/src/lib.rs
+++ b/crates/zed_actions/src/lib.rs
@@ -651,3 +651,33 @@ pub mod wsl_actions {
pub create_new_window: bool,
}
}
+
+pub mod preview {
+ pub mod markdown {
+ use gpui::actions;
+
+ actions!(
+ markdown,
+ [
+ /// Opens a markdown preview for the current file.
+ OpenPreview,
+ /// Opens a markdown preview in a split pane.
+ OpenPreviewToTheSide,
+ ]
+ );
+ }
+
+ pub mod svg {
+ use gpui::actions;
+
+ actions!(
+ svg,
+ [
+ /// Opens an SVG preview for the current file.
+ OpenPreview,
+ /// Opens an SVG preview in a split pane.
+ OpenPreviewToTheSide,
+ ]
+ );
+ }
+}