Implement a separate RenderContext

gui
Blaž Hrastnik 2 years ago
parent 7622643117
commit 3c0e11d69e
No known key found for this signature in database
GPG Key ID: 1238B9C4AD889640

@ -209,7 +209,6 @@ impl Application {
let mut cx = crate::compositor::Context {
editor: &mut self.editor,
jobs: &mut self.jobs,
scroll: None,
};
self.compositor.render(&mut cx);
@ -358,7 +357,6 @@ impl Application {
let mut cx = crate::compositor::Context {
editor: &mut self.editor,
jobs: &mut self.jobs,
scroll: None,
};
if let EventResult::Consumed(_) = editor_view.handle_idle_timeout(&mut cx) {
self.render();
@ -369,7 +367,6 @@ impl Application {
let mut cx = crate::compositor::Context {
editor: &mut self.editor,
jobs: &mut self.jobs,
scroll: None,
};
// Handle key events
let should_redraw = match event {

@ -164,7 +164,6 @@ impl MappableCommand {
let mut cx = compositor::Context {
editor: cx.editor,
jobs: cx.jobs,
scroll: None,
};
if let Err(e) = (command.fun)(&mut cx, &args[..], PromptEvent::Validate) {
cx.editor.set_error(format!("{}", e));

@ -21,10 +21,14 @@ use crate::job::Jobs;
pub struct Context<'a> {
pub editor: &'a mut Editor,
pub scroll: Option<usize>,
pub jobs: &'a mut Jobs,
}
pub struct RenderContext<'a> {
pub editor: &'a Editor,
pub scroll: Option<usize>,
}
pub trait Component: Any + AnyComponent {
/// Process input events, return true if handled.
fn handle_event(&mut self, _event: Event, _ctx: &mut Context) -> EventResult {
@ -38,7 +42,7 @@ pub trait Component: Any + AnyComponent {
}
/// Render the component onto the provided surface.
fn render(&mut self, area: Rect, frame: &mut Surface, ctx: &mut Context);
fn render(&mut self, area: Rect, frame: &mut Surface, ctx: &mut RenderContext);
/// Get cursor position and cursor kind.
fn cursor(&self, _area: Rect, _ctx: &Editor) -> (Option<Position>, CursorKind) {
@ -169,18 +173,25 @@ impl Compositor {
}
pub fn render(&mut self, cx: &mut Context) {
self.terminal
let area = self
.terminal
.autoresize()
.expect("Unable to determine terminal size");
// TODO: need to recalculate view tree if necessary
// if the terminal size suddenly changed, we need to trigger a resize
cx.editor.resize(area.clip_bottom(1)); // -1 from bottom for commandline
let surface = self.terminal.current_buffer_mut();
let area = *surface.area();
// let area = *surface.area();
let mut cx = RenderContext {
editor: cx.editor,
scroll: None,
};
for layer in &mut self.layers {
layer.render(area, surface, cx);
layer.render(area, surface, &mut cx);
}
let (pos, kind) = self.cursor(area, cx.editor);

@ -1,4 +1,4 @@
use crate::compositor::{Component, Context, EventResult};
use crate::compositor::{Component, Context, EventResult, RenderContext};
use crossterm::event::{Event, KeyCode, KeyEvent};
use helix_view::editor::CompleteAction;
use tui::buffer::Buffer as Surface;
@ -301,7 +301,7 @@ impl Component for Completion {
self.popup.required_size(viewport)
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
self.popup.render(area, surface, cx);
// if we have a selection, render a markdown popup on top/below with info
@ -311,7 +311,7 @@ impl Component for Completion {
// ---
// option.documentation
let (view, doc) = current!(cx.editor);
let (view, doc) = current_ref!(cx.editor);
let language = doc
.language()
.and_then(|scope| scope.strip_prefix("source."))
@ -369,7 +369,7 @@ impl Component for Completion {
None => return,
};
let (popup_x, popup_y) = self.popup.get_rel_position(area, cx);
let (popup_x, popup_y) = self.popup.get_rel_position(area, cx.editor);
let (popup_width, _popup_height) = self.popup.get_size();
let mut width = area
.width

@ -1,6 +1,6 @@
use crate::{
commands,
compositor::{Component, Context, EventResult},
compositor::{Component, Context, EventResult, RenderContext},
key,
keymap::{KeymapResult, Keymaps},
ui::{Completion, ProgressSpinners},
@ -1201,7 +1201,6 @@ impl Component for EditorView {
let mut cx = Context {
editor: cx.editor,
jobs: cx.jobs,
scroll: None,
};
let res = completion.handle_event(event, &mut cx);
@ -1288,12 +1287,10 @@ impl Component for EditorView {
}
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
// clear with background color
surface.set_style(area, cx.editor.theme.get("ui.background"));
let config = cx.editor.config();
// if the terminal size suddenly changed, we need to trigger a resize
cx.editor.resize(area.clip_bottom(1)); // -1 from bottom for commandline
for (view, is_focused) in cx.editor.tree.views() {
let doc = cx.editor.document(view.doc).unwrap();
@ -1301,9 +1298,10 @@ impl Component for EditorView {
}
if config.auto_info {
if let Some(mut info) = cx.editor.autoinfo.take() {
// TODO: drop &mut self on render
if let Some(mut info) = cx.editor.autoinfo.clone() {
info.render(area, surface, cx);
cx.editor.autoinfo = Some(info)
// cx.editor.autoinfo = Some(info)
}
}

@ -1,11 +1,11 @@
use crate::compositor::{Component, Context};
use crate::compositor::{Component, RenderContext};
use helix_view::graphics::{Margin, Rect};
use helix_view::info::Info;
use tui::buffer::Buffer as Surface;
use tui::widgets::{Block, Borders, Paragraph, Widget};
impl Component for Info {
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
let text_style = cx.editor.theme.get("ui.text.info");
let popup_style = cx.editor.theme.get("ui.popup.info");

@ -1,4 +1,4 @@
use crate::compositor::{Component, Context};
use crate::compositor::{Component, RenderContext};
use tui::{
buffer::Buffer as Surface,
text::{Span, Spans, Text},
@ -259,7 +259,7 @@ impl Markdown {
}
impl Component for Markdown {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
use tui::widgets::{Paragraph, Widget, Wrap};
let text = self.parse(Some(&cx.editor.theme));

@ -1,5 +1,5 @@
use crate::{
compositor::{Callback, Component, Compositor, Context, EventResult},
compositor::{Callback, Component, Compositor, Context, EventResult, RenderContext},
ctrl, key, shift,
};
use crossterm::event::Event;
@ -265,7 +265,7 @@ impl<T: Item + 'static> Component for Menu<T> {
Some(self.size)
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
let theme = &cx.editor.theme;
let style = theme
.try_get("ui.menu")

@ -6,7 +6,7 @@ use helix_view::{
};
use tui::buffer::Buffer;
use crate::compositor::{Component, Context, EventResult};
use crate::compositor::{Component, Context, EventResult, RenderContext};
/// Contains a component placed in the center of the parent component
pub struct Overlay<T> {
@ -44,7 +44,7 @@ fn clip_rect_relative(rect: Rect, percent_horizontal: u8, percent_vertical: u8)
}
impl<T: Component + 'static> Component for Overlay<T> {
fn render(&mut self, area: Rect, frame: &mut Buffer, ctx: &mut Context) {
fn render(&mut self, area: Rect, frame: &mut Buffer, ctx: &mut RenderContext<'_>) {
let dimensions = (self.calc_child_size)(area);
self.content.render(dimensions, frame, ctx)
}

@ -1,5 +1,5 @@
use crate::{
compositor::{Component, Compositor, Context, EventResult},
compositor::{Component, Compositor, Context, EventResult, RenderContext},
ctrl, key, shift,
ui::{self, EditorView},
};
@ -164,7 +164,7 @@ impl<T> FilePicker<T> {
}
impl<T: 'static> Component for FilePicker<T> {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
// +---------+ +---------+
// |prompt | |preview |
// +---------+ | |
@ -552,7 +552,7 @@ impl<T: 'static> Component for Picker<T> {
EventResult::Consumed(None)
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
let text_style = cx.editor.theme.get("ui.text");
let selected = cx.editor.theme.get("ui.text.focus");
let highlighted = cx.editor.theme.get("special").add_modifier(Modifier::BOLD);

@ -1,12 +1,15 @@
use crate::{
compositor::{Callback, Component, Context, EventResult},
compositor::{Callback, Component, Context, EventResult, RenderContext},
ctrl, key,
};
use crossterm::event::Event;
use tui::buffer::Buffer as Surface;
use helix_core::Position;
use helix_view::graphics::{Margin, Rect};
use helix_view::{
graphics::{Margin, Rect},
Editor,
};
// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
// a width/height hint. maybe Popup(Box<Component>)
@ -53,10 +56,10 @@ impl<T: Component> Popup<T> {
self
}
pub fn get_rel_position(&mut self, viewport: Rect, cx: &Context) -> (u16, u16) {
pub fn get_rel_position(&mut self, viewport: Rect, editor: &Editor) -> (u16, u16) {
let position = self
.position
.get_or_insert_with(|| cx.editor.cursor().0.unwrap_or_default());
.get_or_insert_with(|| editor.cursor().0.unwrap_or_default());
let (width, height) = self.size;
@ -176,13 +179,13 @@ impl<T: Component> Component for Popup<T> {
Some(self.size)
}
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
// trigger required_size so we recalculate if the child changed
self.required_size((viewport.width, viewport.height));
cx.scroll = Some(self.scroll);
let (rel_x, rel_y) = self.get_rel_position(viewport, cx);
let (rel_x, rel_y) = self.get_rel_position(viewport, cx.editor);
// clip to viewport
let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1));

@ -1,4 +1,4 @@
use crate::compositor::{Component, Compositor, Context, EventResult};
use crate::compositor::{Component, Compositor, Context, EventResult, RenderContext};
use crate::{alt, ctrl, key, shift, ui};
use crossterm::event::Event;
use helix_view::input::KeyEvent;
@ -327,7 +327,7 @@ impl Prompt {
const BASE_WIDTH: u16 = 30;
impl Prompt {
pub fn render_prompt(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
pub fn render_prompt(&self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
let theme = &cx.editor.theme;
let prompt_color = theme.get("ui.text");
let completion_color = theme.get("ui.statusline");
@ -547,7 +547,7 @@ impl Component for Prompt {
EventResult::Consumed(None)
}
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut RenderContext<'_>) {
self.render_prompt(area, surface, cx)
}

@ -1,4 +1,4 @@
use crate::compositor::{Component, Context};
use crate::compositor::{Component, RenderContext};
use tui::buffer::Buffer as Surface;
use helix_view::graphics::Rect;
@ -30,7 +30,7 @@ impl From<tui::text::Text<'static>> for Text {
}
impl Component for Text {
fn render(&mut self, area: Rect, surface: &mut Surface, _cx: &mut Context) {
fn render(&mut self, area: Rect, surface: &mut Surface, _cx: &mut RenderContext<'_>) {
use tui::widgets::{Paragraph, Widget, Wrap};
let par = Paragraph::new(self.contents.clone()).wrap(Wrap { trim: false });

@ -2,7 +2,7 @@ use crate::input::KeyEvent;
use helix_core::{register::Registers, unicode::width::UnicodeWidthStr};
use std::{collections::BTreeSet, fmt::Write};
#[derive(Debug)]
#[derive(Debug, Clone)]
/// Info box used in editor. Rendering logic will be in other crate.
pub struct Info {
/// Title shown at top.

Loading…
Cancel
Save