diff --git a/README.md b/README.md index e98b98b..7b02ba9 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,14 @@ call rpcnotify(1, 'Gui', 'Font', 'DejaVu Sans Mono 12') ``` # Command line -As this project uses gtk-rs, custom option by GtkApplication not supported yet. -There is workaround to pass nvim execution path. +* pass nvim custom execution path (by default used `nvim` command) ``` cargo run -- --nvim-bin-path=E:\Neovim\bin\nvim.exe ``` +* enable external popup menu autocompletion menu (this function a bit limited, so disabled by default) +``` +cargo run -- --enable-external-popup +``` # Build ## Linux diff --git a/src/input.rs b/src/input.rs index 31d9e7a..cd553b8 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,7 +1,9 @@ +use gtk::prelude::*; use gdk; use gdk::EventKey; use phf; +use neovim_lib::{Neovim, NeovimApi}; use std::ascii::AsciiExt; @@ -74,3 +76,14 @@ pub fn convert_key(ev: &EventKey) -> Option { None } } + +pub fn gtk_key_press(nvim: &mut Neovim, ev: &EventKey) -> Inhibit { + if let Some(input) = convert_key(ev) { + debug!("nvim_input -> {}", input); + nvim.input(&input) + .expect("Error run input command to nvim"); + Inhibit(true) + } else { + Inhibit(false) + } +} diff --git a/src/main.rs b/src/main.rs index 237632a..b097df2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ mod input; mod settings; mod cursor; mod shell_dlg; +mod popup_menu; use std::env; use gio::ApplicationExt; @@ -29,6 +30,7 @@ use gio::ApplicationExt; use ui::Ui; const BIN_PATH_ARG: &'static str = "--nvim-bin-path"; +const ENABLE_EXTERNAL_POPUP: &'static str = "--enable-external-popup"; fn main() { env_logger::init().expect("Can't initialize env_logger"); @@ -41,6 +43,7 @@ fn main() { let args: Vec = env::args().collect(); let mut argv: Vec<&str> = args.iter() .filter(|a| !a.starts_with(BIN_PATH_ARG)) + .filter(|a| !a.starts_with(ENABLE_EXTERNAL_POPUP)) .map(String::as_str) .collect(); if open_arg().is_some() { @@ -54,6 +57,7 @@ fn activate(app: >k::Application) { ui.init(app, nvim_bin_path(std::env::args()).as_ref(), + external_popup(std::env::args()), open_arg().as_ref()); } @@ -66,6 +70,15 @@ fn nvim_bin_path(args: I) -> Option .unwrap_or(None) } +fn external_popup(args: I) -> bool + where I: Iterator +{ + args.filter(|a| a.starts_with(ENABLE_EXTERNAL_POPUP)) + .map(|_| true) + .nth(0) + .unwrap_or(false) +} + fn open_arg() -> Option { open_arg_impl(std::env::args()) } @@ -87,6 +100,14 @@ fn open_arg_impl(args: I) -> Option mod tests { use super::*; + #[test] + fn test_external_menu() { + assert_eq!(true, + nvim_bin_path(vec!["neovim-gtk", "--enable-external-popup"] + .iter() + .map(|s| s.to_string()))); + } + #[test] fn test_bin_path_arg() { assert_eq!(Some("/test_path".to_string()), diff --git a/src/nvim.rs b/src/nvim.rs index 376dba6..1af7200 100644 --- a/src/nvim.rs +++ b/src/nvim.rs @@ -38,6 +38,17 @@ pub trait RedrawEvents { fn on_mouse(&mut self, on: bool) -> RepaintMode; fn on_busy(&mut self, busy: bool) -> RepaintMode; + + fn popupmenu_show(&mut self, + menu: &Vec>, + selected: i64, + row: u64, + col: u64) + -> RepaintMode; + + fn popupmenu_hide(&mut self) -> RepaintMode; + + fn popupmenu_select(&mut self, selected: i64) -> RepaintMode; } pub trait GuiApi { @@ -45,28 +56,20 @@ pub trait GuiApi { } macro_rules! try_str { - ($exp:expr) => (match $exp.as_str() { - Some(val) => val, - _ => return Err("Can't convert argument to string".to_owned()) - }) + ($exp:expr) => ($exp.as_str().ok_or("Can't convert argument to string".to_owned())?) } macro_rules! try_int { - ($expr:expr) => (match $expr.as_i64() { - Some(val) => val, - _ => return Err("Can't convert argument to int".to_owned()) - }) + ($expr:expr) => ($expr.as_i64().ok_or("Can't convert argument to int".to_owned())?) } macro_rules! try_uint { - ($exp:expr) => (match $exp.as_u64() { - Some(val) => val, - _ => return Err("Can't convert argument to u64".to_owned()) - }) + ($exp:expr) => ($exp.as_u64().ok_or("Can't convert argument to u64".to_owned())?) } pub fn initialize(shell: Arc>, - nvim_bin_path: Option<&String>) + nvim_bin_path: Option<&String>, + external_popup: bool) -> Result { let session = if let Some(path) = nvim_bin_path { Session::new_child_path(path)? @@ -78,7 +81,9 @@ pub fn initialize(shell: Arc>, nvim.session .start_event_loop_handler(NvimHandler::new(shell)); - nvim.ui_attach(80, 24, UiAttachOptions::new()) + let mut opts = UiAttachOptions::new(); + opts.set_popupmenu_external(external_popup); + nvim.ui_attach(80, 24, opts) .map_err(|e| Error::new(ErrorKind::Other, e))?; nvim.command("runtime! ginit.vim") .map_err(|e| Error::new(ErrorKind::Other, e))?; @@ -181,41 +186,63 @@ fn call(ui: &mut shell::State, method: &str, args: &Vec) -> result::Result { - Ok(match method { - "cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])), - "put" => ui.on_put(try_str!(args[0])), - "clear" => ui.on_clear(), - "resize" => ui.on_resize(try_uint!(args[0]), try_uint!(args[1])), - "highlight_set" => { - if let Value::Map(ref attrs) = args[0] { - ui.on_highlight_set(attrs); - } else { - panic!("Supports only map value as argument"); + let repaint_mode = match method { + "cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])), + "put" => ui.on_put(try_str!(args[0])), + "clear" => ui.on_clear(), + "resize" => ui.on_resize(try_uint!(args[0]), try_uint!(args[1])), + "highlight_set" => { + if let Value::Map(ref attrs) = args[0] { + ui.on_highlight_set(attrs); + } else { + panic!("Supports only map value as argument"); + } + RepaintMode::Nothing } - RepaintMode::Nothing - } - "eol_clear" => ui.on_eol_clear(), - "set_scroll_region" => { - ui.on_set_scroll_region(try_uint!(args[0]), - try_uint!(args[1]), - try_uint!(args[2]), - try_uint!(args[3])); - RepaintMode::Nothing - } - "scroll" => ui.on_scroll(try_int!(args[0])), - "update_bg" => ui.on_update_bg(try_int!(args[0])), - "update_fg" => ui.on_update_fg(try_int!(args[0])), - "update_sp" => ui.on_update_sp(try_int!(args[0])), - "mode_change" => ui.on_mode_change(try_str!(args[0])), - "mouse_on" => ui.on_mouse(true), - "mouse_off" => ui.on_mouse(false), - "busy_start" => ui.on_busy(true), - "busy_stop" => ui.on_busy(false), - _ => { - println!("Event {}({:?})", method, args); - RepaintMode::Nothing - } - }) + "eol_clear" => ui.on_eol_clear(), + "set_scroll_region" => { + ui.on_set_scroll_region(try_uint!(args[0]), + try_uint!(args[1]), + try_uint!(args[2]), + try_uint!(args[3])); + RepaintMode::Nothing + } + "scroll" => ui.on_scroll(try_int!(args[0])), + "update_bg" => ui.on_update_bg(try_int!(args[0])), + "update_fg" => ui.on_update_fg(try_int!(args[0])), + "update_sp" => ui.on_update_sp(try_int!(args[0])), + "mode_change" => ui.on_mode_change(try_str!(args[0])), + "mouse_on" => ui.on_mouse(true), + "mouse_off" => ui.on_mouse(false), + "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?); + } + + ui.popupmenu_show(&menu_items, + try_int!(args[1]), + try_uint!(args[2]), + try_uint!(args[3])) + } + "popupmenu_hide" => ui.popupmenu_hide(), + "popupmenu_select" => ui.popupmenu_select(try_int!(args[0])), + _ => { + println!("Event {}({:?})", method, args); + RepaintMode::Nothing + } + }; + + Ok(repaint_mode) } pub trait ErrorReport { diff --git a/src/popup_menu.rs b/src/popup_menu.rs new file mode 100644 index 0000000..ac32987 --- /dev/null +++ b/src/popup_menu.rs @@ -0,0 +1,171 @@ +use std::rc::Rc; +use std::cell::RefCell; + +use gtk::prelude::*; +use gtk::{Window, WindowType, TreeView, TreeViewColumn, TreePath, CellRendererText, ListStore, + Type, ScrolledWindow, PolicyType}; +use glib; +use pango::FontDescription; +use gdk::{EventButton, EventType}; + +use neovim_lib::{Neovim, NeovimApi}; + +use nvim::ErrorReport; + +use input; + +const MIN_CONTENT_HEIGHT: i32 = 250; + +pub struct PopupMenu { + menu: Window, + list: TreeView, +} + +impl PopupMenu { + pub fn new(nvim: Rc>, + font_desc: &FontDescription, + menu: &Vec>, + selected: i64, + x: i32, + y: i32, + grow_up: bool) + -> PopupMenu { + let win = Window::new(WindowType::Popup); + + let tree = create_list(menu, font_desc); + tree.set_can_focus(false); + + let nvim_ref = nvim.clone(); + tree.connect_button_press_event(move |tree, ev| tree_button_press(tree, ev, &mut *nvim_ref.borrow_mut())); + + let scroll = ScrolledWindow::new(None, None); + scroll.set_policy(PolicyType::Never, PolicyType::Automatic); + scroll.set_min_content_height(MIN_CONTENT_HEIGHT); + + scroll.add(&tree); + win.add(&scroll); + if grow_up { + win.move_(x, y - MIN_CONTENT_HEIGHT); + } else { + win.move_(x, y); + } + + win.connect_key_press_event(move |_, ev| input::gtk_key_press(&mut *nvim.borrow_mut(), ev)); + + let popup = PopupMenu { + menu: win, + list: tree, + }; + + popup.select(selected); + + popup + } + + pub fn show(&self) { + self.menu.show_all(); + } + + pub fn hide(self) { + self.menu.destroy(); + } + + pub fn select(&self, selected: i64) { + if selected >= 0 { + let selected_path = TreePath::new_from_string(&format!("{}", selected)); + self.list + .get_selection() + .select_path(&selected_path); + self.list.scroll_to_cell(Some(&selected_path), None, false, 0.0, 0.0); + } else { + self.list.get_selection().unselect_all(); + } + } +} + +fn create_list(menu: &Vec>, font_desc: &FontDescription) -> TreeView { + let tree = TreeView::new(); + + if menu.is_empty() { + return tree; + } + let columns = menu.get(0).unwrap().len(); + + let font_str = font_desc.to_string(); + for i in 0..columns { + append_column(&tree, i as i32, &font_str); + } + + let list_store = ListStore::new(&vec![Type::String; columns]); + let all_column_ids: Vec = (0..columns).map(|i| i as u32).collect(); + + for line in menu { + let line_array: Vec<&glib::ToValue> = line.iter().map(|v| v as &glib::ToValue).collect(); + list_store.insert_with_values(None, &all_column_ids, &line_array[..]); + } + + tree.set_model(Some(&list_store)); + tree.set_headers_visible(false); + + tree +} + +fn append_column(tree: &TreeView, id: i32, font_str: &str) { + let renderer = CellRendererText::new(); + renderer.set_property_font(Some(font_str)); + + let column = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.add_attribute(&renderer, "text", id); + tree.append_column(&column); +} + +fn tree_button_press(tree: &TreeView, ev: &EventButton, nvim: &mut Neovim) -> Inhibit { + if ev.get_event_type() != EventType::ButtonPress { + return Inhibit(false); + } + + let (paths, ..) = tree.get_selection().get_selected_rows(); + let selected_idx = if !paths.is_empty() { + let ids = paths[0].get_indices(); + if !ids.is_empty() { + ids[0] + } else { + -1 + } + } else { + -1 + }; + + let (x, y) = ev.get_position(); + if let Some((Some(tree_path), ..)) = tree.get_path_at_pos(x as i32, y as i32) { + let target_idx = tree_path.get_indices()[0]; + + let scroll_count = find_scroll_count(selected_idx, target_idx); + + let mut apply_command = String::new(); + + for _ in 0..scroll_count { + if target_idx > selected_idx { + apply_command.push_str(""); + } else { + apply_command.push_str(""); + } + } + apply_command.push_str(""); + + nvim.input(&apply_command).report_err(nvim); + } + + Inhibit(false) +} + +fn find_scroll_count(selected_idx: i32, target_idx: i32) -> i32 { + if selected_idx < 0 { + target_idx + 1 + } else if target_idx > selected_idx { + target_idx - selected_idx + } else { + selected_idx - target_idx + } +} diff --git a/src/shell.rs b/src/shell.rs index 37ef08c..c6e960e 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1,14 +1,14 @@ -use std::string::String; use std::cell::{Ref, RefMut, RefCell}; use std::rc::Rc; +use std::sync; use std::sync::Arc; use cairo; use pangocairo as pc; use pango; use pango::FontDescription; -use gdk::{ModifierType, EventKey, EventConfigure, EventButton, EventMotion, EventType, - EventScroll, ScrollDirection}; +use gdk::{ModifierType, EventConfigure, EventButton, EventMotion, EventType, EventScroll, + ScrollDirection}; use gdk_sys; use glib; use gtk::prelude::*; @@ -20,10 +20,12 @@ use settings::{Settings, FontSource}; use ui_model::{UiModel, Cell, Attrs, Color, ModelRect, COLOR_BLACK, COLOR_WHITE, COLOR_RED}; use nvim; use nvim::{RedrawEvents, GuiApi, RepaintMode, ErrorReport}; -use input::{convert_key, keyval_to_input_string}; +use input; +use input::keyval_to_input_string; use cursor::Cursor; use ui; use ui::UiMutex; +use popup_menu::PopupMenu; const DEFAULT_FONT_NAME: &'static str = "DejaVu Sans Mono 12"; @@ -44,19 +46,22 @@ pub struct State { pub mode: NvimMode, mouse_enabled: bool, drawing_area: DrawingArea, - nvim: Option, + nvim: Option>>, font_desc: FontDescription, cursor: Option, + popup_menu: Option, settings: Rc>, line_height: Option, char_width: Option, request_width: bool, resize_timer: Option, + + parent: sync::Weak>, } impl State { - pub fn new(settings: Rc>) -> State { + pub fn new(settings: Rc>, parent: &Arc>) -> State { State { model: UiModel::new(24, 80), drawing_area: DrawingArea::new(), @@ -69,17 +74,20 @@ impl State { mouse_enabled: true, font_desc: FontDescription::from_string(DEFAULT_FONT_NAME), cursor: None, + popup_menu: None, settings: settings, line_height: None, char_width: None, resize_timer: None, request_width: true, + + parent: Arc::downgrade(parent), } } - pub fn nvim(&mut self) -> &mut Neovim { - self.nvim.as_mut().unwrap() + pub fn nvim(&self) -> RefMut { + self.nvim.as_ref().unwrap().borrow_mut() } fn create_pango_font(&self) -> FontDescription { @@ -114,6 +122,13 @@ impl State { fn request_width(&mut self) { self.request_width = true; } + + fn close_popup_menu(&self) { + if self.popup_menu.is_some() { + let mut nvim = self.nvim(); + nvim.input("").report_err(&mut *nvim); + } + } } pub struct UiState { @@ -127,14 +142,14 @@ impl UiState { } pub struct Shell { - state: Arc>, + pub state: Arc>, ui_state: Rc>, } impl Shell { - pub fn new(settings: Rc>) -> Shell { + pub fn new(settings: Rc>, parent: &Arc>) -> Shell { let shell = Shell { - state: Arc::new(UiMutex::new(State::new(settings))), + state: Arc::new(UiMutex::new(State::new(settings, parent))), ui_state: Rc::new(RefCell::new(UiState::new())), }; @@ -144,7 +159,7 @@ impl Shell { shell } - pub fn init(&mut self, parent: Arc>) { + pub fn init(&mut self) { let state = self.state.borrow_mut(); state.drawing_area.set_size_request(500, 300); state.drawing_area.set_hexpand(true); @@ -190,13 +205,21 @@ impl Shell { state .drawing_area .connect_draw(move |_, ctx| { - gtk_draw(&*parent.borrow(), &mut *ref_state.borrow_mut(), ctx) + let mut state = ref_state.borrow_mut(); + let ref_parent = sync::Weak::upgrade(&state.parent).unwrap(); + let parent = ref_parent.borrow(); + gtk_draw(&*parent, &mut *state, ctx) }); let ref_state = self.state.clone(); state .drawing_area - .connect_key_press_event(move |_, ev| gtk_key_press(&mut *ref_state.borrow_mut(), ev)); + .connect_key_press_event(move |_, ev| { + let mut shell = ref_state.borrow_mut(); + shell.cursor.as_mut().unwrap().reset_state(); + let mut nvim = shell.nvim(); + input::gtk_key_press(&mut *nvim, ev) + }); let ref_state = self.state.clone(); state @@ -222,10 +245,12 @@ impl Shell { Ref::map(self.state(), |s| &s.drawing_area) } + #[cfg(unix)] pub fn redraw(&self, mode: &RepaintMode) { self.state.borrow_mut().on_redraw(mode); } + #[cfg(unix)] pub fn set_font_desc(&self, font_name: &str) { self.state.borrow_mut().set_font_desc(font_name); } @@ -241,26 +266,28 @@ impl Shell { state.cursor.as_mut().unwrap().start(); } - pub fn init_nvim(&mut self, nvim_bin_path: Option<&String>) { + pub fn init_nvim(&mut self, nvim_bin_path: Option<&String>, external_popup: bool) { let nvim = - nvim::initialize(self.state.clone(), nvim_bin_path).expect("Can't start nvim instance"); + nvim::initialize(self.state.clone(), nvim_bin_path, external_popup).expect("Can't start nvim instance"); let mut state = self.state.borrow_mut(); - state.nvim = Some(nvim); + state.nvim = Some(Rc::new(RefCell::new(nvim))); state.request_width(); } pub fn open_file(&self, path: &str) { - let mut nvim = self.nvim(); + let state = self.state.borrow(); + let mut nvim = state.nvim(); nvim.command(&format!("e {}", path)) .report_err(&mut *nvim); } pub fn detach_ui(&mut self) { - self.nvim().ui_detach().expect("Error in ui_detach"); + let state = self.state.borrow(); + state.nvim().ui_detach().expect("Error in ui_detach"); } pub fn edit_paste(&self) { - let mut state = self.state.borrow_mut(); + let state = self.state.borrow(); let paste_command = if state.mode == NvimMode::Normal { "\"*p" } else { @@ -268,18 +295,14 @@ impl Shell { }; let mut nvim = state.nvim(); - nvim.input(paste_command).report_err(nvim); + nvim.input(paste_command).report_err(&mut *nvim); } pub fn edit_save_all(&self) { - let mut nvim = &mut *self.nvim(); + let state = self.state.borrow(); + let mut nvim = &mut *state.nvim(); nvim.command(":wa").report_err(nvim); } - - pub fn nvim(&self) -> RefMut { - let state = self.state.borrow_mut(); - RefMut::map(state, |s| s.nvim()) - } } fn gtk_focus_in(state: &mut State) -> Inhibit { @@ -293,6 +316,8 @@ fn gtk_focus_out(state: &mut State) -> Inhibit { state.cursor.as_mut().unwrap().leave_focus(); let point = state.model.cur_point(); state.on_redraw(&RepaintMode::Area(point)); + + state.close_popup_menu(); Inhibit(false) } @@ -301,6 +326,8 @@ fn gtk_scroll_event(state: &mut State, ev: &EventScroll) -> Inhibit { return Inhibit(false); } + state.close_popup_menu(); + match ev.as_ref().direction { ScrollDirection::Right => { mouse_input(state, @@ -354,7 +381,7 @@ fn mouse_input(shell: &mut State, if let Some(line_height) = shell.line_height { if let Some(char_width) = shell.char_width { - let nvim = shell.nvim(); + let mut nvim = shell.nvim(); let (x, y) = position; let col = (x / char_width).trunc() as u64; let row = (y / line_height).trunc() as u64; @@ -380,20 +407,6 @@ fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion Inhibit(false) } -fn gtk_key_press(shell: &mut State, ev: &EventKey) -> Inhibit { - if let Some(input) = convert_key(ev) { - debug!("nvim_input -> {}", input); - shell - .nvim() - .input(&input) - .expect("Error run input command to nvim"); - shell.cursor.as_mut().unwrap().reset_state(); - Inhibit(true) - } else { - Inhibit(false) - } -} - fn gtk_draw(parent: &ui::Components, state: &mut State, ctx: &cairo::Context) -> Inhibit { if state.line_height.is_none() { let (width, height) = calc_char_bounds(state, ctx); @@ -789,6 +802,63 @@ impl RedrawEvents for State { } RepaintMode::Area(self.model.cur_point()) } + + fn popupmenu_show(&mut self, + menu: &Vec>, + selected: i64, + row: u64, + col: u64) + -> RepaintMode { + match (&self.line_height, &self.char_width) { + (&Some(line_height), &Some(char_width)) => { + let parent = sync::Weak::upgrade(&self.parent).unwrap(); + let comps = parent.borrow(); + let window = comps.window(); + let screen = window.get_screen().unwrap(); + let height = screen.get_height(); + + let point = ModelRect::point((col + 1) as usize, (row + 1) as usize); + let (x, y, ..) = point.to_area(line_height, char_width); + let translated = self.drawing_area.translate_coordinates(window, x, y); + let (x, y) = if let Some((x, y)) = translated { + (x, y) + } else { + (x, y) + }; + + let (win_x, win_y) = window.get_position(); + let (abs_x, mut abs_y) = (win_x + x, win_y + y); + + let grow_up = abs_y > height / 2; + + if grow_up { + abs_y -= line_height as i32; + } + + self.popup_menu = Some(PopupMenu::new(self.nvim.as_ref().unwrap().clone(), + &self.font_desc, + menu, + selected, + abs_x, + abs_y, + grow_up)); + self.popup_menu.as_ref().unwrap().show(); + } + _ => (), + }; + + RepaintMode::Nothing + } + + fn popupmenu_hide(&mut self) -> RepaintMode { + self.popup_menu.take().unwrap().hide(); + RepaintMode::Nothing + } + + fn popupmenu_select(&mut self, selected: i64) -> RepaintMode { + self.popup_menu.as_mut().unwrap().select(selected); + RepaintMode::Nothing + } } impl GuiApi for State { diff --git a/src/shell_dlg.rs b/src/shell_dlg.rs index e3fdd4f..e124619 100644 --- a/src/shell_dlg.rs +++ b/src/shell_dlg.rs @@ -51,7 +51,8 @@ fn show_not_saved_dlg(comps: &UiMutex, let res = match dlg.run() { SAVE_ID => { - let mut nvim = shell.nvim(); + let state = shell.state.borrow(); + let mut nvim = state.nvim(); match nvim.command("wa") { Err(ref err) => { println!("Error: {}", err); @@ -71,7 +72,8 @@ fn show_not_saved_dlg(comps: &UiMutex, } fn get_changed_buffers(shell: &Shell) -> Result, CallError> { - let mut nvim = shell.nvim(); + let state = shell.state.borrow(); + let mut nvim = state.nvim(); let buffers = nvim.get_buffers().unwrap(); Ok(buffers diff --git a/src/ui.rs b/src/ui.rs index b1850eb..ffcb4f8 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -45,13 +45,14 @@ impl Components { impl Ui { pub fn new() -> Ui { + let comps = Arc::new(UiMutex::new(Components::new())); let settings = Rc::new(RefCell::new(Settings::new())); - let shell = Rc::new(RefCell::new(Shell::new(settings.clone()))); + let shell = Rc::new(RefCell::new(Shell::new(settings.clone(), &comps))); settings.borrow_mut().set_shell(Rc::downgrade(&shell)); Ui { initialized: false, - comps: Arc::new(UiMutex::new(Components::new())), + comps: comps, shell: shell.clone(), settings: settings, } @@ -60,6 +61,7 @@ impl Ui { pub fn init(&mut self, app: >k::Application, nvim_bin_path: Option<&String>, + external_popup: bool, open_path: Option<&String>) { if self.initialized { return; @@ -90,7 +92,7 @@ impl Ui { paste_btn.connect_clicked(move |_| { shell.borrow_mut().edit_paste(); }); comps.header_bar.pack_start(&paste_btn); - self.shell.borrow_mut().init(self.comps.clone()); + self.shell.borrow_mut().init(); comps.window = Some(ApplicationWindow::new(app)); let window = comps.window.as_ref().unwrap(); @@ -108,7 +110,7 @@ impl Ui { window.connect_delete_event(move |_, _| gtk_delete(&*comps_ref, &*shell_ref)); shell.add_configure_event(); - shell.init_nvim(nvim_bin_path); + shell.init_nvim(nvim_bin_path, external_popup); if open_path.is_some() { shell.open_file(open_path.unwrap()); @@ -118,7 +120,8 @@ impl Ui { } fn guard_dispatch_thread(&self, shell: &mut Shell) { - let guard = shell.nvim().session.take_dispatch_guard(); + let state = shell.state.borrow(); + let guard = state.nvim().session.take_dispatch_guard(); let comps = self.comps.clone(); thread::spawn(move || { diff --git a/src/ui_model.rs b/src/ui_model.rs index 01fa49b..2e07ef5 100644 --- a/src/ui_model.rs +++ b/src/ui_model.rs @@ -135,7 +135,7 @@ impl UiModel { } pub fn cur_point(&self) -> ModelRect { - ModelRect::point(self.cur_row, self.cur_col) + ModelRect::point(self.cur_col, self.cur_row) } pub fn set_cursor(&mut self, row: usize, col: usize) -> ModelRect { @@ -166,7 +166,7 @@ impl UiModel { self.cur_col -= 1; } - changed_region.join(&ModelRect::point(self.cur_row, self.cur_col)); + changed_region.join(&ModelRect::point(self.cur_col, self.cur_row)); changed_region } @@ -250,10 +250,10 @@ impl ModelRect { pub fn point(x: usize, y: usize) -> ModelRect { ModelRect { - top: x, - bot: x, - left: y, - right: y, + top: y, + bot: y, + left: x, + right: x, } }