diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs index 1b0a67ae..bd14850f 100644 --- a/helix-core/src/state.rs +++ b/helix-core/src/state.rs @@ -10,6 +10,7 @@ pub enum Mode { Normal, Insert, Goto, + Command, } /// A state represents the current editor state of a single buffer. diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs index 3ebe5971..81012156 100644 --- a/helix-term/src/editor.rs +++ b/helix-term/src/editor.rs @@ -1,5 +1,5 @@ use clap::ArgMatches as Args; -use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Range, State}; +use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State}; use helix_view::{commands, keymap, View}; use std::{ @@ -242,6 +242,7 @@ impl Editor { Mode::Insert => "INS", Mode::Normal => "NOR", Mode::Goto => "GOTO", + Mode::Command => ":", }; self.surface.set_style( Rect::new(0, self.size.1 - 1, self.size.0, 1), @@ -251,35 +252,45 @@ impl Editor { let text_color = Style::default().fg(Color::Rgb(219, 191, 239)); // lilac self.surface .set_string(1, self.size.1 - 1, mode, text_color); - if let Some(path) = view.state.path() { - self.surface - .set_string(6, self.size.1 - 1, path.to_string_lossy(), text_color); - } - - self.terminal - .backend_mut() - .draw(self.cache.diff(&self.surface).into_iter()); - // swap the buffer - std::mem::swap(&mut self.surface, &mut self.cache); // set cursor shape match view.state.mode() { Mode::Insert => write!(stdout, "\x1B[6 q"), Mode::Normal => write!(stdout, "\x1B[2 q"), Mode::Goto => write!(stdout, "\x1B[2 q"), + Mode::Command => write!(stdout, "\x1B[2 q"), }; // render the cursor - let pos = view.state.selection().cursor(); + let mut pos: Position; + if view.state.mode() == Mode::Command { + pos = Position::new(self.size.0 as usize, 2); + } else { + if let Some(path) = view.state.path() { + self.surface.set_string( + 6, + self.size.1 - 1, + path.to_string_lossy(), + text_color, + ); + } - let pos = view - .screen_coords_at_pos(&view.state.doc().slice(..), pos) - .expect("Cursor is out of bounds."); + let cursor = view.state.selection().cursor(); - execute!( - stdout, - cursor::MoveTo(pos.col as u16 + viewport.x, pos.row as u16 + viewport.y,) - ); + pos = view + .screen_coords_at_pos(&view.state.doc().slice(..), cursor) + .expect("Cursor is out of bounds."); + pos.col += viewport.x as usize; + pos.row += viewport.y as usize; + } + + self.terminal + .backend_mut() + .draw(self.cache.diff(&self.surface).into_iter()); + // swap the buffer + std::mem::swap(&mut self.surface, &mut self.cache); + + execute!(stdout, cursor::MoveTo(pos.col as u16, pos.row as u16)); } None => (), } @@ -357,6 +368,16 @@ impl Editor { // TODO: simplistic ensure cursor in view for now view.ensure_cursor_in_view(); + self.render(); + } + } + Mode::Command => { + // TODO: handle modes and sequences (`gg`) + let keys = vec![event]; + if let Some(command) = keymap[&Mode::Goto].get(&keys) { + // TODO: handle count other than 1 + command(view, 1); + self.render(); } } diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs index 09c6b2fc..0e3f7ce8 100644 --- a/helix-view/src/commands.rs +++ b/helix-view/src/commands.rs @@ -304,6 +304,10 @@ pub fn append_mode(view: &mut View, _count: usize) { }) } +pub fn command_mode(view: &mut View, _count: usize) { + view.state.mode = Mode::Command; +} + // TODO: I, A, o and O can share a lot of the primitives. // calculate line numbers for each selection range diff --git a/helix-view/src/keymap.rs b/helix-view/src/keymap.rs index c3a4b8e7..96a37e6b 100644 --- a/helix-view/src/keymap.rs +++ b/helix-view/src/keymap.rs @@ -163,6 +163,7 @@ pub fn default() -> Keymaps { vec![key!('p')] => commands::paste, vec![key!('>')] => commands::indent, vec![key!('<')] => commands::unindent, + vec![key!(':')] => commands::command_mode, vec![Key { code: KeyCode::Esc, modifiers: Modifiers::NONE @@ -207,6 +208,12 @@ pub fn default() -> Keymaps { }] => commands::normal_mode as Command, vec![key!('g')] => commands::move_file_start as Command, vec![key!('e')] => commands::move_file_end as Command, + ), + state::Mode::Command => hashmap!( + vec![Key { + code: KeyCode::Esc, + modifiers: Modifiers::NONE + }] => commands::normal_mode as Command, ) ) }