@@ -1,4 +1,4 @@
1−use crate::{keymap, theme::Theme, Args};
1+use crate::{commands, keymap, theme::Theme, Args};
2use helix_core::{
2use helix_core::{
3 state::coords_at_pos,
3 state::coords_at_pos,
4 state::Mode,
4 state::Mode,
@@ -31,10 +31,15 @@ type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
32static EX: smol::Executor = smol::Executor::new();
32static EX: smol::Executor = smol::Executor::new();
37+ pub size: (u16, u16),
34pub struct Editor {
40pub struct Editor {
35 terminal: Terminal,
41 terminal: Terminal,
36− state: Option<State>,
42+ view: Option<View>,
38 size: (u16, u16),
43 size: (u16, u16),
39 surface: Surface,
44 surface: Surface,
40 cache: Surface,
45 cache: Surface,
@@ -52,8 +57,7 @@ impl Editor {
53 let mut editor = Editor {
58 let mut editor = Editor {
55− state: None,
60+ view: None,
58 surface: Surface::empty(area),
62 surface: Surface::empty(area),
59 cache: Surface::empty(area),
63 cache: Surface::empty(area),
@@ -75,7 +79,14 @@ impl Editor {
77 .configure(self.theme.scopes());
81 .configure(self.theme.scopes());
78− self.state = Some(state);
82+
89+ self.view = Some(view);
@@ -83,8 +94,8 @@ impl Editor {
83 use tui::backend::Backend;
94 use tui::backend::Backend;
84 use tui::style::Color;
95 use tui::style::Color;
85 // TODO: ideally not mut but highlights require it because of cursor cache
96 // TODO: ideally not mut but highlights require it because of cursor cache
86− match &mut self.state {
97+ match &mut self.view {
87− Some(state) => {
98+ Some(view) => {
88 let area = Rect::new(0, 0, self.size.0, self.size.1);
99 let area = Rect::new(0, 0, self.size.0, self.size.1);
89 let mut stdout = stdout();
100 let mut stdout = stdout();
90 self.surface.reset(); // reset is faster than allocating new empty surface
101 self.surface.reset(); // reset is faster than allocating new empty surface
@@ -97,18 +108,18 @@ impl Editor {
97 let viewport = Rect::new(offset, 0, self.size.0, self.size.1 - 1); // - 1 for statusline
108 let viewport = Rect::new(offset, 0, self.size.0, self.size.1 - 1); // - 1 for statusline
99 // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
110 // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|)
100− let source_code = state.doc().to_string();
111+ let source_code = view.state.doc().to_string();
102 let last_line = std::cmp::min(
113 let last_line = std::cmp::min(
103− (self.first_line + viewport.height - 1) as usize,
114+ (view.first_line + viewport.height - 1) as usize,
104− state.doc().len_lines() - 1,
115+ view.state.doc().len_lines() - 1,
107 let range = {
118 let range = {
108 // calculate viewport byte ranges
119 // calculate viewport byte ranges
109− let start = state.doc().line_to_byte(self.first_line.into());
120+ let start = view.state.doc().line_to_byte(view.first_line.into());
110− let end = state.doc().line_to_byte(last_line)
121+ let end = view.state.doc().line_to_byte(last_line)
111− + state.doc().line(last_line).len_bytes();
122+ + view.state.doc().line(last_line).len_bytes();
113 start..end
124 start..end
@@ -117,7 +128,8 @@ impl Editor {
118 // TODO: cache highlight results
129 // TODO: cache highlight results
119 // TODO: only recalculate when state.doc is actually modified
130 // TODO: only recalculate when state.doc is actually modified
120− let highlights: Vec<_> = state
131+ let highlights: Vec<_> = view
122 .as_mut()
134 .as_mut()
123 .unwrap()
135 .unwrap()
@@ -141,10 +153,10 @@ impl Editor {
141 HighlightEvent::Source { start, end } => {
153 HighlightEvent::Source { start, end } => {
142 // TODO: filter out spans out of viewport for now..
154 // TODO: filter out spans out of viewport for now..
144− let start = state.doc().byte_to_char(start);
156+ let start = view.state.doc().byte_to_char(start);
145− let end = state.doc().byte_to_char(end);
157+ let end = view.state.doc().byte_to_char(end);
147− let text = state.doc().slice(start..end);
159+ let text = view.state.doc().slice(start..end);
149 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
161 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
@@ -191,7 +203,7 @@ impl Editor {
192 let mut line = 0;
204 let mut line = 0;
193 let style = self.theme.get("ui.linenr");
205 let style = self.theme.get("ui.linenr");
194− for i in self.first_line..(last_line as u16) {
206+ for i in view.first_line..(last_line as u16) {
195 self.surface
207 self.surface
196 .set_stringn(0, line, format!("{:>5}", i + 1), 5, style); // lavender
208 .set_stringn(0, line, format!("{:>5}", i + 1), 5, style); // lavender
197 line += 1;
209 line += 1;
@@ -223,7 +235,7 @@ impl Editor {
225 // statusline
237 // statusline
226− let mode = match state.mode() {
238+ let mode = match view.state.mode() {
227 Mode::Insert => "INS",
239 Mode::Insert => "INS",
228 Mode::Normal => "NOR",
240 Mode::Normal => "NOR",
@@ -235,7 +247,7 @@ impl Editor {
235 let text_color = Style::default().fg(Color::Rgb(219, 191, 239)); // lilac
247 let text_color = Style::default().fg(Color::Rgb(219, 191, 239)); // lilac
236 self.surface
248 self.surface
237 .set_string(1, self.size.1 - 1, mode, text_color);
249 .set_string(1, self.size.1 - 1, mode, text_color);
238− if let Some(path) = state.path() {
250+ if let Some(path) = view.state.path() {
239 self.surface
251 self.surface
240 .set_string(6, self.size.1 - 1, path.to_string_lossy(), text_color);
252 .set_string(6, self.size.1 - 1, path.to_string_lossy(), text_color);
@@ -247,19 +259,19 @@ impl Editor {
247 std::mem::swap(&mut self.surface, &mut self.cache);
259 std::mem::swap(&mut self.surface, &mut self.cache);
249 // set cursor shape
261 // set cursor shape
250− match state.mode() {
262+ match view.state.mode() {
251 Mode::Insert => write!(stdout, "\x1B[6 q"),
263 Mode::Insert => write!(stdout, "\x1B[6 q"),
252 Mode::Normal => write!(stdout, "\x1B[2 q"),
264 Mode::Normal => write!(stdout, "\x1B[2 q"),
255 // render the cursor
267 // render the cursor
256− let pos = state.selection().cursor();
268+ let pos = view.state.selection().cursor();
257− let coords = coords_at_pos(&state.doc().slice(..), pos);
269+ let coords = coords_at_pos(&view.state.doc().slice(..), pos);
258 execute!(
270 execute!(
260 cursor::MoveTo(
272 cursor::MoveTo(
261 coords.col as u16 + viewport.x,
273 coords.col as u16 + viewport.x,
262− coords.row as u16 - self.first_line + viewport.y,
274+ coords.row as u16 - view.first_line + viewport.y,
@@ -295,29 +307,29 @@ impl Editor {
297 Some(Ok(Event::Key(event))) => {
309 Some(Ok(Event::Key(event))) => {
298− if let Some(state) = &mut self.state {
310+ if let Some(view) = &mut self.view {
299− match state.mode() {
311+ match view.state.mode() {
300 Mode::Insert => {
312 Mode::Insert => {
301 match event {
313 match event {
302 KeyEvent {
314 KeyEvent {
303 code: KeyCode::Esc, ..
315 code: KeyCode::Esc, ..
304− } => helix_core::commands::normal_mode(state, 1),
316+ } => commands::normal_mode(view, 1),
305 KeyEvent {
317 KeyEvent {
306 code: KeyCode::Backspace,
318 code: KeyCode::Backspace,
308− } => helix_core::commands::delete_char_backward(state, 1),
320+ } => commands::delete_char_backward(view, 1),
309 KeyEvent {
321 KeyEvent {
310 code: KeyCode::Delete,
322 code: KeyCode::Delete,
312− } => helix_core::commands::delete_char_forward(state, 1),
324+ } => commands::delete_char_forward(view, 1),
313 KeyEvent {
325 KeyEvent {
314 code: KeyCode::Char(c),
326 code: KeyCode::Char(c),
316− } => helix_core::commands::insert_char(state, c),
328+ } => commands::insert_char(view, c),
317 KeyEvent {
329 KeyEvent {
318 code: KeyCode::Enter,
330 code: KeyCode::Enter,
320− } => helix_core::commands::insert_char(state, '\n'),
332+ } => commands::insert_char(view, '\n'),
321 _ => (), // skip
333 _ => (), // skip
323 // TODO: simplistic ensure cursor in view for now
335 // TODO: simplistic ensure cursor in view for now
@@ -329,7 +341,7 @@ impl Editor {
329 // TODO: handle modes and sequences (`gg`)
341 // TODO: handle modes and sequences (`gg`)
330 if let Some(command) = keymap.get(&event) {
342 if let Some(command) = keymap.get(&event) {
331 // TODO: handle count other than 1
343 // TODO: handle count other than 1
332− command(state, 1);
344+ command(view, 1);
334 // TODO: simplistic ensure cursor in view for now
346 // TODO: simplistic ensure cursor in view for now
335 self.ensure_cursor_in_view();
347 self.ensure_cursor_in_view();
@@ -350,10 +362,10 @@ impl Editor {
352 fn ensure_cursor_in_view(&mut self) {
364 fn ensure_cursor_in_view(&mut self) {
353− if let Some(state) = &mut self.state {
365+ if let Some(view) = &mut self.view {
354− let cursor = state.selection().cursor();
366+ let cursor = view.state.selection().cursor();
355− let line = state.doc().char_to_line(cursor) as u16;
367+ let line = view.state.doc().char_to_line(cursor) as u16;
356− let document_end = self.first_line + self.size.1.saturating_sub(1) - 1;
368+ let document_end = view.first_line + self.size.1.saturating_sub(1) - 1;
358 let padding = 5u16;
370 let padding = 5u16;
@@ -361,10 +373,10 @@ impl Editor {
362 if line > document_end.saturating_sub(padding) {
374 if line > document_end.saturating_sub(padding) {
363 // scroll down
375 // scroll down
364− self.first_line += line - (document_end.saturating_sub(padding));
376+ view.first_line += line - (document_end.saturating_sub(padding));
365− } else if line < self.first_line + padding {
377+ } else if line < view.first_line + padding {
366 // scroll up
378 // scroll up
367− self.first_line = line.saturating_sub(padding);
379+ view.first_line = line.saturating_sub(padding);