use helix_core::{coords_at_pos, encoding}; use helix_view::{ document::{Mode, SCRATCH_BUFFER_NAME}, graphics::Rect, theme::Style, Document, Editor, View, }; use crate::ui::ProgressSpinners; use helix_view::editor::StatusLineElement as StatusLineElementID; use tui::buffer::Buffer as Surface; use tui::text::{Span, Spans}; pub struct RenderContext<'a> { pub editor: &'a Editor, pub doc: &'a Document, pub view: &'a View, pub focused: bool, pub spinners: &'a ProgressSpinners, pub parts: RenderBuffer<'a>, } impl<'a> RenderContext<'a> { pub fn new( editor: &'a Editor, doc: &'a Document, view: &'a View, focused: bool, spinners: &'a ProgressSpinners, ) -> Self { RenderContext { editor, doc, view, focused, spinners, parts: RenderBuffer::default(), } } } #[derive(Default)] pub struct RenderBuffer<'a> { pub left: Spans<'a>, pub center: Spans<'a>, pub right: Spans<'a>, } pub fn render(context: &mut RenderContext, viewport: Rect, surface: &mut Surface) { let base_style = if context.focused { context.editor.theme.get("ui.statusline") } else { context.editor.theme.get("ui.statusline.inactive") }; surface.set_style(viewport.with_height(1), base_style); let write_left = |context: &mut RenderContext, text, style| { append(&mut context.parts.left, text, &base_style, style) }; let write_center = |context: &mut RenderContext, text, style| { append(&mut context.parts.center, text, &base_style, style) }; let write_right = |context: &mut RenderContext, text, style| { append(&mut context.parts.right, text, &base_style, style) }; // Left side of the status line. let element_ids = &context.editor.config().statusline.left; element_ids .iter() .map(|element_id| get_render_function(*element_id)) .for_each(|render| render(context, write_left)); surface.set_spans( viewport.x, viewport.y, &context.parts.left, context.parts.left.width() as u16, ); // Right side of the status line. let element_ids = &context.editor.config().statusline.right; element_ids .iter() .map(|element_id| get_render_function(*element_id)) .for_each(|render| render(context, write_right)); surface.set_spans( viewport.x + viewport .width .saturating_sub(context.parts.right.width() as u16), viewport.y, &context.parts.right, context.parts.right.width() as u16, ); // Center of the status line. let element_ids = &context.editor.config().statusline.center; element_ids .iter() .map(|element_id| get_render_function(*element_id)) .for_each(|render| render(context, write_center)); // Width of the empty space between the left and center area and between the center and right area. let spacing = 1u16; let edge_width = context.parts.left.width().max(context.parts.right.width()) as u16; let center_max_width = viewport.width.saturating_sub(2 * edge_width + 2 * spacing); let center_width = center_max_width.min(context.parts.center.width() as u16); surface.set_spans( viewport.x + viewport.width / 2 - center_width / 2, viewport.y, &context.parts.center, center_width, ); } fn append(buffer: &mut Spans, text: String, base_style: &Style, style: Option