good start to #16
This commit is contained in:
@@ -1,24 +1,13 @@
|
||||
use std::{
|
||||
cmp::{max, min},
|
||||
collections::HashMap,
|
||||
io,
|
||||
path::PathBuf,
|
||||
cmp::{max, min}, collections::HashMap, io, path::PathBuf
|
||||
};
|
||||
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
crossterm::event,
|
||||
layout::{self, Constraint, Layout, Rect},
|
||||
prelude,
|
||||
style::{Color, Modifier, Style},
|
||||
widgets::{Paragraph, Widget},
|
||||
DefaultTerminal, Frame, crossterm::event, layout::{self, Constraint, Layout, Rect}, prelude, style::{Color, Modifier, Style}, widgets::{Paragraph, Widget}
|
||||
};
|
||||
|
||||
use crate::app::{
|
||||
error_msg::ErrorMessage,
|
||||
logic::calc::{CellType, Grid},
|
||||
mode::Mode,
|
||||
screen::ScreenSpace,
|
||||
clipboard::Clipboard, error_msg::ErrorMessage, logic::calc::{CellType, Grid}, mode::Mode, screen::ScreenSpace
|
||||
};
|
||||
|
||||
pub struct App {
|
||||
@@ -31,6 +20,7 @@ pub struct App {
|
||||
pub screen: ScreenSpace,
|
||||
// this could probably be a normal array
|
||||
pub marks: HashMap<char, (usize, usize)>,
|
||||
pub clipboard: Clipboard,
|
||||
}
|
||||
|
||||
impl Widget for &App {
|
||||
@@ -39,7 +29,7 @@ impl Widget for &App {
|
||||
|
||||
let is_selected = |x: usize, y: usize| -> bool {
|
||||
if let Mode::Visual((mut x1, mut y1)) = self.mode {
|
||||
let (mut x2, mut y2) = self.grid.selected_cell;
|
||||
let (mut x2, mut y2) = self.grid.cursor();
|
||||
x1 += 1;
|
||||
y1 += 1;
|
||||
x2 += 1;
|
||||
@@ -96,7 +86,7 @@ impl Widget for &App {
|
||||
(true, false) => {
|
||||
display = y_idx.to_string();
|
||||
|
||||
let bg = if y_idx == self.grid.selected_cell.1 {
|
||||
let bg = if y_idx == self.grid.cursor().1 {
|
||||
Color::DarkGray
|
||||
} else if y_idx % 2 == 0 {
|
||||
ORANGE1
|
||||
@@ -109,7 +99,7 @@ impl Widget for &App {
|
||||
(false, true) => {
|
||||
display = Grid::num_to_char(x_idx);
|
||||
|
||||
let bg = if x_idx == self.grid.selected_cell.0 {
|
||||
let bg = if x_idx == self.grid.cursor().0 {
|
||||
Color::DarkGray
|
||||
} else if x_idx % 2 == 0 {
|
||||
ORANGE1
|
||||
@@ -157,7 +147,7 @@ impl Widget for &App {
|
||||
}
|
||||
None => should_render = false,
|
||||
}
|
||||
if (x_idx, y_idx) == self.grid.selected_cell {
|
||||
if (x_idx, y_idx) == self.grid.cursor() {
|
||||
should_render = true;
|
||||
style = Style::new().fg(Color::Black).bg(Color::White);
|
||||
// modify the style of the cell you are editing
|
||||
@@ -201,6 +191,7 @@ impl App {
|
||||
vars: HashMap::new(),
|
||||
screen: ScreenSpace::new(),
|
||||
marks: HashMap::new(),
|
||||
clipboard: Clipboard::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +222,7 @@ impl App {
|
||||
let len = match &self.mode {
|
||||
Mode::Insert(edit) | Mode::Command(edit) | Mode::Chord(edit) => edit.len(),
|
||||
Mode::Normal => {
|
||||
let (x, y) = self.grid.selected_cell;
|
||||
let (x, y) = self.grid.cursor();
|
||||
let cell = self.grid.get_cell_raw(x, y).as_ref().map(|f| f.to_string().len()).unwrap_or_default();
|
||||
cell
|
||||
}
|
||||
@@ -259,7 +250,7 @@ impl App {
|
||||
Mode::Chord(chord) => frame.render_widget(chord, cmd_line_left),
|
||||
Mode::Normal => frame.render_widget(
|
||||
Paragraph::new({
|
||||
let (x, y) = self.grid.selected_cell;
|
||||
let (x, y) = self.grid.cursor();
|
||||
let cell = self.grid.get_cell_raw(x, y).as_ref().map(|f| f.to_string()).unwrap_or_default();
|
||||
cell
|
||||
}),
|
||||
@@ -274,7 +265,7 @@ impl App {
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"x/w y/h: cursor{:?} scroll({}, {}) cell({}, {}) screen({}, {}) len{len}",
|
||||
self.grid.selected_cell,
|
||||
self.grid.cursor(),
|
||||
self.screen.scroll_x(),
|
||||
self.screen.scroll_y(),
|
||||
self.screen.get_cell_width(&self.vars),
|
||||
@@ -312,13 +303,13 @@ impl App {
|
||||
|
||||
// try to insert as a float
|
||||
if let Ok(v) = v.parse::<f64>() {
|
||||
self.grid.set_cell_raw(self.grid.selected_cell, Some(v));
|
||||
self.grid.set_cell_raw(self.grid.cursor(), Some(v));
|
||||
} else {
|
||||
// if you can't, then insert as a string
|
||||
if !v.is_empty() {
|
||||
self.grid.set_cell_raw(self.grid.selected_cell, Some(v));
|
||||
self.grid.set_cell_raw(self.grid.cursor(), Some(v));
|
||||
} else {
|
||||
self.grid.set_cell_raw::<CellType>(self.grid.selected_cell, None);
|
||||
self.grid.set_cell_raw::<CellType>(self.grid.cursor(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,7 +369,7 @@ impl App {
|
||||
}
|
||||
|
||||
// make sure cursor is inside window
|
||||
self.screen.scroll_based_on_cursor_location(self.grid.selected_cell, &self.vars);
|
||||
self.screen.scroll_based_on_cursor_location(self.grid.cursor(), &self.vars);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
174
src/app/clipboard.rs
Normal file
174
src/app/clipboard.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
use std::cmp::{max, min};
|
||||
|
||||
use crate::app::logic::calc::{CellType, Grid};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::app::{
|
||||
app::App, mode::{Chord, Mode}
|
||||
};
|
||||
|
||||
pub struct Clipboard {
|
||||
// could this just be a grid?
|
||||
clipboard: Vec<Vec<Option<CellType>>>,
|
||||
// top_left_cell: (usize, usize),
|
||||
last_paste_cell: (usize, usize),
|
||||
momentum: (i32, i32),
|
||||
}
|
||||
|
||||
impl Clipboard {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
clipboard: Vec::new(),
|
||||
last_paste_cell: (0, 0),
|
||||
momentum: (0, 1),
|
||||
}
|
||||
}
|
||||
|
||||
/// After pasting you gain momentum which can be used to
|
||||
/// to move the cursor in the same direction for the next
|
||||
/// paste.
|
||||
pub fn momentum(&self) -> (i32, i32) {
|
||||
// normalize to (-1,-1) to (1,1)
|
||||
let (mx, my) = self.momentum;
|
||||
let x = min(mx, 1);
|
||||
let x = max(x, -1);
|
||||
|
||||
let y = min(my, 1);
|
||||
let y = max(y, -1);
|
||||
|
||||
// prevent diagonal momentum
|
||||
if y != 0 {
|
||||
(0, y)
|
||||
} else {
|
||||
(x,0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paste(&mut self, into: &mut Grid) {
|
||||
// cursor
|
||||
let (cx, cy) = into.cursor();
|
||||
|
||||
for (x, row) in self.clipboard.iter().enumerate() {
|
||||
for (y, cell) in row.iter().enumerate() {
|
||||
into.set_cell_raw((x + cx, y + cy), cell.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let (lx, ly) = self.last_paste_cell;
|
||||
self.momentum = (cx as i32 - lx as i32, cy as i32 - ly as i32);
|
||||
self.last_paste_cell = (cx, cy);
|
||||
}
|
||||
|
||||
/// Clones data from Grid into self.
|
||||
/// Start and end don't have to be sorted in any sort of way. The function works with
|
||||
/// any two points.
|
||||
pub fn clipboard_copy(&mut self, start: (usize, usize), end: (usize, usize), from: &Grid) {
|
||||
let (x1, y1) = start;
|
||||
let (x2, y2) = end;
|
||||
|
||||
let (low_x, hi_x) = if x1 < x2 { (x1, x2) } else { (x2, x1) };
|
||||
let (low_y, hi_y) = if y1 < y2 { (y1, y2) } else { (y2, y1) };
|
||||
|
||||
// size the clipboard appropriately
|
||||
self.clipboard.clear();
|
||||
// clone data into clipboard
|
||||
for x in low_x..=hi_x {
|
||||
let mut col = Vec::new();
|
||||
for y in low_y..=hi_y {
|
||||
let a = from.get_cell_raw(x, y);
|
||||
col.push(a.clone());
|
||||
}
|
||||
self.clipboard.push(col);
|
||||
}
|
||||
self.last_paste_cell = (low_x, low_y);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_paste() {
|
||||
let mut app = App::new();
|
||||
|
||||
app.grid.set_cell("A0", "hello".to_string());
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
|
||||
app.mode = super::mode::Mode::Chord(Chord::new('y'));
|
||||
Mode::process_key(&mut app, 'y');
|
||||
// yy will have set mode back to normal at this point
|
||||
|
||||
assert_eq!(app.clipboard.clipboard.len(), 1);
|
||||
assert!(app.clipboard.clipboard[0][0].as_ref().is_some_and(|c| c.to_string() == "hello"));
|
||||
|
||||
app.grid.mv_cursor_to(1, 1);
|
||||
Mode::process_key(&mut app, 'p');
|
||||
|
||||
let a = app.grid.get_cell("B1").as_ref().expect("Should've been set by paste");
|
||||
assert_eq!(a.to_string(), "hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn momentum_y_pos() {
|
||||
let mut app = App::new();
|
||||
|
||||
app.grid.set_cell("A0", "hello".to_string());
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
|
||||
app.mode = super::mode::Mode::Chord(Chord::new('y'));
|
||||
Mode::process_key(&mut app, 'y');
|
||||
// yy will have set mode back to normal at this point
|
||||
|
||||
app.grid.mv_cursor_to(0, 1);
|
||||
Mode::process_key(&mut app, 'p');
|
||||
|
||||
assert_eq!(app.clipboard.momentum(), (0,1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn momentum_y_neg() {
|
||||
let mut app = App::new();
|
||||
|
||||
app.grid.set_cell("A1", "hello".to_string());
|
||||
app.grid.mv_cursor_to(0, 1);
|
||||
|
||||
app.mode = super::mode::Mode::Chord(Chord::new('y'));
|
||||
Mode::process_key(&mut app, 'y');
|
||||
// yy will have set mode back to normal at this point
|
||||
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
Mode::process_key(&mut app, 'p');
|
||||
|
||||
assert_eq!(app.clipboard.momentum(), (0,-1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn momentum_x_pos() {
|
||||
let mut app = App::new();
|
||||
|
||||
app.grid.set_cell("A0", "hello".to_string());
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
|
||||
app.mode = super::mode::Mode::Chord(Chord::new('y'));
|
||||
Mode::process_key(&mut app, 'y');
|
||||
// yy will have set mode back to normal at this point
|
||||
|
||||
app.grid.mv_cursor_to(1, 0);
|
||||
Mode::process_key(&mut app, 'p');
|
||||
|
||||
assert_eq!(app.clipboard.momentum(), (1,0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn momentum_x_neg() {
|
||||
let mut app = App::new();
|
||||
|
||||
app.grid.set_cell("B0", "hello".to_string());
|
||||
app.grid.mv_cursor_to(1, 0);
|
||||
|
||||
app.mode = super::mode::Mode::Chord(Chord::new('y'));
|
||||
Mode::process_key(&mut app, 'y');
|
||||
// yy will have set mode back to normal at this point
|
||||
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
Mode::process_key(&mut app, 'p');
|
||||
|
||||
assert_eq!(app.clipboard.momentum(), (-1,0));
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
|
||||
use evalexpr::*;
|
||||
|
||||
use crate::app::logic::ctx;
|
||||
use crate::app::{app::App, logic::ctx};
|
||||
|
||||
pub const LEN: usize = 1000;
|
||||
|
||||
@@ -19,7 +19,7 @@ pub struct Grid {
|
||||
// ...
|
||||
cells: Vec<Vec<Option<CellType>>>,
|
||||
/// (X, Y)
|
||||
pub selected_cell: (usize, usize),
|
||||
selected_cell: (usize, usize),
|
||||
/// Have unsaved modifications been made?
|
||||
dirty: bool,
|
||||
}
|
||||
@@ -34,6 +34,14 @@ const CSV_DELIMITER: char = ',';
|
||||
const CSV_ESCAPE: char = '"';
|
||||
|
||||
impl Grid {
|
||||
pub fn cursor(&self) -> (usize, usize) {
|
||||
self.selected_cell
|
||||
}
|
||||
|
||||
pub fn mv_cursor_to(&mut self, x: usize, y: usize) {
|
||||
self.selected_cell = (x,y)
|
||||
}
|
||||
|
||||
pub fn needs_to_be_saved(&self) -> bool {
|
||||
self.dirty
|
||||
}
|
||||
@@ -311,7 +319,7 @@ impl Grid {
|
||||
|
||||
/// Helper for tests
|
||||
#[cfg(test)]
|
||||
fn set_cell<T: Into<CellType>>(&mut self, cell_id: &str, val: T) {
|
||||
pub fn set_cell<T: Into<CellType>>(&mut self, cell_id: &str, val: T) {
|
||||
if let Some(loc) = Self::parse_to_idx(cell_id) {
|
||||
self.set_cell_raw(loc, Some(val));
|
||||
}
|
||||
@@ -365,7 +373,7 @@ impl Default for Grid {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CellType {
|
||||
Number(f64),
|
||||
String(String),
|
||||
@@ -710,5 +718,16 @@ fn ranges() {
|
||||
#[test]
|
||||
fn recursive_ranges() {
|
||||
// recursive ranges causes weird behavior
|
||||
todo!();
|
||||
// todo!();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_fns() {
|
||||
// surprisingly, this test was needed
|
||||
let mut app = App::new();
|
||||
let c = app.grid.cursor();
|
||||
assert_eq!(c, (0,0));
|
||||
|
||||
app.grid.mv_cursor_to(1, 0);
|
||||
assert_eq!(app.grid.cursor(), (1,0));
|
||||
}
|
||||
@@ -3,3 +3,4 @@ mod mode;
|
||||
mod error_msg;
|
||||
mod screen;
|
||||
mod logic;
|
||||
mod clipboard;
|
||||
@@ -116,31 +116,36 @@ impl Mode {
|
||||
match key {
|
||||
// <
|
||||
'h' => {
|
||||
app.grid.selected_cell.0 = app.grid.selected_cell.0.saturating_sub(1);
|
||||
let (x, y) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(x.saturating_sub(1), y);
|
||||
return;
|
||||
}
|
||||
// v
|
||||
'j' => {
|
||||
app.grid.selected_cell.1 = min(app.grid.selected_cell.1.saturating_add(1), LEN - 1);
|
||||
let (x, y) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(x, min(y.saturating_add(1), LEN - 1));
|
||||
return;
|
||||
}
|
||||
// ^
|
||||
'k' => {
|
||||
app.grid.selected_cell.1 = app.grid.selected_cell.1.saturating_sub(1);
|
||||
let (x, y) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(x, y.saturating_sub(1));
|
||||
return;
|
||||
}
|
||||
// >
|
||||
'l' => {
|
||||
app.grid.selected_cell.0 = min(app.grid.selected_cell.0.saturating_add(1), LEN - 1);
|
||||
let (x, y) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(min(x.saturating_add(1), LEN - 1), y);
|
||||
return;
|
||||
}
|
||||
'0' => {
|
||||
app.grid.selected_cell.0 = 0;
|
||||
let (_, y) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(0, y);
|
||||
return;
|
||||
}
|
||||
// edit cell
|
||||
'i' | 'a' => {
|
||||
let (x, y) = app.grid.selected_cell;
|
||||
let (x, y) = app.grid.cursor();
|
||||
|
||||
let val = app.grid.get_cell_raw(x, y).as_ref().map(|f| f.to_string()).unwrap_or(String::new());
|
||||
|
||||
@@ -154,8 +159,15 @@ impl Mode {
|
||||
'A' => { /* insert col after */ }
|
||||
'o' => { /* insert row below */ }
|
||||
'O' => { /* insert row above */ }
|
||||
'v' => app.mode = Mode::Visual(app.grid.selected_cell),
|
||||
'v' => app.mode = Mode::Visual(app.grid.cursor()),
|
||||
':' => app.mode = Mode::Command(Chord::new(':')),
|
||||
'p' => {
|
||||
app.clipboard.paste(&mut app.grid);
|
||||
let (cx, cy) = app.grid.cursor();
|
||||
let (mx, my) = app.clipboard.momentum();
|
||||
app.grid.mv_cursor_to((cx as i32 + mx) as usize, (cy as i32 + my) as usize);
|
||||
return;
|
||||
}
|
||||
// loose chars will put you into chord mode
|
||||
c => {
|
||||
if let Mode::Normal = app.mode {
|
||||
@@ -165,12 +177,13 @@ impl Mode {
|
||||
}
|
||||
if let Mode::Visual((x1, y1)) = app.mode {
|
||||
// TODO visual copy, paste, etc
|
||||
let (x2, y2) = app.grid.selected_cell;
|
||||
let (x2, y2) = app.grid.cursor();
|
||||
|
||||
let (low_x, hi_x) = if x1 < x2 { (x1, x2) } else { (x2, x1) };
|
||||
let (low_y, hi_y) = if y1 < y2 { (y1, y2) } else { (y2, y1) };
|
||||
|
||||
if key == 'd' {
|
||||
match key {
|
||||
'd' => {
|
||||
for x in low_x..=hi_x {
|
||||
for y in low_y..=hi_y {
|
||||
app.grid.set_cell_raw::<CellType>((x, y), None);
|
||||
@@ -178,6 +191,11 @@ impl Mode {
|
||||
}
|
||||
app.mode = Mode::Normal
|
||||
}
|
||||
'y' => {
|
||||
app.clipboard.clipboard_copy((x1, y1), (x2, y2), &app.grid);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Mode::Chord(chord) => {
|
||||
@@ -194,8 +212,8 @@ impl Mode {
|
||||
// For chords that can take a numeric input
|
||||
Ok(num) => match key {
|
||||
'G' => {
|
||||
let sel = app.grid.selected_cell;
|
||||
app.grid.selected_cell = (sel.0, num);
|
||||
let (x, _) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(x, num);
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
_ => {
|
||||
@@ -213,33 +231,40 @@ impl Mode {
|
||||
match (&c[..c.len() - 1], key) {
|
||||
// delete cell under cursor
|
||||
("d", ' ') | ("d", 'w') => {
|
||||
let loc = app.grid.selected_cell;
|
||||
let loc = app.grid.cursor();
|
||||
app.grid.set_cell_raw::<CellType>(loc, None);
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
// go to top of row
|
||||
("g", 'g') => {
|
||||
app.grid.selected_cell.1 = 0;
|
||||
let (x, _) = app.grid.cursor();
|
||||
app.grid.mv_cursor_to(x, 0);
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
// center screen to cursor
|
||||
("z", 'z') => {
|
||||
app.screen.center_x(app.grid.selected_cell, &app.vars);
|
||||
app.screen.center_y(app.grid.selected_cell, &app.vars);
|
||||
app.screen.center_x(app.grid.cursor(), &app.vars);
|
||||
app.screen.center_y(app.grid.cursor(), &app.vars);
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
// mark cell
|
||||
("m", i) => {
|
||||
app.marks.insert(i, app.grid.selected_cell);
|
||||
app.marks.insert(i, app.grid.cursor());
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
// goto marked cell
|
||||
("'", i) => {
|
||||
if let Some(coords) = app.marks.get(&i) {
|
||||
app.grid.selected_cell = *coords;
|
||||
if let Some((cx, cy)) = app.marks.get(&i) {
|
||||
app.grid.mv_cursor_to(*cx, *cy);
|
||||
}
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
// copy 1 cell
|
||||
("y", 'y') => {
|
||||
let point = app.grid.cursor();
|
||||
app.clipboard.clipboard_copy(point, point, &app.grid);
|
||||
app.mode = Mode::Normal;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -295,31 +320,47 @@ impl Widget for &Chord {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn movement_keybinds() {
|
||||
let mut app = App::new();
|
||||
|
||||
assert_eq!(app.grid.cursor(), (0, 0));
|
||||
Mode::process_key(&mut app, 'j');
|
||||
assert_eq!(app.grid.cursor(), (0, 1));
|
||||
|
||||
Mode::process_key(&mut app, 'l');
|
||||
assert_eq!(app.grid.cursor(), (1, 1));
|
||||
|
||||
Mode::process_key(&mut app, 'k');
|
||||
assert_eq!(app.grid.cursor(), (1, 0));
|
||||
|
||||
Mode::process_key(&mut app, 'h');
|
||||
assert_eq!(app.grid.cursor(), (0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keybinds() {
|
||||
let mut app = App::new();
|
||||
|
||||
assert_eq!(app.grid.selected_cell, (0,0));
|
||||
|
||||
// start at B1
|
||||
app.grid.selected_cell = (1,1);
|
||||
assert_eq!(app.grid.selected_cell, (1,1));
|
||||
app.grid.mv_cursor_to(1, 1);
|
||||
assert_eq!(app.grid.cursor(), (1, 1));
|
||||
|
||||
// gg
|
||||
app.mode = Mode::Chord(Chord::new('g'));
|
||||
Mode::process_key(&mut app, 'g');
|
||||
assert_eq!(app.grid.selected_cell, (1,0));
|
||||
assert_eq!(app.grid.cursor(), (1, 0));
|
||||
|
||||
// 0
|
||||
app.mode = Mode::Normal;
|
||||
Mode::process_key(&mut app, '0');
|
||||
assert_eq!(app.grid.selected_cell, (0,0));
|
||||
assert_eq!(app.grid.cursor(), (0, 0));
|
||||
|
||||
// 10l
|
||||
// this should mean all the directions work
|
||||
app.grid.selected_cell = (0,0);
|
||||
app.grid.mv_cursor_to(0, 0);
|
||||
app.mode = Mode::Chord(Chord::new('1'));
|
||||
Mode::process_key(&mut app, '0');
|
||||
Mode::process_key(&mut app, 'l');
|
||||
assert_eq!(app.grid.selected_cell, (10,0));
|
||||
assert_eq!(app.grid.cursor(), (10, 0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user