nvim_gtk/nvim/
handler.rs

1use std::result;
2use std::sync::{mpsc, Arc};
3
4use neovim_lib::{Handler, RequestHandler, Value};
5
6use crate::ui::UiMutex;
7use crate::shell;
8use glib;
9
10use super::repaint_mode::RepaintMode;
11use super::redraw_handler;
12
13pub struct NvimHandler {
14    shell: Arc<UiMutex<shell::State>>,
15
16    delayed_redraw_event_id: Arc<UiMutex<Option<glib::SourceId>>>,
17}
18
19impl NvimHandler {
20    pub fn new(shell: Arc<UiMutex<shell::State>>) -> NvimHandler {
21        NvimHandler {
22            shell,
23            delayed_redraw_event_id: Arc::new(UiMutex::new(None)),
24        }
25    }
26
27    pub fn schedule_redraw_event(&self, event: Value) {
28        let shell = self.shell.clone();
29        let delayed_redraw_event_id = self.delayed_redraw_event_id.clone();
30
31        glib::idle_add(move || {
32            let id = Some(glib::timeout_add(
33                250,
34                clone!(shell, event, delayed_redraw_event_id => move || {
35                delayed_redraw_event_id.replace(None);
36
37                if let Err(msg) = call_redraw_handler(vec![event.clone()], &shell) {
38                    error!("Error call function: {}", msg);
39                }
40
41                glib::Continue(false)
42            }),
43            ));
44
45            delayed_redraw_event_id.replace(id);
46
47            glib::Continue(false)
48        });
49    }
50
51    pub fn remove_scheduled_redraw_event(&self) {
52        let delayed_redraw_event_id = self.delayed_redraw_event_id.clone();
53        glib::idle_add(move || {
54            let id = delayed_redraw_event_id.replace(None);
55            if let Some(ev_id) = id {
56                glib::source_remove(ev_id);
57            }
58
59            glib::Continue(false)
60        });
61    }
62
63    fn nvim_cb(&self, method: &str, mut params: Vec<Value>) {
64        match method {
65            "redraw" => {
66                redraw_handler::remove_or_delay_uneeded_events(self, &mut params);
67
68                self.safe_call(move |ui| call_redraw_handler(params, ui));
69            }
70            "Gui" => {
71                if !params.is_empty() {
72                    let mut params_iter = params.into_iter();
73                    if let Some(ev_name) = params_iter.next() {
74                        if let Value::String(ev_name) = ev_name {
75                            let args = params_iter.collect();
76                            self.safe_call(move |ui| {
77                                let ui = &mut ui.borrow_mut();
78                                redraw_handler::call_gui_event(
79                                    ui,
80                                    ev_name
81                                        .as_str()
82                                        .ok_or_else(|| "Event name does not exists")?,
83                                    args,
84                                )?;
85                                ui.on_redraw(&RepaintMode::All);
86                                Ok(())
87                            });
88                        } else {
89                            error!("Unsupported event");
90                        }
91                    } else {
92                        error!("Event name does not exists");
93                    }
94                } else {
95                    error!("Unsupported event {:?}", params);
96                }
97            }
98            "subscription" => {
99                self.safe_call(move |ui| {
100                    let ui = &ui.borrow();
101                    ui.notify(params)
102                });
103            }
104            _ => {
105                error!("Notification {}({:?})", method, params);
106            }
107        }
108    }
109
110    fn nvim_cb_req(&self, method: &str, params: Vec<Value>) -> result::Result<Value, Value> {
111        match method {
112            "Gui" => {
113                if !params.is_empty() {
114                    let mut params_iter = params.into_iter();
115                    if let Some(req_name) = params_iter.next() {
116                        if let Value::String(req_name) = req_name {
117                            let args = params_iter.collect();
118                            let (sender, receiver) = mpsc::channel();
119                            self.safe_call(move |ui| {
120                                sender
121                                    .send(redraw_handler::call_gui_request(
122                                        &ui.clone(),
123                                        req_name
124                                            .as_str()
125                                            .ok_or_else(|| "Event name does not exists")?,
126                                        &args,
127                                    ))
128                                    .unwrap();
129                                {
130                                    let ui = &mut ui.borrow_mut();
131                                    ui.on_redraw(&RepaintMode::All);
132                                }
133                                Ok(())
134                            });
135                            Ok(receiver.recv().unwrap()?)
136                        } else {
137                            error!("Unsupported request");
138                            Err(Value::Nil)
139                        }
140                    } else {
141                        error!("Request name does not exist");
142                        Err(Value::Nil)
143                    }
144                } else {
145                    error!("Unsupported request {:?}", params);
146                    Err(Value::Nil)
147                }
148            }
149            _ => {
150                error!("Request {}({:?})", method, params);
151                Err(Value::Nil)
152            }
153        }
154    }
155
156    fn safe_call<F>(&self, cb: F)
157    where
158        F: FnOnce(&Arc<UiMutex<shell::State>>) -> result::Result<(), String> + 'static + Send,
159    {
160        safe_call(self.shell.clone(), cb);
161    }
162}
163
164fn call_redraw_handler(
165    params: Vec<Value>,
166    ui: &Arc<UiMutex<shell::State>>,
167) -> result::Result<(), String> {
168    let ui = &mut ui.borrow_mut();
169    let mut repaint_mode = RepaintMode::Nothing;
170
171    for ev in params {
172        if let Value::Array(ev_args) = ev {
173            let mut args_iter = ev_args.into_iter();
174            let ev_name = args_iter.next();
175            if let Some(ev_name) = ev_name {
176                if let Some(ev_name) = ev_name.as_str() {
177                    for local_args in args_iter {
178                        let args = match local_args {
179                            Value::Array(ar) => ar,
180                            _ => vec![],
181                        };
182                        let call_reapint_mode = match redraw_handler::call(ui, &ev_name, args) {
183                            Ok(mode) => mode,
184                            Err(desc) => return Err(format!("Event {}\n{}", ev_name, desc)),
185                        };
186                        repaint_mode = repaint_mode.join(call_reapint_mode);
187                    }
188                } else {
189                    error!("Unsupported event");
190                }
191            } else {
192                error!("Event name does not exists");
193            }
194        } else {
195            error!("Unsupported event type {:?}", ev);
196        }
197    }
198
199    ui.on_redraw(&repaint_mode);
200    Ok(())
201}
202
203fn safe_call<F>(shell: Arc<UiMutex<shell::State>>, cb: F)
204where
205    F: FnOnce(&Arc<UiMutex<shell::State>>) -> result::Result<(), String> + 'static + Send,
206{
207    let mut cb = Some(cb);
208    glib::idle_add(move || {
209        if let Err(msg) = cb.take().unwrap()(&shell) {
210            error!("Error call function: {}", msg);
211        }
212        glib::Continue(false)
213    });
214}
215
216impl Handler for NvimHandler {
217    fn handle_notify(&mut self, name: &str, args: Vec<Value>) {
218        self.nvim_cb(name, args);
219    }
220
221}
222
223impl RequestHandler for NvimHandler {
224    fn handle_request(&mut self, name: &str, args: Vec<Value>) -> result::Result<Value, Value> {
225        self.nvim_cb_req(name, args)
226    }
227}