diff --git a/src/color.rs b/src/color.rs index d8a0e05..76ec34a 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,5 +1,7 @@ use std; + use gdk; + use ui_model::Cell; use theme::Theme; @@ -10,12 +12,12 @@ pub const COLOR_BLACK: Color = Color(0.0, 0.0, 0.0); pub const COLOR_WHITE: Color = Color(1.0, 1.0, 1.0); pub const COLOR_RED: Color = Color(1.0, 0.0, 0.0); -impl<'a> Into for &'a Color { - fn into(self) -> gdk::RGBA { +impl From for gdk::RGBA { + fn from(color: Color) -> Self { gdk::RGBA { - red: self.0, - green: self.1, - blue: self.2, + red: color.0, + green: color.1, + blue: color.2, alpha: 1.0, } } @@ -101,39 +103,36 @@ impl ColorModel { cell.attrs.special.as_ref().unwrap_or(&self.sp_color) } - pub fn pmenu_bg(&self) -> &Color { - if let Some(ref pmenu) = self.theme.pmenu { - pmenu.bg.as_ref().unwrap_or(&self.bg_color) - } else { - &self.bg_color - } + pub fn pmenu_bg<'a>(&'a self) -> Color { + self.theme + .pmenu() + .bg + .clone() + .unwrap_or_else(|| self.bg_color.clone()) } - - pub fn pmenu_fg(&self) -> &Color { - if let Some(ref pmenu) = self.theme.pmenu { - pmenu.fg.as_ref().unwrap_or(&self.fg_color) - } else { - &self.fg_color - } + pub fn pmenu_fg(&self) -> Color { + self.theme + .pmenu() + .fg + .clone() + .unwrap_or_else(|| self.fg_color.clone()) } - - pub fn pmenu_bg_sel(&self) -> &Color { - if let Some(ref pmenu) = self.theme.pmenu { - pmenu.bg_sel.as_ref().unwrap_or(&self.bg_color) - } else { - &self.bg_color - } + pub fn pmenu_bg_sel(&self) -> Color { + self.theme + .pmenu() + .bg_sel + .clone() + .unwrap_or_else(|| self.bg_color.clone()) } - - pub fn pmenu_fg_sel(&self) -> &Color { - if let Some(ref pmenu) = self.theme.pmenu { - pmenu.fg_sel.as_ref().unwrap_or(&self.fg_color) - } else { - &self.fg_color - } + pub fn pmenu_fg_sel(&self) -> Color { + self.theme + .pmenu() + .fg_sel + .clone() + .unwrap_or_else(|| self.fg_color.clone()) } } diff --git a/src/shell.rs b/src/shell.rs index c66c6f0..858b101 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1181,7 +1181,7 @@ impl State { if let Some(mut nvim) = self.nvim.nvim() { let mut render_state = self.render_state.borrow_mut(); - render_state.color_model.theme.update(&mut *nvim); + render_state.color_model.theme.queue_update(&mut *nvim); } RepaintMode::Nothing } diff --git a/src/theme.rs b/src/theme.rs index 6a74fe7..4a08f2b 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,22 +1,72 @@ use std::collections::HashMap; +use std::sync::Arc; +use std::cell::Ref; -use neovim_lib::{Value, Neovim, NeovimApi}; +use glib; +use neovim_lib::{CallError, Neovim, NeovimApiAsync, Value}; + +use ui::UiMutex; use nvim::ErrorReport; use color::Color; use value::ValueMapExt; +struct State { + pmenu: Pmenu, +} + +impl State { + fn new() -> Self { + State { + pmenu: Pmenu::new(), + } + } +} + pub struct Theme { - pub pmenu: Option, + state: Arc>, } impl Theme { pub fn new() -> Self { - Theme { pmenu: None } + Theme { + state: Arc::new(UiMutex::new(State::new())), + } } - pub fn update(&mut self, nvim: &mut Neovim) { - self.pmenu = Some(Pmenu::new(nvim)); + pub fn pmenu(&self) -> Ref { + Ref::map(self.state.borrow(), |s| &s.pmenu) + } + + pub fn queue_update(&self, nvim: &mut Neovim) { + self.get_hl(nvim, "Pmenu", |state, bg, fg| { + state.pmenu.bg = bg; + state.pmenu.fg = fg; + }); + + self.get_hl(nvim, "PmenuSel", |state, bg_sel, fg_sel| { + state.pmenu.bg_sel = bg_sel; + state.pmenu.fg_sel = fg_sel; + }); + } + + fn get_hl(&self, nvim: &mut Neovim, hl_name: &str, mut cb: CB) + where + CB: FnMut(&mut State, Option, Option) + Send + 'static, + { + let state = self.state.clone(); + + nvim.get_hl_by_name_async(hl_name, true) + .cb(move |v| { + let mut hl = Some(hl_colors(v)); + glib::idle_add(move || { + let (bg, fg) = hl.take().unwrap(); + let mut state = state.borrow_mut(); + cb(&mut *state, bg, fg); + glib::Continue(false) + }); + }) + .call(); } } @@ -28,45 +78,38 @@ pub struct Pmenu { } impl Pmenu { - pub fn new(nvim: &mut Neovim) -> Self { - let (bg, fg) = get_hl_colors(nvim, "Pmenu"); - let (bg_sel, fg_sel) = get_hl_colors(nvim, "PmenuSel"); - + pub fn new() -> Self { Pmenu { - bg, - fg, - bg_sel, - fg_sel, + bg: None, + fg: None, + bg_sel: None, + fg_sel: None, } } } fn get_hl_color(map: &HashMap<&str, &Value>, color_name: &str) -> Option { - if let Some(col) = map.get(color_name) { - if let Some(col) = col.as_u64() { - Some(Color::from_indexed_color(col)) - } else { - None - } - } else { - None - } + map.get(color_name) + .and_then(|col| col.as_u64()) + .map(Color::from_indexed_color) } -fn get_hl_colors(nvim: &mut Neovim, hl: &str) -> (Option, Option) { - nvim.get_hl_by_name(hl, true) - .ok_and_report() - .and_then(|m| if let Some(m) = m.to_attrs_map_report() { - let reverse = m.get("reverse").and_then(|v| v.as_bool()).unwrap_or(false); - let bg = get_hl_color(&m, "background"); - let fg = get_hl_color(&m, "foreground"); - if reverse { - Some((fg, bg)) +fn hl_colors(hl: Result, CallError>) -> (Option, Option) { + hl.ok_and_report() + .and_then(|m| { + if let Some(m) = m.to_attrs_map_report() { + let reverse = m.get("reverse").and_then(|v| v.as_bool()).unwrap_or(false); + let bg = get_hl_color(&m, "background"); + let fg = get_hl_color(&m, "foreground"); + if reverse { + Some((fg, bg)) + } else { + Some((bg, fg)) + } } else { - Some((bg, fg)) + None } - } else { - None }) .unwrap_or((None, None)) } +