Retrive theme color as async task

This will prevent lock of ui in case of neovim slowdown and in case of
errors. Also speedup starting.
This commit is contained in:
daa 2018-04-07 21:18:06 +03:00
parent ddc2d36b17
commit d8d33edb19
3 changed files with 109 additions and 67 deletions

View File

@ -1,5 +1,7 @@
use std; use std;
use gdk; use gdk;
use ui_model::Cell; use ui_model::Cell;
use theme::Theme; 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_WHITE: Color = Color(1.0, 1.0, 1.0);
pub const COLOR_RED: Color = Color(1.0, 0.0, 0.0); pub const COLOR_RED: Color = Color(1.0, 0.0, 0.0);
impl<'a> Into<gdk::RGBA> for &'a Color { impl From<Color> for gdk::RGBA {
fn into(self) -> gdk::RGBA { fn from(color: Color) -> Self {
gdk::RGBA { gdk::RGBA {
red: self.0, red: color.0,
green: self.1, green: color.1,
blue: self.2, blue: color.2,
alpha: 1.0, alpha: 1.0,
} }
} }
@ -101,39 +103,36 @@ impl ColorModel {
cell.attrs.special.as_ref().unwrap_or(&self.sp_color) cell.attrs.special.as_ref().unwrap_or(&self.sp_color)
} }
pub fn pmenu_bg(&self) -> &Color { pub fn pmenu_bg<'a>(&'a self) -> Color {
if let Some(ref pmenu) = self.theme.pmenu { self.theme
pmenu.bg.as_ref().unwrap_or(&self.bg_color) .pmenu()
} else { .bg
&self.bg_color .clone()
} .unwrap_or_else(|| self.bg_color.clone())
} }
pub fn pmenu_fg(&self) -> Color {
pub fn pmenu_fg(&self) -> &Color { self.theme
if let Some(ref pmenu) = self.theme.pmenu { .pmenu()
pmenu.fg.as_ref().unwrap_or(&self.fg_color) .fg
} else { .clone()
&self.fg_color .unwrap_or_else(|| self.fg_color.clone())
}
} }
pub fn pmenu_bg_sel(&self) -> Color {
pub fn pmenu_bg_sel(&self) -> &Color { self.theme
if let Some(ref pmenu) = self.theme.pmenu { .pmenu()
pmenu.bg_sel.as_ref().unwrap_or(&self.bg_color) .bg_sel
} else { .clone()
&self.bg_color .unwrap_or_else(|| self.bg_color.clone())
}
} }
pub fn pmenu_fg_sel(&self) -> Color {
pub fn pmenu_fg_sel(&self) -> &Color { self.theme
if let Some(ref pmenu) = self.theme.pmenu { .pmenu()
pmenu.fg_sel.as_ref().unwrap_or(&self.fg_color) .fg_sel
} else { .clone()
&self.fg_color .unwrap_or_else(|| self.fg_color.clone())
}
} }
} }

View File

@ -1181,7 +1181,7 @@ impl State {
if let Some(mut nvim) = self.nvim.nvim() { if let Some(mut nvim) = self.nvim.nvim() {
let mut render_state = self.render_state.borrow_mut(); 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 RepaintMode::Nothing
} }

View File

@ -1,22 +1,72 @@
use std::collections::HashMap; 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 nvim::ErrorReport;
use color::Color; use color::Color;
use value::ValueMapExt; use value::ValueMapExt;
struct State {
pmenu: Pmenu,
}
impl State {
fn new() -> Self {
State {
pmenu: Pmenu::new(),
}
}
}
pub struct Theme { pub struct Theme {
pub pmenu: Option<Pmenu>, state: Arc<UiMutex<State>>,
} }
impl Theme { impl Theme {
pub fn new() -> Self { pub fn new() -> Self {
Theme { pmenu: None } Theme {
state: Arc::new(UiMutex::new(State::new())),
}
} }
pub fn update(&mut self, nvim: &mut Neovim) { pub fn pmenu(&self) -> Ref<Pmenu> {
self.pmenu = Some(Pmenu::new(nvim)); 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<CB>(&self, nvim: &mut Neovim, hl_name: &str, mut cb: CB)
where
CB: FnMut(&mut State, Option<Color>, Option<Color>) + 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 { impl Pmenu {
pub fn new(nvim: &mut Neovim) -> Self { pub fn new() -> Self {
let (bg, fg) = get_hl_colors(nvim, "Pmenu");
let (bg_sel, fg_sel) = get_hl_colors(nvim, "PmenuSel");
Pmenu { Pmenu {
bg, bg: None,
fg, fg: None,
bg_sel, bg_sel: None,
fg_sel, fg_sel: None,
} }
} }
} }
fn get_hl_color(map: &HashMap<&str, &Value>, color_name: &str) -> Option<Color> { fn get_hl_color(map: &HashMap<&str, &Value>, color_name: &str) -> Option<Color> {
if let Some(col) = map.get(color_name) { map.get(color_name)
if let Some(col) = col.as_u64() { .and_then(|col| col.as_u64())
Some(Color::from_indexed_color(col)) .map(Color::from_indexed_color)
} else {
None
}
} else {
None
}
} }
fn get_hl_colors(nvim: &mut Neovim, hl: &str) -> (Option<Color>, Option<Color>) { fn hl_colors(hl: Result<Vec<(Value, Value)>, CallError>) -> (Option<Color>, Option<Color>) {
nvim.get_hl_by_name(hl, true) hl.ok_and_report()
.ok_and_report() .and_then(|m| {
.and_then(|m| if let Some(m) = m.to_attrs_map_report() { if let Some(m) = m.to_attrs_map_report() {
let reverse = m.get("reverse").and_then(|v| v.as_bool()).unwrap_or(false); let reverse = m.get("reverse").and_then(|v| v.as_bool()).unwrap_or(false);
let bg = get_hl_color(&m, "background"); let bg = get_hl_color(&m, "background");
let fg = get_hl_color(&m, "foreground"); let fg = get_hl_color(&m, "foreground");
if reverse { if reverse {
Some((fg, bg)) Some((fg, bg))
} else {
Some((bg, fg))
}
} else { } else {
Some((bg, fg)) None
} }
} else {
None
}) })
.unwrap_or((None, None)) .unwrap_or((None, None))
} }