diff --git a/Makefile b/Makefile index 4ccb906..608f476 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,5 @@ test: RUST_BACKTRACE=1 cargo test + +run: + RUST_BACKTRACE=1 cargo run diff --git a/src/nvim.rs b/src/nvim.rs index 2f6b70d..12fe3a3 100644 --- a/src/nvim.rs +++ b/src/nvim.rs @@ -23,6 +23,10 @@ pub trait RedrawEvents { fn on_highlight_set(&mut self, attrs: &HashMap); fn on_eol_clear(&mut self); + + fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64); + + fn on_scroll(&mut self, count: i64); } macro_rules! try_str { @@ -33,9 +37,17 @@ macro_rules! try_str { } macro_rules! try_int { + ($expr:expr) => (match $expr { + Value::Integer(Integer::U64(val)) => val as i64, + Value::Integer(Integer::I64(val)) => val, + _ => return Err("Can't convert argument to int".to_owned()) + }) +} + +macro_rules! try_uint { ($exp:expr) => (match $exp { Value::Integer(Integer::U64(val)) => val, - _ => return Err("Can't convert argument to int".to_owned()) + _ => return Err("Can't convert argument to u64".to_owned()) }) } @@ -93,7 +105,7 @@ fn call(method: &str, args: Vec) { match method { "cursor_goto" => { safe_call(move |ui| { - ui.on_cursor_goto(try_int!(args[0]), try_int!(args[1])); + ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])); Ok(()) }) } @@ -111,19 +123,29 @@ fn call(method: &str, args: Vec) { } "resize" => { safe_call(move |ui| { - ui.on_resize(try_int!(args[0]), try_int!(args[1])); + ui.on_resize(try_uint!(args[0]), try_uint!(args[1])); Ok(()) }); } "highlight_set" => { safe_call(move |ui| { if let Value::Map(ref attrs) = args[0] { - let attrs_map: HashMap = attrs.iter().map(|v| { - match v { - &(Value::String(ref key), ref value) => (key.clone(), value.clone()), - _ => panic!("attribute key must be string"), - } - }).collect(); + let attrs_map: HashMap = attrs.iter() + .map(|v| { + match v { + &(Value::String(ref key), + ref value) => { + (key.clone(), + value.clone()) + } + _ => { + panic!("attribute \ + key must be \ + string") + } + } + }) + .collect(); ui.on_highlight_set(&attrs_map); } else { panic!("Supports only map value as argument"); @@ -137,6 +159,18 @@ fn call(method: &str, args: Vec) { Ok(()) }) } + "set_scroll_region" => { + safe_call(move |ui| { + ui.on_set_scroll_region(try_uint!(args[0]), try_uint!(args[1]), try_uint!(args[2]), try_uint!(args[3])); + Ok(()) + }); + } + "scroll" => { + safe_call(move |ui| { + ui.on_scroll(try_int!(args[0])); + Ok(()) + }); + } _ => println!("Event {}({:?})", method, args), }; } diff --git a/src/ui.rs b/src/ui.rs index a75815d..ba9cef3 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -244,6 +244,14 @@ impl RedrawEvents for Ui { self.drawing_area.queue_draw(); } + fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) { + self.model.set_scroll_region(top, bot, left, right); + } + + fn on_scroll(&mut self, count: i64) { + self.model.scroll(count); + } + fn on_highlight_set(&mut self, attrs: &HashMap) { let mut model_attrs = Attrs::new(); if let Some(&Value::Integer(Integer::U64(fg))) = attrs.get("foreground") { diff --git a/src/ui_model.rs b/src/ui_model.rs index 4ddb03a..87a343c 100644 --- a/src/ui_model.rs +++ b/src/ui_model.rs @@ -31,6 +31,7 @@ impl Attrs { } } +#[derive(Clone)] pub struct Cell { pub ch: char, pub attrs: Attrs, @@ -56,6 +57,10 @@ pub struct UiModel { cur_row: usize, cur_col: usize, model: Vec>, + top: usize, + bot: usize, + left: usize, + right: usize, } impl UiModel { @@ -78,6 +83,10 @@ impl UiModel { cur_row: 0, cur_col: 0, model: model, + top: 0, + bot: 0, + left: 0, + right: 0, } } @@ -97,12 +106,44 @@ impl UiModel { self.cur_col += 1; } - pub fn clear(&mut self) { - for row in 0..self.rows { - for col in 0..self.columns { - self.model[row][col].clear(); + pub fn set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) { + self.top = top as usize; + self.bot = bot as usize; + self.left = left as usize; + self.right = right as usize; + } + + fn copy_row(&mut self, row: usize, offset: i64, left: usize, right: usize) { + for col in left..right + 1 { + let from_row = (row as i64 + offset) as usize; + let from_cell = self.model[from_row][col].clone(); + self.model[row][col] = from_cell; + } + } + + pub fn scroll(&mut self, count: i64) { + let (top, bot, left, right) = (self.top as i64, self.bot as i64, self.left, self.right); + + if count > 0 { + for row in top as usize..(bot - count + 1) as usize { + self.copy_row(row, count, left, right); + } + } else { + for row in ((top - count) as usize..(bot + 1) as usize).rev() { + self.copy_row(row, count, left, right); } } + + if count > 0 { + self.clear_region((bot - count + 1) as usize, bot as usize, left, right); + } else { + self.clear_region(top as usize, (top - count - 1) as usize, left, right); + } + } + + pub fn clear(&mut self) { + let (rows, columns) = (self.rows, self.columns); + self.clear_region(0, rows - 1, 0, columns - 1); } pub fn eol_clear(&mut self) { @@ -111,9 +152,9 @@ impl UiModel { } fn clear_region(&mut self, top: usize, bot: usize, left: usize, right: usize) { - for row in top..bot + 1 { - for col in left..right + 1 { - self.model[row][col].clear(); + for row in &mut self.model[top..bot + 1] { + for cell in &mut row[left..right + 1] { + cell.clear(); } } }