Move theme from view to editor, support multiple views in editor.

imgbot
Blaž Hrastnik 4 years ago
parent b2b3083a62
commit 64b5b23315

@ -23,7 +23,7 @@ pub struct State {
pub restore_cursor: bool, pub restore_cursor: bool,
// // TODO: move these to a Document wrapper?
pub syntax: Option<Syntax>, pub syntax: Option<Syntax>,
/// Pending changes since last history commit. /// Pending changes since last history commit.
pub changes: ChangeSet, pub changes: ChangeSet,

@ -1,6 +1,6 @@
use clap::ArgMatches as Args; use clap::ArgMatches as Args;
use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State}; use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State};
use helix_view::{commands, keymap, prompt::Prompt, Editor, View}; use helix_view::{commands, keymap, prompt::Prompt, Editor, Theme, View};
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -15,8 +15,7 @@ use anyhow::Error;
use crossterm::{ use crossterm::{
cursor, cursor,
cursor::position, event::{read, Event, EventStream, KeyCode, KeyEvent},
event::{self, read, Event, EventStream, KeyCode, KeyEvent},
execute, queue, execute, queue,
terminal::{self, disable_raw_mode, enable_raw_mode}, terminal::{self, disable_raw_mode, enable_raw_mode},
}; };
@ -75,19 +74,18 @@ impl Renderer {
self.cache = Surface::empty(area); self.cache = Surface::empty(area);
} }
pub fn render_view(&mut self, view: &mut View, viewport: Rect) { pub fn render_view(&mut self, view: &mut View, viewport: Rect, theme: &Theme) {
self.render_buffer(view, viewport); self.render_buffer(view, viewport, theme);
self.render_statusline(view); self.render_statusline(view, theme);
} }
// TODO: ideally not &mut View but highlights require it because of cursor cache // TODO: ideally not &mut View but highlights require it because of cursor cache
pub fn render_buffer(&mut self, view: &mut View, viewport: Rect) { pub fn render_buffer(&mut self, view: &mut View, viewport: Rect, theme: &Theme) {
let area = Rect::new(0, 0, self.size.0, self.size.1); let area = Rect::new(0, 0, self.size.0, self.size.1);
self.surface.reset(); // reset is faster than allocating new empty surface self.surface.reset(); // reset is faster than allocating new empty surface
// clear with background color // clear with background color
self.surface self.surface.set_style(area, theme.get("ui.background"));
.set_style(area, view.theme.get("ui.background"));
// TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|) // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
let source_code = view.state.doc().to_string(); let source_code = view.state.doc().to_string();
@ -150,7 +148,7 @@ impl Renderer {
use helix_core::graphemes::{grapheme_width, RopeGraphemes}; use helix_core::graphemes::{grapheme_width, RopeGraphemes};
let style = match spans.first() { let style = match spans.first() {
Some(span) => view.theme.get(view.theme.scopes()[span.0].as_str()), Some(span) => theme.get(theme.scopes()[span.0].as_str()),
None => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender None => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
}; };
@ -214,7 +212,7 @@ impl Renderer {
} }
} }
} }
let style: Style = view.theme.get("ui.linenr"); let style: Style = theme.get("ui.linenr");
let last_line = view.last_line(); let last_line = view.last_line();
for (i, line) in (view.first_line..last_line).enumerate() { for (i, line) in (view.first_line..last_line).enumerate() {
self.surface self.surface
@ -222,7 +220,7 @@ impl Renderer {
} }
} }
pub fn render_statusline(&mut self, view: &View) { pub fn render_statusline(&mut self, view: &View, theme: &Theme) {
let mode = match view.state.mode() { let mode = match view.state.mode() {
Mode::Insert => "INS", Mode::Insert => "INS",
Mode::Normal => "NOR", Mode::Normal => "NOR",
@ -231,7 +229,7 @@ impl Renderer {
// statusline // statusline
self.surface.set_style( self.surface.set_style(
Rect::new(0, self.size.1 - 2, self.size.0, 1), Rect::new(0, self.size.1 - 2, self.size.0, 1),
view.theme.get("ui.statusline"), theme.get("ui.statusline"),
); );
self.surface self.surface
.set_string(1, self.size.1 - 2, mode, self.text_color); .set_string(1, self.size.1 - 2, mode, self.text_color);
@ -354,8 +352,11 @@ impl Application {
fn render(&mut self) { fn render(&mut self) {
let viewport = Rect::new(OFFSET, 0, self.terminal.size.0, self.terminal.size.1 - 2); // - 2 for statusline and prompt let viewport = Rect::new(OFFSET, 0, self.terminal.size.0, self.terminal.size.1 - 2); // - 2 for statusline and prompt
// SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow
// theme. Theme is immutable mutating view won't disrupt theme_ref.
let theme_ref = unsafe { &*(&self.editor.theme as *const Theme) };
if let Some(view) = self.editor.view_mut() { if let Some(view) = self.editor.view_mut() {
self.terminal.render_view(view, viewport); self.terminal.render_view(view, viewport, theme_ref);
if let Some(prompt) = &self.prompt { if let Some(prompt) = &self.prompt {
if prompt.should_close { if prompt.should_close {
self.prompt = None; self.prompt = None;
@ -389,6 +390,7 @@ impl Application {
self.terminal.resize(width, height); self.terminal.resize(width, height);
// TODO: simplistic ensure cursor in view for now // TODO: simplistic ensure cursor in view for now
// TODO: loop over views
if let Some(view) = self.editor.view_mut() { if let Some(view) = self.editor.view_mut() {
view.size = self.terminal.size; view.size = self.terminal.size;
view.ensure_cursor_in_view() view.ensure_cursor_in_view()

@ -1,4 +1,6 @@
use crate::theme::Theme;
use crate::View; use crate::View;
use helix_core::State;
use std::path::PathBuf; use std::path::PathBuf;
@ -8,20 +10,25 @@ pub struct Editor {
pub views: Vec<View>, pub views: Vec<View>,
pub focus: usize, pub focus: usize,
pub should_close: bool, pub should_close: bool,
pub theme: Theme, // TODO: share one instance
} }
impl Editor { impl Editor {
pub fn new() -> Self { pub fn new() -> Self {
let theme = Theme::default();
Self { Self {
views: Vec::new(), views: Vec::new(),
focus: 0, focus: 0,
should_close: false, should_close: false,
theme,
} }
} }
pub fn open(&mut self, path: PathBuf, size: (u16, u16)) -> Result<(), Error> { pub fn open(&mut self, path: PathBuf, size: (u16, u16)) -> Result<(), Error> {
let pos = self.views.len(); let pos = self.views.len();
self.views.push(View::open(path, size)?); let state = State::load(path, self.theme.scopes())?;
self.views.push(View::new(state, size)?);
self.focus = pos; self.focus = pos;
Ok(()) Ok(())
} }

@ -6,4 +6,5 @@ pub mod theme;
pub mod view; pub mod view;
pub use editor::Editor; pub use editor::Editor;
pub use theme::Theme;
pub use view::View; pub use view::View;

@ -1,8 +1,7 @@
use anyhow::Error; use anyhow::Error;
use std::{borrow::Cow, path::PathBuf}; use std::borrow::Cow;
use crate::theme::Theme;
use helix_core::{ use helix_core::{
graphemes::{grapheme_width, RopeGraphemes}, graphemes::{grapheme_width, RopeGraphemes},
indent::TAB_WIDTH, indent::TAB_WIDTH,
@ -12,24 +11,23 @@ use tui::layout::Rect;
pub const PADDING: usize = 5; pub const PADDING: usize = 5;
// TODO: view should be View { doc: Document(state, history,..) }
// since we can have multiple views into the same file
pub struct View { pub struct View {
pub state: State, pub state: State,
pub history: History,
pub first_line: usize, pub first_line: usize,
pub size: (u16, u16), pub size: (u16, u16),
pub theme: Theme, // TODO: share one instance
// TODO: Doc<> fields
pub history: History,
} }
impl View { impl View {
pub fn open(path: PathBuf, size: (u16, u16)) -> Result<Self, Error> { pub fn new(state: State, size: (u16, u16)) -> Result<Self, Error> {
let theme = Theme::default();
let state = State::load(path, theme.scopes())?;
let view = Self { let view = Self {
state, state,
first_line: 0, first_line: 0,
size, size,
theme,
history: History::default(), history: History::default(),
}; };

Loading…
Cancel
Save