nvim_gtk/nvim/
client.rs

1use std::cell::{Cell, RefCell, RefMut};
2use std::ops::{Deref, DerefMut};
3use std::sync::{Arc, Mutex, MutexGuard};
4
5use super::ErrorReport;
6use neovim_lib::{Neovim, NeovimApi};
7
8#[derive(Clone, Copy, PartialEq)]
9enum NeovimClientState {
10    Uninitialized,
11    InitInProgress,
12    Initialized,
13    Error,
14}
15
16pub enum NeovimRef<'a> {
17    SingleThreaded(RefMut<'a, Neovim>),
18    MultiThreaded(MutexGuard<'a, Option<Neovim>>),
19}
20
21impl<'a> NeovimRef<'a> {
22    fn from_nvim(nvim: RefMut<'a, Neovim>) -> Self {
23        NeovimRef::SingleThreaded(nvim)
24    }
25
26    fn try_nvim_async(nvim_async: &'a NeovimClientAsync) -> Option<NeovimRef<'a>> {
27        let guard = nvim_async.nvim.try_lock();
28
29        if let Ok(guard) = guard {
30            if guard.is_some() {
31                return Some(NeovimRef::MultiThreaded(guard));
32            }
33        }
34
35        None
36    }
37
38    fn from_nvim_async(nvim_async: &'a NeovimClientAsync) -> Option<NeovimRef<'a>> {
39        let guard = nvim_async.nvim.lock().unwrap();
40
41        if guard.is_some() {
42            Some(NeovimRef::MultiThreaded(guard))
43        } else {
44            None
45        }
46    }
47
48    pub fn non_blocked(mut self) -> Option<Self> {
49        self.get_mode().ok_and_report().and_then(|mode| {
50            mode.iter()
51                .find(|kv| kv.0.as_str().map(|key| key == "blocking").unwrap_or(false))
52                .map(|kv| kv.1.as_bool().unwrap_or(false))
53                .and_then(|block| if block { None } else { Some(self) })
54        })
55    }
56}
57
58impl<'a> Deref for NeovimRef<'a> {
59    type Target = Neovim;
60
61    fn deref(&self) -> &Neovim {
62        match *self {
63            NeovimRef::SingleThreaded(ref nvim) => &*nvim,
64            NeovimRef::MultiThreaded(ref nvim) => (&*nvim).as_ref().unwrap(),
65        }
66    }
67}
68
69impl<'a> DerefMut for NeovimRef<'a> {
70    fn deref_mut(&mut self) -> &mut Neovim {
71        match *self {
72            NeovimRef::SingleThreaded(ref mut nvim) => &mut *nvim,
73            NeovimRef::MultiThreaded(ref mut nvim) => (&mut *nvim).as_mut().unwrap(),
74        }
75    }
76}
77
78pub struct NeovimClientAsync {
79    nvim: Arc<Mutex<Option<Neovim>>>,
80}
81
82impl NeovimClientAsync {
83    fn new() -> Self {
84        NeovimClientAsync {
85            nvim: Arc::new(Mutex::new(None)),
86        }
87    }
88
89    pub fn borrow(&self) -> Option<NeovimRef> {
90        NeovimRef::from_nvim_async(self)
91    }
92
93    pub fn try_borrow(&self) -> Option<NeovimRef> {
94        NeovimRef::try_nvim_async(self)
95    }
96}
97
98impl Clone for NeovimClientAsync {
99    fn clone(&self) -> Self {
100        NeovimClientAsync {
101            nvim: self.nvim.clone(),
102        }
103    }
104}
105
106pub struct NeovimClient {
107    state: Cell<NeovimClientState>,
108    nvim: RefCell<Option<Neovim>>,
109    nvim_async: NeovimClientAsync,
110}
111
112impl NeovimClient {
113    pub fn new() -> Self {
114        NeovimClient {
115            state: Cell::new(NeovimClientState::Uninitialized),
116            nvim: RefCell::new(None),
117            nvim_async: NeovimClientAsync::new(),
118        }
119    }
120
121    pub fn clear(&self) {
122        let mut nvim = self.nvim.borrow_mut();
123        if nvim.is_some() {
124            nvim.take();
125        } else {
126            self.nvim_async.nvim.lock().unwrap().take();
127        }
128    }
129
130    pub fn async_to_sync(&self) {
131        let mut lock = self.nvim_async.nvim.lock().unwrap();
132        let nvim = lock.take().unwrap();
133        *self.nvim.borrow_mut() = Some(nvim);
134    }
135
136    pub fn set_nvim_async(&self, nvim: Neovim) -> NeovimClientAsync {
137        *self.nvim_async.nvim.lock().unwrap() = Some(nvim);
138        self.nvim_async.clone()
139    }
140
141    pub fn set_initialized(&self) {
142        self.state.set(NeovimClientState::Initialized);
143    }
144
145    pub fn set_error(&self) {
146        self.state.set(NeovimClientState::Error);
147    }
148
149    pub fn set_in_progress(&self) {
150        self.state.set(NeovimClientState::InitInProgress);
151    }
152
153    pub fn is_initialized(&self) -> bool {
154        self.state.get() == NeovimClientState::Initialized
155    }
156
157    pub fn is_uninitialized(&self) -> bool {
158        self.state.get() == NeovimClientState::Uninitialized
159    }
160
161    pub fn is_initializing(&self) -> bool {
162        self.state.get() == NeovimClientState::InitInProgress
163    }
164
165    /// In case neovimref locked in another thread
166    /// this method can return None
167    pub fn try_nvim(&self) -> Option<NeovimRef> {
168        let nvim = self.nvim.borrow_mut();
169        if nvim.is_some() {
170            Some(NeovimRef::from_nvim(RefMut::map(nvim, |n| {
171                n.as_mut().unwrap()
172            })))
173        } else {
174            self.nvim_async.try_borrow()
175        }
176    }
177
178    pub fn nvim(&self) -> Option<NeovimRef> {
179        let nvim = self.nvim.borrow_mut();
180        if nvim.is_some() {
181            Some(NeovimRef::from_nvim(RefMut::map(nvim, |n| {
182                n.as_mut().unwrap()
183            })))
184        } else {
185            self.nvim_async.borrow()
186        }
187    }
188}