1use neovim_api::NeovimApi;
2use rmpv::Value;
3use rpc::*;
4use session::Session;
5use std::error::Error;
6use std::fmt;
7
8pub struct Neovim {
9 pub session: Session,
10}
11
12pub enum UiOption {
13 RGB(bool),
14 ExtPopupmenu(bool),
15 ExtTabline(bool),
16 ExtCmdline(bool),
17 ExtWildmenu(bool),
18 ExtLinegrid(bool),
19 ExtHlstate(bool),
20 ExtTermcolors(bool),
21}
22
23impl UiOption {
24 fn to_value(&self) -> (Value, Value) {
25 let name_value = self.to_name_value();
26 (name_value.0.into(), name_value.1)
27 }
28
29 fn to_name_value(&self) -> (&'static str, Value) {
30 match *self {
31 UiOption::RGB(val) => ("rgb", val.into()),
32 UiOption::ExtPopupmenu(val) => ("ext_popupmenu", val.into()),
33 UiOption::ExtTabline(val) => ("ext_tabline", val.into()),
34 UiOption::ExtCmdline(val) => ("ext_cmdline", val.into()),
35 UiOption::ExtWildmenu(val) => ("ext_wildmenu", val.into()),
36 UiOption::ExtLinegrid(val) => ("ext_linegrid", val.into()),
37 UiOption::ExtHlstate(val) => ("ext_hlstate", val.into()),
38 UiOption::ExtTermcolors(val) => ("ext_termcolors", val.into()),
39 }
40 }
41}
42
43pub struct UiAttachOptions {
44 options: Vec<(&'static str, UiOption)>,
45}
46
47impl UiAttachOptions {
48 pub fn new() -> UiAttachOptions {
49 UiAttachOptions {
50 options: Vec::new(),
51 }
52 }
53
54 fn set_option(&mut self, option: UiOption) {
55 let name = option.to_name_value();
56 let position = self.options.iter().position(|o| o.0 == name.0);
57
58 if let Some(position) = position {
59 self.options[position].1 = option;
60 } else {
61 self.options.push((name.0, option));
62 }
63 }
64
65 pub fn set_rgb(&mut self, rgb: bool) -> &mut Self {
66 self.set_option(UiOption::RGB(rgb));
67 self
68 }
69
70 pub fn set_popupmenu_external(&mut self, popupmenu_external: bool) -> &mut Self {
71 self.set_option(UiOption::ExtPopupmenu(popupmenu_external));
72 self
73 }
74
75 pub fn set_tabline_external(&mut self, tabline_external: bool) -> &mut Self {
76 self.set_option(UiOption::ExtTabline(tabline_external));
77 self
78 }
79
80 pub fn set_cmdline_external(&mut self, cmdline_external: bool) -> &mut Self {
81 self.set_option(UiOption::ExtCmdline(cmdline_external));
82 self
83 }
84
85 pub fn set_wildmenu_external(&mut self, wildmenu_external: bool) -> &mut Self {
86 self.set_option(UiOption::ExtWildmenu(wildmenu_external));
87 self
88 }
89
90 pub fn set_linegrid_external(&mut self, linegrid_external: bool) -> &mut Self {
91 self.set_option(UiOption::ExtLinegrid(linegrid_external));
92 self
93 }
94
95 pub fn set_hlstate_external(&mut self, hlstate_external: bool) -> &mut Self {
96 self.set_option(UiOption::ExtHlstate(hlstate_external));
97 self
98 }
99
100 pub fn set_termcolors_external(&mut self, termcolors_external: bool) -> &mut Self {
101 self.set_option(UiOption::ExtTermcolors(termcolors_external));
102 self
103 }
104
105 fn to_value_map(&self) -> Value {
106 let map = self.options.iter().map(|o| o.1.to_value()).collect();
107 Value::Map(map)
108 }
109}
110
111#[derive(Debug, PartialEq, Eq, Clone)]
112pub enum CallError {
113 GenericError(String),
114 NeovimError(i64, String),
115}
116
117impl fmt::Display for CallError {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 match *self {
120 CallError::GenericError(ref s) => write!(f, "Unknown error type: {}", s),
121 CallError::NeovimError(id, ref s) => write!(f, "{} - {}", id, s),
122 }
123 }
124}
125
126impl Error for CallError {
127 fn description(&self) -> &str {
128 match *self {
129 CallError::GenericError(ref s) => s,
130 CallError::NeovimError(_, ref s) => s,
131 }
132 }
133}
134
135#[doc(hidden)]
136pub fn map_generic_error(err: Value) -> CallError {
137 match err {
138 Value::String(val) => CallError::GenericError(val.as_str().unwrap().to_owned()),
139 Value::Array(arr) => {
140 if arr.len() == 2 {
141 match (&arr[0], &arr[1]) {
142 (&Value::Integer(ref id), &Value::String(ref val)) => CallError::NeovimError(
143 id.as_i64().unwrap(),
144 val.as_str().unwrap().to_owned(),
145 ),
146 _ => CallError::GenericError(format!("{:?}", arr)),
147 }
148 } else {
149 CallError::GenericError(format!("{:?}", arr))
150 }
151 }
152 val => CallError::GenericError(format!("{:?}", val)),
153 }
154}
155
156#[doc(hidden)]
157pub fn map_result<T: FromVal<Value>>(val: Value) -> T {
158 T::from_val(val)
159}
160
161impl Neovim {
162 pub fn new(session: Session) -> Neovim {
163 Neovim { session }
164 }
165
166 pub fn ui_attach(
170 &mut self,
171 width: i64,
172 height: i64,
173 opts: &UiAttachOptions,
174 ) -> Result<(), CallError> {
175 self.session
176 .call(
177 "nvim_ui_attach",
178 call_args!(width, height, opts.to_value_map()),
179 ).map_err(map_generic_error)
180 .map(|_| ())
181 }
182
183 pub fn quit_no_save(&mut self) -> Result<(), CallError> {
187 self.command("qa!")
188 }
189
190 pub fn set_option(&mut self, option: UiOption) -> Result<(), CallError> {
192 let name_value = option.to_name_value();
193 self.ui_set_option(name_value.0, name_value.1)
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn test_ui_options() {
203 let value_map = UiAttachOptions::new()
204 .set_rgb(true)
205 .set_rgb(false)
206 .set_popupmenu_external(true)
207 .to_value_map();
208
209 assert_eq!(
210 Value::Map(vec![
211 ("rgb".into(), false.into()),
212 ("ext_popupmenu".into(), true.into()),
213 ]),
214 value_map
215 );
216 }
217}