Add SVG preview (#32694)

Closes #10454

Implements SVG file preview capability similar to the existing markdown
preview.
- Adds `svg_preview` crate with preview view and live reloading upon
file save.
- Integrates SVG preview button in quick action bar.
- File preview shortcuts (`ctrl/cmd+k v` and `ctrl/cmd+shift+v`) are
extension-aware.

Release Notes:

- Added SVG file preview, accessible via the quick action bar button or
keyboard shortcuts (`ctrl/cmd+k v` and `ctrl/cmd+shift+v`) when editing
SVG files.
This commit is contained in:
Ron Harel 2025-06-27 12:08:05 +03:00 committed by GitHub
parent 6c46e1129d
commit e6bc1308af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 528 additions and 93 deletions

View file

@ -17,10 +17,9 @@ use ui::prelude::*;
use workspace::item::{Item, ItemHandle};
use workspace::{Pane, Workspace};
use crate::OpenPreviewToTheSide;
use crate::markdown_elements::ParsedMarkdownElement;
use crate::{
OpenFollowingPreview, OpenPreview,
OpenFollowingPreview, OpenPreview, OpenPreviewToTheSide,
markdown_elements::ParsedMarkdown,
markdown_parser::parse_markdown,
markdown_renderer::{RenderContext, render_markdown_block},
@ -36,7 +35,6 @@ pub struct MarkdownPreviewView {
contents: Option<ParsedMarkdown>,
selected_block: usize,
list_state: ListState,
tab_content_text: Option<SharedString>,
language_registry: Arc<LanguageRegistry>,
parsing_markdown_task: Option<Task<Result<()>>>,
mode: MarkdownPreviewMode,
@ -173,7 +171,6 @@ impl MarkdownPreviewView {
editor,
workspace_handle,
language_registry,
None,
window,
cx,
)
@ -192,7 +189,6 @@ impl MarkdownPreviewView {
editor,
workspace_handle,
language_registry,
None,
window,
cx,
)
@ -203,7 +199,6 @@ impl MarkdownPreviewView {
active_editor: Entity<Editor>,
workspace: WeakEntity<Workspace>,
language_registry: Arc<LanguageRegistry>,
tab_content_text: Option<SharedString>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> Entity<Self> {
@ -324,7 +319,6 @@ impl MarkdownPreviewView {
workspace: workspace.clone(),
contents: None,
list_state,
tab_content_text,
language_registry,
parsing_markdown_task: None,
image_cache: RetainAllImageCache::new(cx),
@ -405,12 +399,6 @@ impl MarkdownPreviewView {
},
);
let tab_content = editor.read(cx).tab_content_text(0, cx);
if self.tab_content_text.is_none() {
self.tab_content_text = Some(format!("Preview {}", tab_content).into());
}
self.active_editor = Some(EditorState {
editor,
_subscription: subscription,
@ -547,21 +535,28 @@ impl Focusable for MarkdownPreviewView {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PreviewEvent {}
impl EventEmitter<PreviewEvent> for MarkdownPreviewView {}
impl EventEmitter<()> for MarkdownPreviewView {}
impl Item for MarkdownPreviewView {
type Event = PreviewEvent;
type Event = ();
fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(Icon::new(IconName::FileDoc))
}
fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
self.tab_content_text
.clone()
fn tab_content_text(&self, _detail: usize, cx: &App) -> SharedString {
self.active_editor
.as_ref()
.and_then(|editor_state| {
let buffer = editor_state.editor.read(cx).buffer().read(cx);
let buffer = buffer.as_singleton()?;
let file = buffer.read(cx).file()?;
let local_file = file.as_local()?;
local_file
.abs_path(cx)
.file_name()
.map(|name| format!("Preview {}", name.to_string_lossy()).into())
})
.unwrap_or_else(|| SharedString::from("Markdown Preview"))
}