on master help sign in
Move theme from view to editor, support multiple views in editor.
64b5b23Blaž Hrastnik
helix-core/src/state.rs+1−1
@@ -23,7 +23,7 @@ pub struct State {
23
23
24 pub restore_cursor: bool,
24 pub restore_cursor: bool,
25
25
26− //
26+ // TODO: move these to a Document wrapper?
27 pub syntax: Option<Syntax>,
27 pub syntax: Option<Syntax>,
28 /// Pending changes since last history commit.
28 /// Pending changes since last history commit.
29 pub changes: ChangeSet,
29 pub changes: ChangeSet,
helix-term/src/application.rs+16−14
@@ -1,6 +1,6 @@
1use clap::ArgMatches as Args;
1use clap::ArgMatches as Args;
2use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State};
2use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State};
3−use helix_view::{commands, keymap, prompt::Prompt, Editor, View};
3+use helix_view::{commands, keymap, prompt::Prompt, Editor, Theme, View};
4
4
5use std::{
5use std::{
6 borrow::Cow,
6 borrow::Cow,
@@ -15,8 +15,7 @@ use anyhow::Error;
15
15
16use crossterm::{
16use crossterm::{
17 cursor,
17 cursor,
18− cursor::position,
19− event::{self, read, Event, EventStream, KeyCode, KeyEvent},
18+ event::{read, Event, EventStream, KeyCode, KeyEvent},
20 execute, queue,
19 execute, queue,
21 terminal::{self, disable_raw_mode, enable_raw_mode},
20 terminal::{self, disable_raw_mode, enable_raw_mode},
22};
21};
@@ -75,19 +74,18 @@ impl Renderer {
75 self.cache = Surface::empty(area);
74 self.cache = Surface::empty(area);
76 }
75 }
77
76
78− pub fn render_view(&mut self, view: &mut View, viewport: Rect) {
77+ pub fn render_view(&mut self, view: &mut View, viewport: Rect, theme: &Theme) {
79− self.render_buffer(view, viewport);
78+ self.render_buffer(view, viewport, theme);
80− self.render_statusline(view);
79+ self.render_statusline(view, theme);
81 }
80 }
82
81
83 // TODO: ideally not &mut View but highlights require it because of cursor cache
82 // TODO: ideally not &mut View but highlights require it because of cursor cache
84− pub fn render_buffer(&mut self, view: &mut View, viewport: Rect) {
83+ pub fn render_buffer(&mut self, view: &mut View, viewport: Rect, theme: &Theme) {
85 let area = Rect::new(0, 0, self.size.0, self.size.1);
84 let area = Rect::new(0, 0, self.size.0, self.size.1);
86 self.surface.reset(); // reset is faster than allocating new empty surface
85 self.surface.reset(); // reset is faster than allocating new empty surface
87
86
88 // clear with background color
87 // clear with background color
89− self.surface
90− .set_style(area, view.theme.get("ui.background"));
88+ self.surface.set_style(area, theme.get("ui.background"));
91
89
92 // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
90 // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
93 let source_code = view.state.doc().to_string();
91 let source_code = view.state.doc().to_string();
@@ -150,7 +148,7 @@ impl Renderer {
150 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
148 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
151
149
152 let style = match spans.first() {
150 let style = match spans.first() {
153− Some(span) => view.theme.get(view.theme.scopes()[span.0].as_str()),
151+ Some(span) => theme.get(theme.scopes()[span.0].as_str()),
154 None => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
152 None => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender
155 };
153 };
156
154
@@ -214,7 +212,7 @@ impl Renderer {
214 }
212 }
215 }
213 }
216 }
214 }
217− let style: Style = view.theme.get("ui.linenr");
215+ let style: Style = theme.get("ui.linenr");
218 let last_line = view.last_line();
216 let last_line = view.last_line();
219 for (i, line) in (view.first_line..last_line).enumerate() {
217 for (i, line) in (view.first_line..last_line).enumerate() {
220 self.surface
218 self.surface
@@ -222,7 +220,7 @@ impl Renderer {
222 }
220 }
223 }
221 }
224
222
225− pub fn render_statusline(&mut self, view: &View) {
223+ pub fn render_statusline(&mut self, view: &View, theme: &Theme) {
226 let mode = match view.state.mode() {
224 let mode = match view.state.mode() {
227 Mode::Insert => "INS",
225 Mode::Insert => "INS",
228 Mode::Normal => "NOR",
226 Mode::Normal => "NOR",
@@ -231,7 +229,7 @@ impl Renderer {
231 // statusline
229 // statusline
232 self.surface.set_style(
230 self.surface.set_style(
233 Rect::new(0, self.size.1 - 2, self.size.0, 1),
231 Rect::new(0, self.size.1 - 2, self.size.0, 1),
234− view.theme.get("ui.statusline"),
232+ theme.get("ui.statusline"),
235 );
233 );
236 self.surface
234 self.surface
237 .set_string(1, self.size.1 - 2, mode, self.text_color);
235 .set_string(1, self.size.1 - 2, mode, self.text_color);
@@ -354,8 +352,11 @@ impl Application {
354 fn render(&mut self) {
352 fn render(&mut self) {
355 let viewport = Rect::new(OFFSET, 0, self.terminal.size.0, self.terminal.size.1 - 2); // - 2 for statusline and prompt
353 let viewport = Rect::new(OFFSET, 0, self.terminal.size.0, self.terminal.size.1 - 2); // - 2 for statusline and prompt
356
354
355+ // SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow
356+ // theme. Theme is immutable mutating view won't disrupt theme_ref.
357+ let theme_ref = unsafe { &*(&self.editor.theme as *const Theme) };
357 if let Some(view) = self.editor.view_mut() {
358 if let Some(view) = self.editor.view_mut() {
358− self.terminal.render_view(view, viewport);
359+ self.terminal.render_view(view, viewport, theme_ref);
359 if let Some(prompt) = &self.prompt {
360 if let Some(prompt) = &self.prompt {
360 if prompt.should_close {
361 if prompt.should_close {
361 self.prompt = None;
362 self.prompt = None;
@@ -389,6 +390,7 @@ impl Application {
389 self.terminal.resize(width, height);
390 self.terminal.resize(width, height);
390
391
391 // TODO: simplistic ensure cursor in view for now
392 // TODO: simplistic ensure cursor in view for now
393+ // TODO: loop over views
392 if let Some(view) = self.editor.view_mut() {
394 if let Some(view) = self.editor.view_mut() {
393 view.size = self.terminal.size;
395 view.size = self.terminal.size;
394 view.ensure_cursor_in_view()
396 view.ensure_cursor_in_view()
helix-view/src/editor.rs+8−1
@@ -1,4 +1,6 @@
1+use crate::theme::Theme;
1use crate::View;
2use crate::View;
3+use helix_core::State;
2
4
3use std::path::PathBuf;
5use std::path::PathBuf;
4
6
@@ -8,20 +10,25 @@ pub struct Editor {
8 pub views: Vec<View>,
10 pub views: Vec<View>,
9 pub focus: usize,
11 pub focus: usize,
10 pub should_close: bool,
12 pub should_close: bool,
13+ pub theme: Theme, // TODO: share one instance
11}
14}
12
15
13impl Editor {
16impl Editor {
14 pub fn new() -> Self {
17 pub fn new() -> Self {
18+ let theme = Theme::default();
19+
15 Self {
20 Self {
16 views: Vec::new(),
21 views: Vec::new(),
17 focus: 0,
22 focus: 0,
18 should_close: false,
23 should_close: false,
24+ theme,
19 }
25 }
20 }
26 }
21
27
22 pub fn open(&mut self, path: PathBuf, size: (u16, u16)) -> Result<(), Error> {
28 pub fn open(&mut self, path: PathBuf, size: (u16, u16)) -> Result<(), Error> {
23 let pos = self.views.len();
29 let pos = self.views.len();
30+ let state = State::load(path, self.theme.scopes())?;
24− self.views.push(View::open(path, size)?);
31+ self.views.push(View::new(state, size)?);
25 self.focus = pos;
32 self.focus = pos;
26 Ok(())
33 Ok(())
27 }
34 }
helix-view/src/lib.rs+1
@@ -6,4 +6,5 @@ pub mod theme;
6pub mod view;
6pub mod view;
7
7
8pub use editor::Editor;
8pub use editor::Editor;
9+pub use theme::Theme;
9pub use view::View;
10pub use view::View;
helix-view/src/view.rs+7−9
@@ -1,8 +1,7 @@
1use anyhow::Error;
1use anyhow::Error;
2
2
3−use std::{borrow::Cow, path::PathBuf};
3+use std::borrow::Cow;
4
4
5−use crate::theme::Theme;
6use helix_core::{
5use helix_core::{
7 graphemes::{grapheme_width, RopeGraphemes},
6 graphemes::{grapheme_width, RopeGraphemes},
8 indent::TAB_WIDTH,
7 indent::TAB_WIDTH,
@@ -12,24 +11,23 @@ use tui::layout::Rect;
12
11
13pub const PADDING: usize = 5;
12pub const PADDING: usize = 5;
14
13
14+// TODO: view should be View { doc: Document(state, history,..) }
15+// since we can have multiple views into the same file
15pub struct View {
16pub struct View {
16 pub state: State,
17 pub state: State,
17− pub history: History,
18 pub first_line: usize,
18 pub first_line: usize,
19 pub size: (u16, u16),
19 pub size: (u16, u16),
20− pub theme: Theme, // TODO: share one instance
20+
21+ // TODO: Doc<> fields
22+ pub history: History,
21}
23}
22
24
23impl View {
25impl View {
24− pub fn open(path: PathBuf, size: (u16, u16)) -> Result<Self, Error> {
26+ pub fn new(state: State, size: (u16, u16)) -> Result<Self, Error> {
25− let theme = Theme::default();
26− let state = State::load(path, theme.scopes())?;
27−
28 let view = Self {
27 let view = Self {
29 state,
28 state,
30 first_line: 0,
29 first_line: 0,
31 size,
30 size,
32− theme,
33 history: History::default(),
31 history: History::default(),
34 };
32 };
35
33