diff --git a/src/main.rs b/src/main.rs index b6e14b3..78b0059 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,18 +4,18 @@ extern crate cairo; extern crate neovim_lib; extern crate rmp; -mod ui_mutex; mod nvim; mod ui_model; mod ui; -use ui::Ui; - fn main() { - let ui = Ui::new(); - ui.show(); + gtk::init().expect("Failed to initialize GTK"); + ui::UI.with(|ui_cell| { + let mut ui = ui_cell.borrow_mut(); + ui.init(); - let nvim = nvim::initialize(ui).expect("Can't start nvim instance"); + nvim::initialize(&mut *ui).expect("Can't start nvim instance"); + }); gtk::main(); } diff --git a/src/nvim.rs b/src/nvim.rs index 188b669..f825996 100644 --- a/src/nvim.rs +++ b/src/nvim.rs @@ -1,16 +1,13 @@ use neovim_lib::{Neovim, NeovimApi, Session}; use std::io::{Result, Error, ErrorKind}; -use std::sync::Arc; use std::result; use ui_model::UiModel; -use ui_mutex::UiMutex; use rmp::Value; use rmp::value::Integer; +use ui; use ui::Ui; use glib; -pub type SharedUi = Arc>; - pub trait RedrawEvents { fn on_cursor_goto(&mut self, row: u64, col: u64); @@ -35,7 +32,7 @@ macro_rules! try_int { }) } -pub fn initialize(mut ui: Ui) -> Result { +pub fn initialize(ui: &mut Ui) -> Result<()> { // let mut session = try!(Session::new_tcp("127.0.0.1:6666")); let session = if cfg!(target_os = "windows") { Session::new_child_path("E:\\Neovim\\bin\\nvim.exe").unwrap() @@ -46,24 +43,17 @@ pub fn initialize(mut ui: Ui) -> Result { ui.set_nvim(nvim); ui.model = UiModel::new(80, 24); - let sh_ui = Arc::new(UiMutex::new(ui)); + let mut nvim = ui.nvim(); + nvim.session.start_event_loop_cb(move |m, p| nvim_cb(m, p)); + // fix neovim --embed bug to start embed mode + nvim.input("i").unwrap(); + try!(nvim.ui_attach(80, 24, true).map_err(|e| Error::new(ErrorKind::Other, e))); - { - let mut ui = (*sh_ui).borrow_mut(); - let mut nvim = ui.nvim(); - - let moved_sh_ui = sh_ui.clone(); - nvim.session.start_event_loop_cb(move |m, p| nvim_cb(&moved_sh_ui, m, p)); - // fix neovim --embed bug to start embed mode - nvim.input("i").unwrap(); - try!(nvim.ui_attach(80, 24, true).map_err(|e| Error::new(ErrorKind::Other, e))); - } - - Ok(sh_ui) + Ok(()) } -fn nvim_cb(ui: &SharedUi, method: &str, params: Vec) { +fn nvim_cb(method: &str, params: Vec) { if method == "redraw" { for ev in params { if let Value::Array(ev_args) = ev { @@ -72,7 +62,7 @@ fn nvim_cb(ui: &SharedUi, method: &str, params: Vec) { Value::Array(ref ar) => ar.clone(), _ => vec![], }; - call(ui, ev_name, args); + call(ev_name, args); } else { println!("Unsupported event {:?}", ev_args); } @@ -85,29 +75,29 @@ fn nvim_cb(ui: &SharedUi, method: &str, params: Vec) { } } -fn call(ui: &SharedUi, method: &str, args: Vec) { +fn call(method: &str, args: Vec) { match method { "cursor_goto" => { - safe_call(ui, move |ui| { - ui.borrow_mut().on_cursor_goto(try_int!(args[0]), try_int!(args[1])); + safe_call(move |ui| { + ui.on_cursor_goto(try_int!(args[0]), try_int!(args[1])); Ok(()) }) } "put" => { - safe_call(ui, move |ui| { - ui.borrow_mut().on_put(try_str!(args[0])); + safe_call(move |ui| { + ui.on_put(try_str!(args[0])); Ok(()) }) } "clear" => { - safe_call(ui, move |ui| { - ui.borrow_mut().on_clear(); + safe_call(move |ui| { + ui.on_clear(); Ok(()) }) } "resize" => { - safe_call(ui, move |ui| { - ui.borrow_mut().on_resize(try_int!(args[0]), try_int!(args[1])); + safe_call(move |ui| { + ui.on_resize(try_int!(args[0]), try_int!(args[1])); Ok(()) }); } @@ -115,14 +105,15 @@ fn call(ui: &SharedUi, method: &str, args: Vec) { }; } -fn safe_call(ui: &SharedUi, cb: F) - where F: Fn(&UiMutex) -> result::Result<(), String> + 'static + Send +fn safe_call(cb: F) + where F: Fn(&mut Ui) -> result::Result<(), String> + 'static + Send { - let sent_ui = ui.clone(); glib::idle_add(move || { - if let Err(msg) = cb(&*sent_ui) { - println!("Error call function: {}", msg); - } + ui::UI.with(|ui_cell| { + if let Err(msg) = cb(&mut *ui_cell.borrow_mut()) { + println!("Error call function: {}", msg); + } + }); glib::Continue(false) }); } diff --git a/src/ui.rs b/src/ui.rs index 9d7ee7c..526eb21 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,3 +1,6 @@ +use std::cell::RefCell; +use std::thread; + use cairo; use gtk; use gtk::prelude::*; @@ -7,15 +10,26 @@ use neovim_lib::Neovim; use ui_model::UiModel; use nvim::RedrawEvents; +thread_local!(pub static UI: RefCell = { + let thread = thread::current(); + let current_thread_name = thread.name(); + if current_thread_name != Some("
") { + panic!("Can create UI only from main thread, {:?}", current_thread_name); + } + RefCell::new(Ui::new()) +}); + pub struct Ui { pub model: UiModel, nvim: Option, + drawing_area: DrawingArea, } impl Ui { pub fn new() -> Ui { Ui { model: UiModel::empty(), + drawing_area: DrawingArea::new(), nvim: None, } } @@ -28,8 +42,8 @@ impl Ui { self.nvim.as_mut().unwrap() } - pub fn show(&self) { - gtk::init().expect("Failed to initialize GTK"); + pub fn init(&mut self) { + let window = Window::new(WindowType::Toplevel); let grid = Grid::new(); @@ -52,30 +66,41 @@ impl Ui { grid.attach(&button_bar, 0, 0, 1, 1); - let drawing_area = DrawingArea::new(); - drawing_area.set_size_request(500, 500); - drawing_area.connect_draw(Self::gtk_draw); - grid.attach(&drawing_area, 0, 1, 1, 1); + self.drawing_area.set_size_request(500, 500); + self.drawing_area.set_hexpand(true); + self.drawing_area.set_vexpand(true); + grid.attach(&self.drawing_area, 0, 1, 1, 1); + self.drawing_area.connect_draw(gtk_draw); window.add(&grid); window.show_all(); - window.connect_delete_event(|_,_| { + window.connect_delete_event(|_, _| { gtk::main_quit(); Inhibit(false) }); - } +} - fn gtk_draw(drawing_area: &DrawingArea, ctx: &cairo::Context) -> Inhibit { - let width = drawing_area.get_allocated_width() as f64; - let height = drawing_area.get_allocated_height() as f64; - ctx.set_source_rgb(1.0, 0.0, 0.0); - ctx.arc(width / 2.0, height / 2.0, - width / 2.0, - 0.0, 2.0 * 3.14); - ctx.fill(); - Inhibit(true) - } +fn gtk_draw(drawing_area: &DrawingArea, ctx: &cairo::Context) -> Inhibit { + let width = drawing_area.get_allocated_width() as f64; + let height = drawing_area.get_allocated_height() as f64; + + let font_face = cairo::FontFace::toy_create("", + cairo::enums::FontSlant::Normal, + cairo::enums::FontWeight::Normal); + ctx.set_font_face(font_face); + UI.with(|ui_cell| { + ctx.set_source_rgb(0.0, 0.0, 0.0); + let ui = ui_cell.borrow(); + let mut line_y = 30.0; + for line in ui.model.lines() { + ctx.move_to(0.0, line_y); + ctx.show_text(&line); + line_y += 30.0; + } + }); + + Inhibit(true) } impl RedrawEvents for Ui { @@ -95,4 +120,3 @@ impl RedrawEvents for Ui { self.model = UiModel::new(rows, columns); } } - diff --git a/src/ui_model.rs b/src/ui_model.rs index ef19073..89cd272 100644 --- a/src/ui_model.rs +++ b/src/ui_model.rs @@ -43,6 +43,10 @@ impl UiModel { } } + pub fn lines(&self) -> Vec { + self.model.iter().map(|r| r.iter().map(|c| c.ch).collect::()).collect() + } + pub fn set_cursor(&mut self, row: u64, col: u64) { self.cur_col = col as usize; self.cur_row = row as usize; diff --git a/src/ui_mutex.rs b/src/ui_mutex.rs deleted file mode 100644 index 6d423b3..0000000 --- a/src/ui_mutex.rs +++ /dev/null @@ -1,32 +0,0 @@ - -use std::cell::{RefCell, RefMut}; -use std::thread; - -pub struct UiMutex { - data: RefCell, - main_thread_name: Option, -} - -// here sync used to mark that internal data is acessed only from main thread -// this behaviour works because of borrow_mut check thread name -unsafe impl Sync for UiMutex {} - -impl UiMutex { - pub fn new(t: T) -> UiMutex { - UiMutex { - data: RefCell::new(t), - main_thread_name: thread::current().name().map(|v| v.to_owned()), - } - } - - pub fn borrow_mut(&self) -> RefMut { - let current_thread_name = thread::current().name().map(|v| v.to_owned()); - if current_thread_name != self.main_thread_name { - panic!("Can access value only from main thread, {:?}/{:?}", current_thread_name, self.main_thread_name); - } - - self.data.borrow_mut() - } -} - -