1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use mpack::{Value, WriteError};
use mpack::rpc::{Client, RpcResult};
use std::env;
use std::error::Error;
use std::io::{self, Read, Stdin, Stdout, Write};
use std::net::{TcpStream, ToSocketAddrs, SocketAddr};
use std::process::{Command, Child, ChildStdin, ChildStdout, Stdio};
use std::sync::mpsc::Receiver;
use super::metadata::Metadata;
pub struct Session {
pub metadata: Metadata,
conn: ClientConn,
}
impl Session {
pub fn new_tcp<A: ToSocketAddrs>(addr: A) -> io::Result<Session> {
let reader = try!(TcpStream::connect(&addr));
let writer = try!(reader.try_clone());
let addr = reader.peer_addr().unwrap();
let mut client = Client::new(reader, writer);
Ok(Session{
metadata: try!(Session::get_vim_api_info(&mut client)),
conn: ClientConn::Tcp(client, addr),
})
}
pub fn new_stdio() -> Session {
let mut client = Client::new(io::stdin(), io::stdout());
Session{
metadata: Session::get_vim_api_info(&mut client).unwrap(),
conn: ClientConn::Stdio(client),
}
}
pub fn new_child(args: &[String]) -> io::Result<Session> {
let cmd = env::var("NVIM_BIN").unwrap_or(String::from("nvim"));
let mut child = try!(Command::new(cmd).args(args).arg("--embed").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn());
let mut client = Client::new(child.stdout.take().unwrap(), child.stdin.take().unwrap());
Ok(Session{
metadata: try!(Session::get_vim_api_info(&mut client)),
conn: ClientConn::Child(client, child),
})
}
pub fn new_socket() {
unimplemented!()
}
pub fn call(&mut self, method: String, params: Vec<Value>) -> Result<Receiver<RpcResult>, WriteError> {
match self.conn {
ClientConn::Tcp(ref mut client, _) => client.call(method, params),
ClientConn::Stdio(ref mut client) => client.call(method, params),
ClientConn::Child(ref mut client, _) => client.call(method, params),
}
}
pub fn call_sync(&mut self, method: String, params: Vec<Value>) -> Result<RpcResult, WriteError> {
match self.conn {
ClientConn::Tcp(ref mut client, _) => client.call_sync(method, params),
ClientConn::Stdio(ref mut client) => client.call_sync(method, params),
ClientConn::Child(ref mut client, _) => client.call_sync(method, params),
}
}
pub fn socket_addr(&self) -> Option<&SocketAddr> {
match self.conn {
ClientConn::Tcp(_, ref addr) => Some(addr),
ClientConn::Stdio(..) | ClientConn::Child(..) => None,
}
}
fn get_vim_api_info<R: Read + Send + 'static, W: Write + Send>(client: &mut Client<R, W>) -> io::Result<Metadata> {
let api_info = match client.call_sync(String::from("vim_get_api_info"), vec![]) {
Ok(result) => match result {
Ok(api_info) => api_info,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, "call to vim_get_api_info failed")),
},
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e.description())),
};
Ok(Metadata::new(api_info.array().unwrap().get(1).unwrap().clone()).unwrap())
}
}
enum ClientConn {
Tcp(Client<TcpStream, TcpStream>, SocketAddr),
Stdio(Client<Stdin, Stdout>),
Child(Client<ChildStdout, ChildStdin>, Child),
}