Skip to main content

ratatui_command_palette/render/
split.rs

1use ratatui::buffer::Buffer;
2use ratatui::layout::{Constraint, Direction, Layout, Rect};
3use ratatui::style::{Color, Style};
4use ratatui::widgets::{Block, BorderType, Borders, Clear, Widget};
5
6use super::PaletteRenderer;
7use super::parts::{render_footer, render_query, render_rows, render_selected_row_details};
8use crate::view::PaletteView;
9
10/// Split command palette renderer with a preview pane.
11///
12/// The split renderer renders search results on the left and selected-row
13/// details on the right. It uses only [`PaletteView`] data, so applications can
14/// replace this preview with richer domain-specific rendering later. See the
15/// [`render`](super) module for the renderer contract shared by all built-in
16/// renderers.
17#[derive(Clone, Debug)]
18pub struct SplitPreviewRenderer {
19    title: String,
20    preview_title: String,
21}
22
23impl Default for SplitPreviewRenderer {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl SplitPreviewRenderer {
30    /// Creates a split preview renderer with default titles.
31    pub fn new() -> Self {
32        Self {
33            title: "Command Palette".into(),
34            preview_title: "Preview".into(),
35        }
36    }
37
38    /// Sets the palette pane title.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// use ratatui_command_palette::render::SplitPreviewRenderer;
44    ///
45    /// let renderer = SplitPreviewRenderer::new().title("Commands");
46    ///
47    /// assert!(format!("{renderer:?}").contains("Commands"));
48    /// ```
49    pub fn title(mut self, title: impl Into<String>) -> Self {
50        self.title = title.into();
51        self
52    }
53
54    /// Sets the preview pane title.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use ratatui_command_palette::render::SplitPreviewRenderer;
60    ///
61    /// let renderer = SplitPreviewRenderer::new().preview_title("Details");
62    ///
63    /// assert!(format!("{renderer:?}").contains("Details"));
64    /// ```
65    pub fn preview_title(mut self, title: impl Into<String>) -> Self {
66        self.preview_title = title.into();
67        self
68    }
69}
70
71impl PaletteRenderer for SplitPreviewRenderer {
72    fn render(&self, area: Rect, buf: &mut Buffer, view: &PaletteView) {
73        Clear.render(area, buf);
74
75        let columns = Layout::default()
76            .direction(Direction::Horizontal)
77            .constraints([Constraint::Percentage(58), Constraint::Percentage(42)])
78            .split(area);
79
80        render_palette_panel(columns[0], buf, view, &self.title);
81        render_preview_panel(columns[1], buf, view, &self.preview_title);
82    }
83}
84
85fn render_palette_panel(area: Rect, buf: &mut Buffer, view: &PaletteView, title: &str) {
86    let block = Block::new()
87        .title(title)
88        .borders(Borders::ALL)
89        .border_type(BorderType::Rounded)
90        .border_style(Style::new().fg(Color::Cyan));
91    let inner = block.inner(area);
92    block.render(area, buf);
93
94    if inner.height == 0 || inner.width == 0 {
95        return;
96    }
97
98    let sections = Layout::default()
99        .direction(Direction::Vertical)
100        .constraints([
101            Constraint::Length(1),
102            Constraint::Min(0),
103            Constraint::Length(1),
104        ])
105        .split(inner);
106
107    render_query(sections[0], buf, view);
108    render_rows(sections[1], buf, view);
109    render_footer(sections[2], buf, view);
110}
111
112fn render_preview_panel(area: Rect, buf: &mut Buffer, view: &PaletteView, title: &str) {
113    let block = Block::new()
114        .title(title)
115        .borders(Borders::ALL)
116        .border_type(BorderType::Rounded)
117        .border_style(Style::new().fg(Color::DarkGray));
118    let inner = block.inner(area);
119    block.render(area, buf);
120
121    if inner.height == 0 || inner.width == 0 {
122        return;
123    }
124
125    render_selected_row_details(inner, buf, view);
126}