Cargo.lock 🔗
@@ -8270,6 +8270,7 @@ dependencies = [
"assistant",
"editor",
"gpui",
+ "markdown_preview",
"repl",
"search",
"settings",
Nate Butler created
Add a "Preview Markdown" button to the quick action bar when in a
markdown editor.
While it isn't my favorite, I went with the basic eye icon to be a bit
more generic so we can extend this control to allow opening other
previews such as SVGs like @jansol mentioned.

https://github.com/user-attachments/assets/5980272c-eab9-4f69-86b6-0c593c25b525
---
Release Notes:
- Added a button to preview Markdown files in the toolbar.
`Option|Alt+Click` will open the preview to the side.
Cargo.lock | 1
assets/icons/eye.svg | 1
assets/icons/file_code.svg | 1
assets/icons/file_text.svg | 1
crates/markdown_preview/src/markdown_preview_view.rs | 4
crates/quick_action_bar/Cargo.toml | 3
crates/quick_action_bar/src/quick_action_bar.rs | 30 ++--
crates/quick_action_bar/src/toggle_markdown_preview.rs | 61 ++++++++++++
crates/ui/src/components/icon.rs | 6 +
9 files changed, 90 insertions(+), 18 deletions(-)
@@ -8270,6 +8270,7 @@ dependencies = [
"assistant",
"editor",
"gpui",
+ "markdown_preview",
"repl",
"search",
"settings",
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-eye"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/></svg>
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-code"><path d="M10 12.5 8 15l2 2.5"/><path d="m14 12.5 2 2.5-2 2.5"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"/></svg>
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>
@@ -99,7 +99,7 @@ impl MarkdownPreviewView {
.and_then(|view| pane.index_for_item(&view))
}
- fn resolve_active_item_as_markdown_editor(
+ pub fn resolve_active_item_as_markdown_editor(
workspace: &Workspace,
cx: &mut ViewContext<Workspace>,
) -> Option<View<Editor>> {
@@ -278,7 +278,7 @@ impl MarkdownPreviewView {
}
}
- fn is_markdown_file<V>(editor: &View<Editor>, cx: &mut ViewContext<V>) -> bool {
+ pub fn is_markdown_file<V>(editor: &View<Editor>, cx: &mut ViewContext<V>) -> bool {
let language = editor.read(cx).buffer().read(cx).language_at(0, cx);
language
.map(|l| l.name().as_ref() == "Markdown")
@@ -16,12 +16,13 @@ doctest = false
assistant.workspace = true
editor.workspace = true
gpui.workspace = true
+markdown_preview.workspace = true
+repl.workspace = true
search.workspace = true
settings.workspace = true
ui.workspace = true
util.workspace = true
workspace.workspace = true
-repl.workspace = true
zed_actions.workspace = true
[dev-dependencies]
@@ -21,16 +21,18 @@ use workspace::{
};
mod repl_menu;
+mod toggle_markdown_preview;
pub struct QuickActionBar {
+ _inlay_hints_enabled_subscription: Option<Subscription>,
+ active_item: Option<Box<dyn ItemHandle>>,
buffer_search_bar: View<BufferSearchBar>,
+ platform_style: PlatformStyle,
repl_menu: Option<View<ContextMenu>>,
- toggle_settings_menu: Option<View<ContextMenu>>,
+ show: bool,
toggle_selections_menu: Option<View<ContextMenu>>,
- active_item: Option<Box<dyn ItemHandle>>,
- _inlay_hints_enabled_subscription: Option<Subscription>,
+ toggle_settings_menu: Option<View<ContextMenu>>,
workspace: WeakView<Workspace>,
- show: bool,
}
impl QuickActionBar {
@@ -40,14 +42,15 @@ impl QuickActionBar {
cx: &mut ViewContext<Self>,
) -> Self {
let mut this = Self {
+ _inlay_hints_enabled_subscription: None,
+ active_item: None,
buffer_search_bar,
- toggle_settings_menu: None,
- toggle_selections_menu: None,
+ platform_style: PlatformStyle::platform(),
repl_menu: None,
- active_item: None,
- _inlay_hints_enabled_subscription: None,
- workspace: workspace.weak_handle(),
show: true,
+ toggle_selections_menu: None,
+ toggle_settings_menu: None,
+ workspace: workspace.weak_handle(),
};
this.apply_settings(cx);
cx.observe_global::<SettingsStore>(|this, cx| this.apply_settings(cx))
@@ -300,22 +303,19 @@ impl Render for QuickActionBar {
h_flex()
.id("quick action bar")
- .gap(Spacing::Large.rems(cx))
+ .gap(Spacing::XXLarge.rems(cx))
.child(
h_flex()
.gap(Spacing::Medium.rems(cx))
.children(self.render_repl_menu(cx))
+ .children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
+ .children(search_button)
.when(
AssistantSettings::get_global(cx).enabled
&& AssistantSettings::get_global(cx).button,
|bar| bar.child(assistant_button),
),
)
- .child(
- h_flex()
- .gap(Spacing::Medium.rems(cx))
- .children(search_button),
- )
.child(
h_flex()
.gap(Spacing::Medium.rems(cx))
@@ -0,0 +1,61 @@
+use gpui::{AnyElement, WeakView};
+use markdown_preview::{
+ markdown_preview_view::MarkdownPreviewView, OpenPreview, OpenPreviewToTheSide,
+};
+use ui::{prelude::*, IconButtonShape, Tooltip};
+use workspace::Workspace;
+
+use crate::QuickActionBar;
+
+impl QuickActionBar {
+ pub fn render_toggle_markdown_preview(
+ &self,
+ workspace: WeakView<Workspace>,
+ cx: &mut ViewContext<Self>,
+ ) -> Option<AnyElement> {
+ let mut active_editor_is_markdown = false;
+
+ if let Some(workspace) = self.workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ active_editor_is_markdown =
+ MarkdownPreviewView::resolve_active_item_as_markdown_editor(workspace, cx)
+ .is_some();
+ });
+ }
+
+ if !active_editor_is_markdown {
+ return None;
+ }
+
+ let tooltip_meta = match self.platform_style {
+ PlatformStyle::Mac => "Option+Click to open in a split",
+ _ => "Alt+Click to open in a split",
+ };
+
+ let button = IconButton::new("toggle-markdown-preview", IconName::Eye)
+ .shape(IconButtonShape::Square)
+ .icon_size(IconSize::Small)
+ .style(ButtonStyle::Subtle)
+ .tooltip(move |cx| {
+ Tooltip::with_meta(
+ "Preview Markdown",
+ Some(&markdown_preview::OpenPreview),
+ tooltip_meta,
+ cx,
+ )
+ })
+ .on_click(move |_, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |_, cx| {
+ if cx.modifiers().alt {
+ cx.dispatch_action(Box::new(OpenPreviewToTheSide));
+ } else {
+ cx.dispatch_action(Box::new(OpenPreview));
+ }
+ });
+ }
+ });
+
+ Some(button.into_any_element())
+ }
+}
@@ -158,6 +158,7 @@ pub enum IconName {
Exit,
ExpandVertical,
ExternalLink,
+ Eye,
File,
FileDoc,
FileGeneric,
@@ -166,6 +167,8 @@ pub enum IconName {
FileRust,
FileToml,
FileTree,
+ FileText,
+ FileCode,
Filter,
Folder,
FolderOpen,
@@ -309,6 +312,7 @@ impl IconName {
IconName::Exit => "icons/exit.svg",
IconName::ExpandVertical => "icons/expand_vertical.svg",
IconName::ExternalLink => "icons/external_link.svg",
+ IconName::Eye => "icons/eye.svg",
IconName::File => "icons/file.svg",
IconName::FileDoc => "icons/file_icons/book.svg",
IconName::FileGeneric => "icons/file_icons/file.svg",
@@ -317,6 +321,8 @@ impl IconName {
IconName::FileRust => "icons/file_icons/rust.svg",
IconName::FileToml => "icons/file_icons/toml.svg",
IconName::FileTree => "icons/project.svg",
+ IconName::FileCode => "icons/file_code.svg",
+ IconName::FileText => "icons/file_text.svg",
IconName::Filter => "icons/filter.svg",
IconName::Folder => "icons/file_icons/folder.svg",
IconName::FolderOpen => "icons/file_icons/folder_open.svg",