use std::ops::Range; use std::path::PathBuf; use std::sync::Arc; use gpui::{AnyElement, App, Entity, IntoElement, Window}; use language::{Anchor, Buffer, HighlightedText}; use project::Symbol; /// The editor-agnostic interface a [`Picker`](crate::Picker) uses to drive its /// preview. pub trait PreviewBackend: 'static { fn update(&self, update: Update, window: &mut Window, cx: &mut App); fn render(&self, layout: Layout, cx: &mut App) -> AnyElement; /// Called after a resize to let the preview do resizing logic like scrolling. fn adjust_to_new_size(&self, window: &mut Window, cx: &mut App); /// Empty the preview and show a placeholder message. fn clear(&self, cx: &mut App); } /// The preview window of a [`Picker`](crate::Picker). pub struct Preview { content: Arc, pub(crate) layout: Layout, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum Layout { #[default] Hidden, Below, Right, } impl Preview { pub fn new(content: Arc) -> Self { Preview { content, layout: Layout::default(), } } pub fn update(&mut self, update: Update, window: &mut Window, cx: &mut App) { self.content.update(update, window, cx); } pub fn render(&self, cx: &mut App) -> impl IntoElement { self.content.render(self.layout, cx) } pub fn adjust_to_new_size(&self, window: &mut Window, cx: &mut App) { self.content.adjust_to_new_size(window, cx); } pub(crate) fn clear(&self, cx: &mut App) { self.content.clear(cx); } } /// Identifies what a preview should show. pub enum PreviewSource { /// The buffer is identified by its absolute path; the preview opens it. /// /// Used by pickers (like the file finder) that only know the path of the /// match. Path(PathBuf), /// The buffer is provided directly. /// /// Used by pickers (like the text picker) that already hold the matched /// buffer. Buffer(Entity), /// The buffer is identified by a project symbol; the preview opens it and /// highlights the symbol's range. /// /// Used by pickers (like the project symbols picker) that only know the /// matched symbol. The highlight is derived from the symbol once its buffer /// loads, so callers don't supply a [`MatchLocation`]. Symbol(Symbol), /// No buffer to show; display this message centered in the preview instead. /// /// Used by pickers that have a selection without a previewable buffer (like /// the file finder's "create new file" entry). Built as a [`HighlightedText`] /// so callers can emphasize parts of the message (e.g. a file path). Message(HighlightedText), } pub struct MatchLocation { /// The location of the match (for highlighting) pub anchor_range: Range, /// The location of the match as an offset (for scrolling) pub range: Range, } /// An update for the [`Preview`] window of a [`Picker`](crate::Picker). pub struct Update { /// Where to source the buffer to preview. pub source: PreviewSource, /// The location to highlight and scroll to, if any. pub match_location: Option, } impl Update { /// Preview the buffer at `abs_path` without highlighting anything. pub fn from_path(abs_path: PathBuf) -> Self { Self { source: PreviewSource::Path(abs_path), match_location: None, } } /// Show `message` centered in the preview instead of a buffer. /// /// The message is a [`HighlightedText`], so parts of it (e.g. a file path) /// can be emphasized. pub fn message(message: HighlightedText) -> Self { Self { source: PreviewSource::Message(message), match_location: None, } } /// Preview `buffer`, highlighting and scrolling to `highlight`. pub fn from_buffer(buffer: Entity, highlight: MatchLocation) -> Self { Self { source: PreviewSource::Buffer(buffer), match_location: Some(highlight), } } /// Preview the buffer for `symbol`, highlighting and scrolling to its range. /// /// The buffer is opened and the highlight derived by the preview once the /// buffer loads. pub fn from_symbol(symbol: Symbol) -> Self { Self { source: PreviewSource::Symbol(symbol), match_location: None, } } }