pub mod code_actions;
pub mod command_line;
pub mod completion;
pub mod diagnostics;
pub mod editor_view;
pub mod file_finder;
pub mod hover;
pub mod references;
pub mod status_line;
pub mod tab_bar;
pub mod workspace_symbols;
use ratatui::Frame;
use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::{Color, Style};
use crate::editor::Editor;
use crate::editor::pane::{AreaRect, PaneRenderData};
use self::code_actions::CodeActionsPopup;
use self::command_line::CommandLine;
use self::completion::CompletionPopup;
use self::diagnostics::DiagnosticsPopup;
use self::editor_view::EditorView;
use self::file_finder::FileFinderPopup;
use self::hover::HoverPopup;
use self::references::ReferencesPopup;
use self::workspace_symbols::WorkspaceSymbolsPopup;
use self::status_line::StatusLine;
use self::tab_bar::TabBar;
fn to_rect(a: AreaRect) -> Rect {
Rect::new(a.x, a.y, a.width, a.height)
}
pub fn render(editor: &Editor, frame: &mut Frame) {
let size = frame.area();
let show_tabs = editor.buffers.len() > 1;
let chunks = if show_tabs {
Layout::vertical([
Constraint::Length(1), Constraint::Min(1), Constraint::Length(1), ])
.split(size)
} else {
Layout::vertical([
Constraint::Length(0), Constraint::Min(1), Constraint::Length(1), ])
.split(size)
};
if show_tabs {
frame.render_widget(TabBar::new(editor), chunks[0]);
}
let pane_area_rect: AreaRect = chunks[1].into();
let pane_rects = editor.pane_layout.layout(pane_area_rect);
let buf = frame.buffer_mut();
let separators = editor.pane_layout.separators(pane_area_rect);
let sep_style = Style::default().fg(Color::DarkGray);
for (x, y, height) in separators {
for dy in 0..height {
let sy = y + dy;
if x < size.width + size.x && sy < size.height + size.y {
buf[(x, sy)].set_char('│').set_style(sep_style);
}
}
}
let mut active_pane_rect = chunks[1];
for &(pane_id, arect) in &pane_rects {
let rect = to_rect(arect);
if rect.height < 2 {
continue; }
let editor_rect = Rect::new(rect.x, rect.y, rect.width, rect.height.saturating_sub(1));
let status_rect = Rect::new(rect.x, rect.y + editor_rect.height, rect.width, 1);
let is_active = pane_id == editor.active_pane_id;
if is_active {
active_pane_rect = editor_rect;
}
let render_data = build_pane_render_data(editor, pane_id, is_active);
let status_data = build_pane_render_data(editor, pane_id, is_active);
frame.render_widget(EditorView::new(render_data), editor_rect);
frame.render_widget(StatusLine::new(status_data), status_rect);
}
frame.render_widget(CompletionPopup::new(editor), active_pane_rect);
frame.render_widget(HoverPopup::new(editor), active_pane_rect);
frame.render_widget(ReferencesPopup::new(editor), active_pane_rect);
frame.render_widget(CodeActionsPopup::new(editor), active_pane_rect);
frame.render_widget(DiagnosticsPopup::new(editor), active_pane_rect);
frame.render_widget(FileFinderPopup::new(editor), active_pane_rect);
frame.render_widget(WorkspaceSymbolsPopup::new(editor), active_pane_rect);
frame.render_widget(CommandLine::new(editor), chunks[2]);
}
fn build_pane_render_data<'a>(
editor: &'a Editor,
pane_id: usize,
is_active: bool,
) -> PaneRenderData<'a> {
if is_active {
let matching_bracket = editor.matching_bracket();
PaneRenderData {
document: &editor.document,
cursor: editor.cursor,
view: editor.view,
mode: editor.mode,
diagnostics: &editor.diagnostics,
line_styles: &editor.line_styles,
styles_offset: editor.styles_offset,
search_matches: &editor.search_matches,
search_query: &editor.search_query,
visual_anchor: editor.visual_anchor,
is_active: true,
matching_bracket,
}
} else {
let pane = editor.panes.iter().find(|p| p.id == pane_id);
match pane {
Some(pane) => {
let buffer = &editor.buffers[pane.buffer_idx];
let matching_bracket = PaneRenderData::compute_matching_bracket(
&buffer.document,
pane.cursor,
);
PaneRenderData {
document: &buffer.document,
cursor: pane.cursor,
view: pane.view,
mode: Mode::Normal, diagnostics: &buffer.diagnostics,
line_styles: &pane.line_styles,
styles_offset: pane.styles_offset,
search_matches: &pane.search_matches,
search_query: &pane.search_query,
visual_anchor: None,
is_active: false,
matching_bracket,
}
}
None => {
PaneRenderData {
document: &editor.document,
cursor: editor.cursor,
view: editor.view,
mode: editor.mode,
diagnostics: &editor.diagnostics,
line_styles: &editor.line_styles,
styles_offset: editor.styles_offset,
search_matches: &editor.search_matches,
search_query: &editor.search_query,
visual_anchor: editor.visual_anchor,
is_active: false,
matching_bracket: None,
}
}
}
}
}
use crate::input::mode::Mode;