mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-25 10:56:19 +04:00
Implement a separate RenderContext
This commit is contained in:
parent
7622643117
commit
3c0e11d69e
@ -209,7 +209,6 @@ fn render(&mut self) {
|
||||
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 @@ pub fn handle_idle_timeout(&mut self) {
|
||||
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 @@ pub fn handle_terminal_events(&mut self, event: Option<Result<Event, crossterm::
|
||||
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 @@ pub fn execute(&self, cx: &mut Context) {
|
||||
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 @@ pub enum EventResult {
|
||||
|
||||
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 @@ fn should_update(&self) -> bool {
|
||||
}
|
||||
|
||||
/// 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 @@ pub fn handle_event(&mut self, event: Event, cx: &mut Context) -> bool {
|
||||
}
|
||||
|
||||
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 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
||||
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 @@ fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||
// ---
|
||||
// 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 @@ fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||
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 @@ fn handle_event(
|
||||
let mut cx = Context {
|
||||
editor: cx.editor,
|
||||
jobs: cx.jobs,
|
||||
scroll: None,
|
||||
};
|
||||
let res = completion.handle_event(event, &mut cx);
|
||||
|
||||
@ -1288,12 +1287,10 @@ fn handle_event(
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||
}
|
||||
|
||||
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 @@ fn parse(&self, theme: Option<&Theme>) -> tui::text::Text<'_> {
|
||||
}
|
||||
|
||||
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 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
||||
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 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 mul_and_cast(size: u16, factor: u8) -> u16 {
|
||||
}
|
||||
|
||||
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 @@ fn get_preview<'picker, 'editor>(
|
||||
}
|
||||
|
||||
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 @@ fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
|
||||
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 @@ pub fn auto_close(mut self, auto_close: bool) -> Self {
|
||||
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 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
||||
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 @@ pub fn exit_selection(&mut self) {
|
||||
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 @@ fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
|
||||
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 @@ fn from(contents: tui::text::Text<'static>) -> Self {
|
||||
}
|
||||
|
||||
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 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…
Reference in New Issue
Block a user