diff --git a/src/main.rs b/src/main.rs index 85fc87f..064e91c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ extern crate serde_derive; extern crate serde; extern crate toml; +mod value; mod ui_model; #[macro_use] mod ui; diff --git a/src/nvim.rs b/src/nvim.rs index eb3febb..f83f569 100644 --- a/src/nvim.rs +++ b/src/nvim.rs @@ -5,7 +5,6 @@ use std::process::{Stdio, Command}; use std::result; use std::sync::Arc; use std::ops::{Deref, DerefMut}; -use std::collections::HashMap; use neovim_lib::{Handler, Neovim, NeovimApi, Session, Value, UiAttachOptions, CallError, UiOption}; use neovim_lib::neovim_api::Tabpage; @@ -15,6 +14,8 @@ use ui_model::{ModelRect, ModelRectVec}; use shell; use glib; +use value::ValueMapExt; + pub trait RedrawEvents { fn on_cursor_goto(&mut self, row: u64, col: u64) -> RepaintMode; @@ -59,7 +60,7 @@ pub trait RedrawEvents { fn tabline_update(&mut self, selected: Tabpage, - tabs: Vec<(Tabpage, Option<&str>)>) + tabs: Vec<(Tabpage, Option)>) -> RepaintMode; fn mode_info_set(&mut self, @@ -88,6 +89,23 @@ macro_rules! try_bool { ($exp:expr) => ($exp.as_bool().ok_or("Can't convert argument to bool".to_owned())?) } +macro_rules! map_array { + ($arg:expr, $err:expr, |$item:ident| $exp:expr) => ( + $arg.as_array() + .ok_or($err) + .and_then(|items| items.iter().map(|$item| { + $exp + }).collect::, _>>()) + ); + ($arg:expr, $err:expr, |$item:ident| {$exp:expr}) => ( + $arg.as_array() + .ok_or($err) + .and_then(|items| items.iter().map(|$item| { + $exp + }).collect::, _>>()) + ); +} + pub enum CursorShape { Block, Horizontal, @@ -119,15 +137,7 @@ pub struct ModeInfo { impl ModeInfo { pub fn new(mode_info_arr: &Vec<(Value, Value)>) -> Result { - let mode_info_map = mode_info_arr - .iter() - .map(|p| { - p.0 - .as_str() - .ok_or("mode_info key not string".to_owned()) - .map(|key| (key, p.1.clone())) - }) - .collect::, String>>()?; + let mode_info_map = mode_info_arr.to_attrs_map()?; let cursor_shape = if let Some(shape) = mode_info_map.get("cursor_shape") { Some(CursorShape::new(shape)?) @@ -372,17 +382,11 @@ fn call(ui: &mut shell::State, "busy_start" => ui.on_busy(true), "busy_stop" => ui.on_busy(false), "popupmenu_show" => { - let mut menu_items = Vec::new(); - - let items = args[0].as_array().ok_or("Error get menu list array")?; - for item in items { - let item_line: result::Result, &str> = item.as_array() - .ok_or("Error get menu item array")? - .iter() - .map(|col| col.as_str().ok_or("Error get menu column")) - .collect(); - menu_items.push(item_line?); - } + let menu_items = map_array!(args[0], "Error get menu list array", |item| { + map_array!(item, + "Error get menu item array", + |col| col.as_str().ok_or("Error get menu column")) + })?; ui.popupmenu_show(&menu_items, try_int!(args[1]), @@ -392,40 +396,32 @@ fn call(ui: &mut shell::State, "popupmenu_hide" => ui.popupmenu_hide(), "popupmenu_select" => ui.popupmenu_select(try_int!(args[0])), "tabline_update" => { - let tabs_in = args[1].as_array().ok_or("Error get tabline list")?; + let tabs_out = map_array!(args[1], "Error get tabline list".to_owned(), |tab| { + tab.as_map() + .ok_or("Error get map for tab".to_owned()) + .and_then(|tab_map| tab_map.to_attrs_map()) + .map(|tab_attrs| { + let name_attr = tab_attrs + .get("name") + .and_then(|n| n.as_str().map(|s| s.to_owned())); + let tab_attr = tab_attrs + .get("tab") + .map(|tab_id| Tabpage::new(tab_id.clone())) + .unwrap(); - let mut tabs_out = Vec::new(); - for tab in tabs_in { - let tab_attrs = tab.as_map().ok_or("Error get map for tab")?; - - let mut tab_attr = None; - let mut name_attr = None; - - for attr in tab_attrs { - let key = attr.0.as_str().ok_or("Error get key value")?; - if key == "tab" { - tab_attr = Some(Tabpage::new(attr.1.clone())); - } else if key == "name" { - name_attr = attr.1.as_str(); - } - } - tabs_out.push((tab_attr.unwrap(), name_attr)); - } + (tab_attr, name_attr) + }) + })?; ui.tabline_update(Tabpage::new(args[0].clone()), tabs_out) } "mode_info_set" => { - let mode_info_array = args[1] - .as_array() - .ok_or("Erro get array key value for mode_info")?; - - let mode_info = mode_info_array - .iter() - .map(|mi| { - mi.as_map() - .ok_or("Erro get map for mode_info".to_owned()) - .and_then(|mi_map| ModeInfo::new(mi_map)) - }) - .collect::, String>>()?; + let mode_info = map_array!(args[1], + "Error get array key value for mode_info".to_owned(), + |mi| { + mi.as_map() + .ok_or("Erro get map for mode_info".to_owned()) + .and_then(|mi_map| ModeInfo::new(mi_map)) + })?; ui.mode_info_set(try_bool!(args[0]), mode_info) } _ => { diff --git a/src/shell.rs b/src/shell.rs index 9048ec0..a18a7f8 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1007,7 +1007,7 @@ impl RedrawEvents for State { fn tabline_update(&mut self, selected: Tabpage, - tabs: Vec<(Tabpage, Option<&str>)>) + tabs: Vec<(Tabpage, Option)>) -> RepaintMode { self.tabs.update_tabs(&self.nvim, &selected, &tabs); diff --git a/src/tabline.rs b/src/tabline.rs index 69efe3f..cea0304 100644 --- a/src/tabline.rs +++ b/src/tabline.rs @@ -69,7 +69,7 @@ impl Tabline { fn update_state(&self, nvim: &Rc>, selected: &Tabpage, - tabs: &Vec<(Tabpage, Option<&str>)>) { + tabs: &Vec<(Tabpage, Option)>) { let mut state = self.state.borrow_mut(); if state.nvim.is_none() { @@ -84,7 +84,7 @@ impl Tabline { pub fn update_tabs(&self, nvim: &Rc>, selected: &Tabpage, - tabs: &Vec<(Tabpage, Option<&str>)>) { + tabs: &Vec<(Tabpage, Option)>) { if tabs.len() <= 1 { self.tabs.hide(); return; @@ -113,7 +113,7 @@ impl Tabline { for (idx, tab) in tabs.iter().enumerate() { let tab_child = self.tabs.get_nth_page(Some(idx as u32)); self.tabs - .set_tab_label_text(&tab_child.unwrap(), &tab.1.unwrap_or("??")); + .set_tab_label_text(&tab_child.unwrap(), &tab.1.as_ref().unwrap_or(&"??".to_owned())); if *selected == tab.0 { self.tabs.set_current_page(Some(idx as u32)); diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..f74e7a1 --- /dev/null +++ b/src/value.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; +use neovim_lib::Value; + +pub trait ValueMapExt { + fn to_attrs_map(&self) -> Result, String>; +} + +impl ValueMapExt for Vec<(Value, Value)> { + fn to_attrs_map(&self) -> Result, String> { + self.iter() + .map(|p| { + p.0 + .as_str() + .ok_or("Can't convert map key to string".to_owned()) + .map(|key| (key, p.1.clone())) + }) + .collect::, String>>() + + } +}