1use std::io::Result;
2use std::io::{Error, ErrorKind, Stdin, Stdout};
3use std::net::TcpStream;
4use std::process::Stdio;
5use std::process::{Child, ChildStdin, ChildStdout, Command};
6use std::result;
7use std::sync::mpsc;
8use std::thread::JoinHandle;
9use std::time::Duration;
10
11use std::path::Path;
12#[cfg(unix)]
13use unix_socket::UnixStream;
14
15use rpc;
16use rpc::handler::{DefaultHandler, Handler, RequestHandler};
17use rpc::Client;
18
19use async::AsyncCall;
20
21use rmpv::Value;
22
23pub struct Session {
25 client: ClientConnection,
26 timeout: Option<Duration>,
27}
28
29macro_rules! call_args {
30 () => (Vec::new());
31 ($($e:expr), +,) => (call_args![$($e),*]);
32 ($($e:expr), +) => {{
33 let mut vec = Vec::new();
34 $(
35 vec.push($e.into_val());
36 )*
37 vec
38 }};
39}
40
41impl Session {
42 pub fn new_tcp(addr: &str) -> Result<Session> {
44 let stream = TcpStream::connect(addr)?;
45 let read = stream.try_clone()?;
46 Ok(Session {
47 client: ClientConnection::Tcp(Client::new(stream, read)),
48 timeout: Some(Duration::new(5, 0)),
49 })
50 }
51
52 #[cfg(unix)]
53 pub fn new_unix_socket<P: AsRef<Path>>(path: P) -> Result<Session> {
55 let stream = UnixStream::connect(path)?;
56 let read = stream.try_clone()?;
57 Ok(Session {
58 client: ClientConnection::UnixSocket(Client::new(stream, read)),
59 timeout: Some(Duration::new(5, 0)),
60 })
61 }
62
63 pub fn new_child() -> Result<Session> {
65 if cfg!(target_os = "windows") {
66 Self::new_child_path("nvim.exe")
67 } else {
68 Self::new_child_path("nvim")
69 }
70 }
71
72 pub fn new_child_path<S: AsRef<Path>>(program: S) -> Result<Session> {
74 Self::new_child_cmd(Command::new(program.as_ref()).arg("--embed"))
75 }
76
77 pub fn new_child_cmd(cmd: &mut Command) -> Result<Session> {
81 let mut child = cmd.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
82 let stdout = child
83 .stdout
84 .take()
85 .ok_or_else(|| Error::new(ErrorKind::Other, "Can't open stdout"))?;
86 let stdin = child
87 .stdin
88 .take()
89 .ok_or_else(|| Error::new(ErrorKind::Other, "Can't open stdin"))?;
90
91 Ok(Session {
92 client: ClientConnection::Child(Client::new(stdout, stdin), child),
93 timeout: Some(Duration::new(5, 0)),
94 })
95 }
96
97 pub fn new_parent() -> Result<Session> {
99 use std::io;
100
101 Ok(Session {
102 client: ClientConnection::Parent(Client::new(io::stdin(), io::stdout())),
103 timeout: Some(Duration::new(5, 0)),
104 })
105 }
106
107 pub fn set_timeout(&mut self, timeout: Duration) {
109 self.timeout = Some(timeout);
110 }
111
112 pub fn set_infinity_timeout(&mut self) {
113 self.timeout = None;
114 }
115
116 pub fn start_event_loop_channel_handler<H>(
118 &mut self,
119 request_handler: H,
120 ) -> mpsc::Receiver<(String, Vec<Value>)>
121 where
122 H: RequestHandler + Send + 'static,
123 {
124 match self.client {
125 ClientConnection::Child(ref mut client, _) => {
126 client.start_event_loop_channel_handler(request_handler)
127 }
128 ClientConnection::Parent(ref mut client) => {
129 client.start_event_loop_channel_handler(request_handler)
130 }
131 ClientConnection::Tcp(ref mut client) => {
132 client.start_event_loop_channel_handler(request_handler)
133 }
134
135 #[cfg(unix)]
136 ClientConnection::UnixSocket(ref mut client) => {
137 client.start_event_loop_channel_handler(request_handler)
138 }
139 }
140 }
141
142 pub fn start_event_loop_channel(&mut self) -> mpsc::Receiver<(String, Vec<Value>)> {
144 self.start_event_loop_channel_handler(DefaultHandler())
145 }
146
147 pub fn start_event_loop_handler<H>(&mut self, handler: H)
149 where
150 H: Handler + Send + 'static,
151 {
152 match self.client {
153 ClientConnection::Child(ref mut client, _) => client.start_event_loop_handler(handler),
154 ClientConnection::Parent(ref mut client) => client.start_event_loop_handler(handler),
155 ClientConnection::Tcp(ref mut client) => client.start_event_loop_handler(handler),
156
157 #[cfg(unix)]
158 ClientConnection::UnixSocket(ref mut client) => {
159 client.start_event_loop_handler(handler)
160 }
161 }
162 }
163
164 pub fn start_event_loop(&mut self) {
166 match self.client {
167 ClientConnection::Child(ref mut client, _) => client.start_event_loop(),
168 ClientConnection::Parent(ref mut client) => client.start_event_loop(),
169 ClientConnection::Tcp(ref mut client) => client.start_event_loop(),
170
171 #[cfg(unix)]
172 ClientConnection::UnixSocket(ref mut client) => client.start_event_loop(),
173 }
174 }
175
176 pub fn call(&mut self, method: &str, args: Vec<Value>) -> result::Result<Value, Value> {
178 match self.client {
179 ClientConnection::Child(ref mut client, _) => client.call(method, args, self.timeout),
180 ClientConnection::Parent(ref mut client) => client.call(method, args, self.timeout),
181 ClientConnection::Tcp(ref mut client) => client.call(method, args, self.timeout),
182
183 #[cfg(unix)]
184 ClientConnection::UnixSocket(ref mut client) => client.call(method, args, self.timeout),
185 }
186 }
187
188 pub fn call_async<R: rpc::FromVal<Value>>(
190 &mut self,
191 method: &str,
192 args: Vec<Value>,
193 ) -> AsyncCall<R> {
194 AsyncCall::new(&mut self.client, method.to_owned(), args)
195 }
196
197 pub fn take_dispatch_guard(&mut self) -> JoinHandle<()> {
201 match self.client {
202 ClientConnection::Child(ref mut client, _) => client.take_dispatch_guard(),
203 ClientConnection::Parent(ref mut client) => client.take_dispatch_guard(),
204 ClientConnection::Tcp(ref mut client) => client.take_dispatch_guard(),
205
206 #[cfg(unix)]
207 ClientConnection::UnixSocket(ref mut client) => client.take_dispatch_guard(),
208 }
209 }
210}
211
212pub enum ClientConnection {
213 Child(Client<ChildStdout, ChildStdin>, Child),
214 Parent(Client<Stdin, Stdout>),
215 Tcp(Client<TcpStream, TcpStream>),
216
217 #[cfg(unix)]
218 UnixSocket(Client<UnixStream, UnixStream>),
219}