diff options
author | Ville Hakulinen <ville.hakulinen@gmail.com> | 2020-06-30 23:16:12 +0300 |
---|---|---|
committer | Ville Hakulinen <ville.hakulinen@gmail.com> | 2020-07-03 15:18:55 +0300 |
commit | d6e8fda114ca5233b0bc490d935d49f7f677ba97 (patch) | |
tree | c09b546877a97d1a3ae5f21b3ac1b17c78e3da78 | |
parent | f2d0ffab68f770897053e50fa36d2d19e3017727 (diff) |
Move uistate into its own file
-rw-r--r-- | src/ui/cmdline.rs | 2 | ||||
-rw-r--r-- | src/ui/color.rs | 25 | ||||
-rw-r--r-- | src/ui/grid/grid.rs | 2 | ||||
-rw-r--r-- | src/ui/grid/render.rs | 2 | ||||
-rw-r--r-- | src/ui/mod.rs | 1 | ||||
-rw-r--r-- | src/ui/popupmenu/popupmenu.rs | 2 | ||||
-rw-r--r-- | src/ui/state.rs | 510 | ||||
-rw-r--r-- | src/ui/tabline.rs | 2 | ||||
-rw-r--r-- | src/ui/ui.rs | 526 | ||||
-rw-r--r-- | src/ui/wildmenu.rs | 2 |
10 files changed, 547 insertions, 527 deletions
diff --git a/src/ui/cmdline.rs b/src/ui/cmdline.rs index c403450..2c5df2c 100644 --- a/src/ui/cmdline.rs +++ b/src/ui/cmdline.rs @@ -3,9 +3,9 @@ use gtk::prelude::*; use crate::nvim_bridge; use crate::nvim_gio::GioNeovim; +use crate::ui::color::HlDefs; use crate::ui::common::calc_line_space; use crate::ui::font::{Font, FontUnit}; -use crate::ui::ui::HlDefs; use crate::ui::wildmenu::Wildmenu; const MAX_WIDTH: i32 = 650; diff --git a/src/ui/color.rs b/src/ui/color.rs index ba2e7b8..f677bc7 100644 --- a/src/ui/color.rs +++ b/src/ui/color.rs @@ -1,5 +1,30 @@ +use std::collections::HashMap; + use glib; +#[derive(Default)] +pub struct HlDefs { + hl_defs: HashMap<u64, Highlight>, + + pub default_fg: Color, + pub default_bg: Color, + pub default_sp: Color, +} + +impl HlDefs { + pub fn get_mut(&mut self, id: &u64) -> Option<&mut Highlight> { + self.hl_defs.get_mut(id) + } + + pub fn get(&self, id: &u64) -> Option<&Highlight> { + self.hl_defs.get(id) + } + + pub fn insert(&mut self, id: u64, hl: Highlight) -> Option<Highlight> { + self.hl_defs.insert(id, hl) + } +} + #[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Highlight { pub foreground: Option<Color>, diff --git a/src/ui/grid/grid.rs b/src/ui/grid/grid.rs index f66a527..1e6a29b 100644 --- a/src/ui/grid/grid.rs +++ b/src/ui/grid/grid.rs @@ -12,11 +12,11 @@ use gtk::{DrawingArea, EventBox}; use gtk::prelude::*; use crate::nvim_bridge::{GridLineSegment, ModeInfo}; +use crate::ui::color::HlDefs; use crate::ui::font::Font; use crate::ui::grid::context::Context; use crate::ui::grid::render; use crate::ui::grid::row::Row; -use crate::ui::ui::HlDefs; pub enum ScrollDirection { Up, diff --git a/src/ui/grid/render.rs b/src/ui/grid/render.rs index 62f5dbb..721cca7 100644 --- a/src/ui/grid/render.rs +++ b/src/ui/grid/render.rs @@ -7,9 +7,9 @@ use pangocairo; use crate::nvim_bridge::GridLineSegment; use crate::ui::color::Highlight; +use crate::ui::color::HlDefs; use crate::ui::grid::context::{CellMetrics, Context}; use crate::ui::grid::row::{Cell, Segment}; -use crate::ui::ui::HlDefs; /// Renders text to `cr`. /// diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 96a20ee..05695b1 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -55,6 +55,7 @@ mod cursor_tooltip; mod font; mod grid; mod popupmenu; +mod state; mod tabline; mod ui; mod wildmenu; diff --git a/src/ui/popupmenu/popupmenu.rs b/src/ui/popupmenu/popupmenu.rs index a9c3015..f015dff 100644 --- a/src/ui/popupmenu/popupmenu.rs +++ b/src/ui/popupmenu/popupmenu.rs @@ -8,6 +8,7 @@ use pango; use crate::nvim_bridge::{CompletionItem, PmenuColors}; use crate::nvim_gio::GioNeovim; +use crate::ui::color::HlDefs; use crate::ui::common::{ calc_line_space, get_preferred_horizontal_position, get_preferred_vertical_position, spawn_local, @@ -15,7 +16,6 @@ use crate::ui::common::{ use crate::ui::font::{Font, FontUnit}; use crate::ui::popupmenu::get_icon_pixbuf; use crate::ui::popupmenu::LazyLoader; -use crate::ui::ui::HlDefs; /// Maximum height of completion menu. const MAX_HEIGHT: i32 = 500; diff --git a/src/ui/state.rs b/src/ui/state.rs new file mode 100644 index 0000000..cc388bd --- /dev/null +++ b/src/ui/state.rs @@ -0,0 +1,510 @@ +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +use glib; +use gtk; +use gtk::prelude::*; + +use log::{debug, error}; +use nvim_rs::Tabpage; + +use crate::nvim_bridge::{ + CmdlinePos, CmdlineSpecialChar, DefaultColorsSet, GnvimEvent, + GridCursorGoto, GridResize, HlAttrDefine, ModeChange, ModeInfo, + ModeInfoSet, Notify, OptionSet, RedrawEvent, TablineUpdate, +}; +use crate::nvim_gio::GioNeovim; +use crate::ui::cmdline::Cmdline; +use crate::ui::color::HlDefs; +use crate::ui::common::spawn_local; +#[cfg(feature = "libwebkit2gtk")] +use crate::ui::cursor_tooltip::{CursorTooltip, Gravity}; +use crate::ui::font::Font; +use crate::ui::grid::Grid; +use crate::ui::popupmenu::Popupmenu; +use crate::ui::tabline::Tabline; + +pub(crate) type Grids = HashMap<u64, Grid>; + +pub(crate) struct ResizeOptions { + pub font: Font, + pub line_space: i64, +} + +/// Internal structure for `UI` to work on. +pub(crate) struct UIState { + /// All grids currently in the UI. + pub grids: Grids, + /// Highlight definitions. + pub hl_defs: HlDefs, + /// Mode infos. When a mode is activated, the activated mode is passed + /// to the gird(s). + pub mode_infos: Vec<ModeInfo>, + /// Id of the current active grid. + pub current_grid: u64, + + pub popupmenu: Popupmenu, + pub cmdline: Cmdline, + pub tabline: Tabline, + #[cfg(feature = "libwebkit2gtk")] + pub cursor_tooltip: CursorTooltip, + + /// Overlay contains our grid(s) and popupmenu. + #[allow(unused)] + pub overlay: gtk::Overlay, + + /// Source id for delayed call to ui_try_resize. + pub resize_source_id: Rc<RefCell<Option<glib::SourceId>>>, + /// Resize options that is some if a resize should be send to nvim on flush. + pub resize_on_flush: Option<ResizeOptions>, +} + +impl UIState { + pub fn handle_notify( + &mut self, + window: >k::ApplicationWindow, + notify: &Notify, + nvim: &GioNeovim, + ) { + match notify { + Notify::RedrawEvent(events) => { + events.iter().for_each(|e| { + self.handle_redraw_event(window, e, &nvim); + }); + } + Notify::GnvimEvent(event) => match event { + Ok(event) => self.handle_gnvim_event(event, nvim), + Err(err) => { + let nvim = nvim.clone(); + let msg = format!( + "echom \"Failed to parse gnvim notify: '{}'\"", + err + ); + spawn_local(async move { + if let Err(err) = nvim.command(&msg).await { + error!("Failed to execute nvim command: {}", err) + } + }); + } + }, + } + } + + fn handle_gnvim_event(&mut self, event: &GnvimEvent, nvim: &GioNeovim) { + match event { + GnvimEvent::SetGuiColors(colors) => { + self.popupmenu.set_colors(colors.pmenu, &self.hl_defs); + self.tabline.set_colors(colors.tabline, &self.hl_defs); + self.cmdline.set_colors(colors.cmdline, &self.hl_defs); + self.cmdline + .wildmenu_set_colors(&colors.wildmenu, &self.hl_defs); + } + GnvimEvent::CompletionMenuToggleInfo => { + self.popupmenu.toggle_show_info() + } + GnvimEvent::PopupmenuWidth(width) => { + self.popupmenu.set_width(*width as i32); + } + GnvimEvent::PopupmenuWidthDetails(width) => { + self.popupmenu.set_width_details(*width as i32); + } + GnvimEvent::PopupmenuShowMenuOnAllItems(should_show) => { + self.popupmenu.set_show_menu_on_all_items(*should_show); + } + GnvimEvent::Unknown(msg) => { + debug!("Received unknown GnvimEvent: {}", msg); + } + + #[cfg(not(feature = "libwebkit2gtk"))] + GnvimEvent::CursorTooltipLoadStyle(..) + | GnvimEvent::CursorTooltipShow(..) + | GnvimEvent::CursorTooltipHide + | GnvimEvent::CursorTooltipSetStyle(..) => { + let nvim = nvim.clone(); + let msg = + "echom \"Cursor tooltip not supported in this build\""; + spawn_local(async move { + if let Err(err) = nvim.command(&msg).await { + error!("Failed to execute nvim command: {}", err) + } + }); + } + + #[cfg(feature = "libwebkit2gtk")] + GnvimEvent::CursorTooltipLoadStyle(..) + | GnvimEvent::CursorTooltipShow(..) + | GnvimEvent::CursorTooltipHide + | GnvimEvent::CursorTooltipSetStyle(..) => match event { + GnvimEvent::CursorTooltipLoadStyle(path) => { + if let Err(err) = + self.cursor_tooltip.load_style(path.clone()) + { + let msg = format!( + "echom \"Cursor tooltip load style failed: '{}'\"", + err + ); + let nvim = nvim.clone(); + spawn_local(async move { + if let Err(err) = nvim.command(&msg).await { + error!( + "Failed to execute nvim command: {}", + err + ) + } + }); + } + } + GnvimEvent::CursorTooltipShow(content, row, col) => { + self.cursor_tooltip.show(content.clone()); + + let grid = self.grids.get(&self.current_grid).unwrap(); + let rect = grid.get_rect_for_cell(*row, *col); + + self.cursor_tooltip.move_to(&rect); + } + GnvimEvent::CursorTooltipHide => self.cursor_tooltip.hide(), + GnvimEvent::CursorTooltipSetStyle(style) => { + self.cursor_tooltip.set_style(style) + } + _ => unreachable!(), + }, + } + } + + fn handle_redraw_event( + &mut self, + window: >k::ApplicationWindow, + event: &RedrawEvent, + nvim: &GioNeovim, + ) { + match event { + RedrawEvent::SetTitle(evt) => { + evt.iter().for_each(|title| { + window.set_title(title); + }); + } + RedrawEvent::GridLine(evt) => { + evt.iter().for_each(|line| { + let grid = self.grids.get(&line.grid).unwrap(); + grid.put_line(line, &self.hl_defs); + }); + } + RedrawEvent::GridCursorGoto(evt) => { + evt.iter().for_each( + |GridCursorGoto { + grid: grid_id, + row, + col, + }| { + // Gird cursor goto sets the current cursor to grid_id, + // so we'll need to handle that here... + let grid = if *grid_id != self.current_grid { + // ...so if the grid_id is not same as the self tells us, + // set the previous current grid to inactive self. + self.grids + .get(&self.current_grid) + .unwrap() + .set_active(false); + self.current_grid = *grid_id; + + // And set the new current grid to active. + let grid = self.grids.get(grid_id).unwrap(); + grid.set_active(true); + grid + } else { + self.grids.get(grid_id).unwrap() + }; + + // And after all that, set the current grid's cursor position. + grid.cursor_goto(*row, *col); + }, + ); + } + RedrawEvent::GridResize(evt) => { + evt.iter().for_each( + |GridResize { + grid, + width, + height, + }| { + let grid = self.grids.get(grid).unwrap(); + grid.resize(*width, *height); + }, + ); + } + RedrawEvent::GridClear(evt) => { + evt.iter().for_each(|grid| { + let grid = self.grids.get(grid).unwrap(); + grid.clear(&self.hl_defs); + }); + } + RedrawEvent::GridScroll(evt) => { + evt.iter().for_each(|info| { + let grid = self.grids.get(&info.grid).unwrap(); + grid.scroll(info.reg, info.rows, info.cols, &self.hl_defs); + + // Since nvim doesn't have its own 'scroll' autocmd, we'll + // have to do it on our own. This use useful for the cursor tooltip. + let nvim = nvim.clone(); + spawn_local(async move { + if let Err(err) = nvim.command("if exists('#User#GnvimScroll') | doautocmd User GnvimScroll | endif").await { + error!("GnvimScroll error: {:?}", err); + } + }); + }); + } + RedrawEvent::DefaultColorsSet(evt) => { + evt.iter().for_each(|DefaultColorsSet { fg, bg, sp }| { + self.hl_defs.default_fg = *fg; + self.hl_defs.default_bg = *bg; + self.hl_defs.default_sp = *sp; + + { + // NOTE(ville): Not sure if these are actually needed. + let hl = self.hl_defs.get_mut(&0).unwrap(); + hl.foreground = Some(*fg); + hl.background = Some(*bg); + hl.special = Some(*sp); + } + + for grid in self.grids.values() { + grid.redraw(&self.hl_defs); + } + + #[cfg(feature = "libwebkit2gtk")] + self.cursor_tooltip.set_colors(*fg, *bg); + }); + } + RedrawEvent::HlAttrDefine(evt) => { + evt.iter().for_each(|HlAttrDefine { id, hl }| { + self.hl_defs.insert(*id, *hl); + }); + } + RedrawEvent::OptionSet(evt) => { + evt.iter().for_each(|opt| match opt { + OptionSet::GuiFont(font) => { + let font = + Font::from_guifont(font).unwrap_or(Font::default()); + + let mut opts = + self.resize_on_flush.take().unwrap_or_else(|| { + let grid = self.grids.get(&1).unwrap(); + ResizeOptions { + font: grid.get_font(), + line_space: grid.get_line_space(), + } + }); + + opts.font = font; + + self.resize_on_flush = Some(opts); + } + OptionSet::LineSpace(val) => { + let mut opts = + self.resize_on_flush.take().unwrap_or_else(|| { + let grid = self.grids.get(&1).unwrap(); + ResizeOptions { + font: grid.get_font(), + line_space: grid.get_line_space(), + } + }); + + opts.line_space = *val; + + self.resize_on_flush = Some(opts); + } + OptionSet::NotSupported(name) => { + debug!("Not supported option set: {}", name); + } + }); + } + RedrawEvent::ModeInfoSet(evt) => { + evt.iter().for_each(|ModeInfoSet { mode_info, .. }| { + self.mode_infos = mode_info.clone(); + }); + } + RedrawEvent::ModeChange(evt) => { + evt.iter().for_each(|ModeChange { index, .. }| { + let mode = self.mode_infos.get(*index as usize).unwrap(); + // Broadcast the mode change to all grids. + // TODO(ville): It might be enough to just set the mode to the + // current active grid. + for grid in self.grids.values() { + grid.set_mode(mode); + } + }); + } + RedrawEvent::SetBusy(busy) => { + for grid in self.grids.values() { + grid.set_busy(*busy); + } + } + RedrawEvent::Flush() => { + for grid in self.grids.values() { + grid.flush(&self.hl_defs); + } + + if let Some(opts) = self.resize_on_flush.take() { + for grid in self.grids.values() { + grid.update_cell_metrics( + opts.font.clone(), + opts.line_space, + ); + } + + let grid = self.grids.get(&1).unwrap(); + let (cols, rows) = grid.calc_size(); + + // Cancel any possible delayed call for ui_try_resize. + let mut id = self.resize_source_id.borrow_mut(); + if let Some(id) = id.take() { + glib::source::source_remove(id); + } + + let nvim = nvim.clone(); + spawn_local(async move { + if let Err(err) = + nvim.ui_try_resize(cols as i64, rows as i64).await + { + error!("Error: failed to resize nvim on line space change ({:?})", err); + } + }); + + self.popupmenu.set_font(opts.font.clone(), &self.hl_defs); + self.cmdline.set_font(opts.font.clone(), &self.hl_defs); + self.tabline.set_font(opts.font.clone(), &self.hl_defs); + #[cfg(feature = "libwebkit2gtk")] + self.cursor_tooltip.set_font(opts.font.clone()); + + self.cmdline.set_line_space(opts.line_space); + self.popupmenu + .set_line_space(opts.line_space, &self.hl_defs); + self.tabline.set_line_space(opts.line_space, &self.hl_defs); + } + } + RedrawEvent::PopupmenuShow(evt) => { + evt.iter().for_each(|popupmenu| { + self.popupmenu + .set_items(popupmenu.items.clone(), &self.hl_defs); + + let grid = self.grids.get(&self.current_grid).unwrap(); + let rect = + grid.get_rect_for_cell(popupmenu.row, popupmenu.col); + + self.popupmenu.set_anchor(rect); + self.popupmenu + .select(popupmenu.selected as i32, &self.hl_defs); + + self.popupmenu.show(); + + // If the cursor tooltip is visible at the same time, move + // it out of our way. + #[cfg(feature = "libwebkit2gtk")] + { + if self.cursor_tooltip.is_visible() { + if self.popupmenu.is_above_anchor() { + self.cursor_tooltip + .force_gravity(Some(Gravity::Down)); + } else { + self.cursor_tooltip + .force_gravity(Some(Gravity::Up)); + } + + self.cursor_tooltip.refresh_position(); + } + } + }); + } + RedrawEvent::PopupmenuHide() => { + self.popupmenu.hide(); + + // Undo any force positioning of cursor tool tip that might + // have occured on popupmenu show. + #[cfg(feature = "libwebkit2gtk")] + { + self.cursor_tooltip.force_gravity(None); + self.cursor_tooltip.refresh_position(); + } + } + RedrawEvent::PopupmenuSelect(evt) => { + evt.iter().for_each(|selected| { + self.popupmenu.select(*selected as i32, &self.hl_defs); + }); + } + RedrawEvent::TablineUpdate(evt) => { + evt.iter().for_each(|TablineUpdate { current, tabs }| { + let current = Tabpage::new(current.clone(), nvim.clone()); + let tabs = tabs + .iter() + .map(|v| { + ( + Tabpage::new(v.0.clone(), nvim.clone()), + v.1.clone(), + ) + }) + .collect(); + self.tabline.update(current, tabs); + }); + } + RedrawEvent::CmdlineShow(evt) => { + evt.iter().for_each(|cmdline_show| { + self.cmdline.show(cmdline_show, &self.hl_defs); + }); + } + RedrawEvent::CmdlineHide() => { + self.cmdline.hide(); + } + RedrawEvent::CmdlinePos(evt) => { + evt.iter().for_each(|CmdlinePos { pos, level }| { + self.cmdline.set_pos(*pos, *level); + }); + } + RedrawEvent::CmdlineSpecialChar(evt) => { + evt.iter().for_each( + |CmdlineSpecialChar { + character: ch, + shift, + level, + }| { + self.cmdline.show_special_char( + ch.clone(), + *shift, + *level, + ); + }, + ); + } + RedrawEvent::CmdlineBlockShow(evt) => { + evt.iter().for_each(|show| { + self.cmdline.show_block(show, &self.hl_defs); + }); + } + RedrawEvent::CmdlineBlockAppend(evt) => { + evt.iter().for_each(|line| { + self.cmdline.block_append(line, &self.hl_defs); + }); + } + RedrawEvent::CmdlineBlockHide() => { + self.cmdline.hide_block(); + } + RedrawEvent::WildmenuShow(evt) => { + evt.iter().for_each(|items| { + self.cmdline.wildmenu_show(&items.0); + }); + } + RedrawEvent::WildmenuHide() => { + self.cmdline.wildmenu_hide(); + } + RedrawEvent::WildmenuSelect(evt) => { + evt.iter().for_each(|item| { + self.cmdline.wildmenu_select(*item); + }); + } + RedrawEvent::Ignored(_) => (), + RedrawEvent::Unknown(e) => { + debug!("Received unknown redraw event: {}", e); + } + } + } +} diff --git a/src/ui/tabline.rs b/src/ui/tabline.rs index 0d360d6..22f33ee 100644 --- a/src/ui/tabline.rs +++ b/src/ui/tabline.rs @@ -10,9 +10,9 @@ use nvim_rs::Tabpage; use crate::nvim_bridge; use crate::nvim_gio::{GioNeovim, GioWriter}; +use crate::ui::color::HlDefs; use crate::ui::common::{calc_line_space, spawn_local}; use crate::ui::font::{Font, FontUnit}; -use crate::ui::ui::HlDefs; pub struct Tabline { notebook: gtk::Notebook, diff --git a/src/ui/ui.rs b/src/ui/ui.rs index d8e18be..b56e6db 100644 --- a/src/ui/ui.rs +++ b/src/ui/ui.rs @@ -8,83 +8,22 @@ use gtk; use gtk::prelude::*; use log::{debug, error}; -use nvim_rs::Tabpage; use rmpv::Value; use crate::nvim_bridge::{ - CmdlinePos, CmdlineSpecialChar, DefaultColorsSet, GnvimEvent, - GridCursorGoto, GridResize, HlAttrDefine, Message, ModeChange, ModeInfo, - ModeInfoSet, Notify, OptionSet, RedrawEvent, Request, TablineUpdate, + Message, Request, }; use crate::nvim_gio::GioNeovim; use crate::ui::cmdline::Cmdline; -use crate::ui::color::{Color, Highlight}; +use crate::ui::color::{Highlight, HlDefs}; use crate::ui::common::spawn_local; #[cfg(feature = "libwebkit2gtk")] -use crate::ui::cursor_tooltip::{CursorTooltip, Gravity}; -use crate::ui::font::Font; +use crate::ui::cursor_tooltip::CursorTooltip; use crate::ui::grid::Grid; use crate::ui::popupmenu::Popupmenu; +use crate::ui::state::UIState; use crate::ui::tabline::Tabline; -type Grids = HashMap<u64, Grid>; - -#[derive(Default)] -pub struct HlDefs { - hl_defs: HashMap<u64, Highlight>, - - pub default_fg: Color, - pub default_bg: Color, - pub default_sp: Color, -} - -impl HlDefs { - pub fn get_mut(&mut self, id: &u64) -> Option<&mut Highlight> { - self.hl_defs.get_mut(id) - } - - pub fn get(&self, id: &u64) -> Option<&Highlight> { - self.hl_defs.get(id) - } - - pub fn insert(&mut self, id: u64, hl: Highlight) -> Option<Highlight> { - self.hl_defs.insert(id, hl) - } -} - -struct ResizeOptions { - font: Font, - line_space: i64, -} - -/// Internal structure for `UI` to work on. -struct UIState { - /// All grids currently in the UI. - grids: Grids, - /// Highlight definitions. - hl_defs: HlDefs, - /// Mode infos. When a mode is activated, the activated mode is passed - /// to the gird(s). - mode_infos: Vec<ModeInfo>, - /// Id of the current active grid. - current_grid: u64, - - popupmenu: Popupmenu, - cmdline: Cmdline, - tabline: Tabline, - #[cfg(feature = "libwebkit2gtk")] - cursor_tooltip: CursorTooltip, - - /// Overlay contains our grid(s) and popupmenu. - #[allow(unused)] - overlay: gtk::Overlay, - - /// Source id for delayed call to ui_try_resize. - resize_source_id: Rc<RefCell<Option<glib::SourceId>>>, - /// Resize options that is some if a resize should be send to nvim on flush. - resize_on_flush: Option<ResizeOptions>, -} - /// Main UI structure. pub struct UI { /// Main window. @@ -341,7 +280,7 @@ impl UI { Message::Notify(notify) => { let mut state = state.borrow_mut(); - handle_notify(&win, ¬ify, &mut state, &nvim); + state.handle_notify(&win, ¬ify, &nvim); } // Handle a request. Message::Request(tx, request) => { @@ -382,461 +321,6 @@ fn handle_request( } } -fn handle_notify( - window: >k::ApplicationWindow, - notify: &Notify, - state: &mut UIState, - nvim: &GioNeovim, -) { - match notify { - Notify::RedrawEvent(events) => { - handle_redraw_event(window, events, state, &nvim); - } - Notify::GnvimEvent(event) => match event { - Ok(event) => handle_gnvim_event(event, state, nvim), - Err(err) => { - let nvim = nvim.clone(); - let msg = format!( - "echom \"Failed to parse gnvim notify: '{}'\"", - err - ); - spawn_local(async move { - if let Err(err) = nvim.command(&msg).await { - error!("Failed to execute nvim command: {}", err) - } - }); - } - }, - } -} - -fn handle_gnvim_event( - event: &GnvimEvent, - state: &mut UIState, - nvim: &GioNeovim, -) { - match event { - GnvimEvent::SetGuiColors(colors) => { - state.popupmenu.set_colors(colors.pmenu, &state.hl_defs); - state.tabline.set_colors(colors.tabline, &state.hl_defs); - state.cmdline.set_colors(colors.cmdline, &state.hl_defs); - state - .cmdline - .wildmenu_set_colors(&colors.wildmenu, &state.hl_defs); - } - GnvimEvent::CompletionMenuToggleInfo => { - state.popupmenu.toggle_show_info() - } - GnvimEvent::PopupmenuWidth(width) => { - state.popupmenu.set_width(*width as i32); - } - GnvimEvent::PopupmenuWidthDetails(width) => { - state.popupmenu.set_width_details(*width as i32); - } - GnvimEvent::PopupmenuShowMenuOnAllItems(should_show) => { - state.popupmenu.set_show_menu_on_all_items(*should_show); - } - GnvimEvent::Unknown(msg) => { - debug!("Received unknown GnvimEvent: {}", msg); - } - - #[cfg(not(feature = "libwebkit2gtk"))] - GnvimEvent::CursorTooltipLoadStyle(..) - | GnvimEvent::CursorTooltipShow(..) - | GnvimEvent::CursorTooltipHide - | GnvimEvent::CursorTooltipSetStyle(..) => { - let nvim = nvim.clone(); - let msg = "echom \"Cursor tooltip not supported in this build\""; - spawn_local(async move { - if let Err(err) = nvim.command(&msg).await { - error!("Failed to execute nvim command: {}", err) - } - }); - } - - #[cfg(feature = "libwebkit2gtk")] - GnvimEvent::CursorTooltipLoadStyle(..) - | GnvimEvent::CursorTooltipShow(..) - | GnvimEvent::CursorTooltipHide - | GnvimEvent::CursorTooltipSetStyle(..) => match event { - GnvimEvent::CursorTooltipLoadStyle(path) => { - if let Err(err) = state.cursor_tooltip.load_style(path.clone()) - { - let msg = format!( - "echom \"Cursor tooltip load style failed: '{}'\"", - err - ); - let nvim = nvim.clone(); - spawn_local(async move { - if let Err(err) = nvim.command(&msg).await { - error!("Failed to execute nvim command: {}", err) - } - }); - } - } - GnvimEvent::CursorTooltipShow(content, row, col) => { - state.cursor_tooltip.show(content.clone()); - - let grid = state.grids.get(&state.current_grid).unwrap(); - let rect = grid.get_rect_for_cell(*row, *col); - - state.cursor_tooltip.move_to(&rect); - } - GnvimEvent::CursorTooltipHide => state.cursor_tooltip.hide(), - GnvimEvent::CursorTooltipSetStyle(style) => { - state.cursor_tooltip.set_style(style) - } - _ => unreachable!(), - }, - } -} - -fn handle_redraw_event( - window: >k::ApplicationWindow, - events: &Vec<RedrawEvent>, - state: &mut UIState, - nvim: &GioNeovim, -) { - for event in events { - match event { - RedrawEvent::SetTitle(evt) => { - evt.iter().for_each(|title| { - window.set_title(title); - }); - } - RedrawEvent::GridLine(evt) => { - evt.iter().for_each(|line| { - let grid = state.grids.get(&line.grid).unwrap(); - grid.put_line(line, &state.hl_defs); - }); - } - RedrawEvent::GridCursorGoto(evt) => { - evt.iter().for_each( - |GridCursorGoto { - grid: grid_id, - row, - col, - }| { - // Gird cursor goto sets the current cursor to grid_id, - // so we'll need to handle that here... - let grid = if *grid_id != state.current_grid { - // ...so if the grid_id is not same as the state tells us, - // set the previous current grid to inactive state. - state - .grids - .get(&state.current_grid) - .unwrap() - .set_active(false); - state.current_grid = *grid_id; - - // And set the new current grid to active. - let grid = state.grids.get(grid_id).unwrap(); - grid.set_active(true); - grid - } else { - state.grids.get(grid_id).unwrap() - }; - - // And after all that, set the current grid's cursor position. - grid.cursor_goto(*row, *col); - }, - ); - } - RedrawEvent::GridResize(evt) => { - evt.iter().for_each( - |GridResize { - |