2022-10-18 02:22:04 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-07-10 23:47:14 +02:00
|
|
|
use rmpv::Value;
|
|
|
|
|
|
|
|
use tokio::io::Stdout;
|
|
|
|
|
2022-07-11 02:08:37 +02:00
|
|
|
use nvim_rs::{compat::tokio::Compat, Handler, Neovim};
|
2022-07-16 03:45:32 +02:00
|
|
|
use nvim_rs::create::tokio::new_parent;
|
2022-10-18 02:22:04 +02:00
|
|
|
use tokio::sync::{mpsc, Mutex};
|
2022-07-10 23:47:14 +02:00
|
|
|
|
2022-10-18 02:22:04 +02:00
|
|
|
use crate::dispatcher::{Dispatcher, proto::CursorUpdate};
|
2022-07-13 01:55:04 +02:00
|
|
|
|
2022-07-10 23:47:14 +02:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct NeovimHandler {
|
2022-10-18 02:22:04 +02:00
|
|
|
dispatcher: Dispatcher,
|
|
|
|
sink: Arc<Mutex<Option<mpsc::Sender<CursorUpdate>>>>,
|
2022-07-10 23:47:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl NeovimHandler {
|
2022-10-18 02:22:04 +02:00
|
|
|
pub fn new(dispatcher: Dispatcher) -> Self {
|
|
|
|
NeovimHandler {
|
|
|
|
dispatcher,
|
|
|
|
sink: Arc::new(Mutex::new(None)),
|
2022-07-21 10:40:43 +02:00
|
|
|
}
|
2022-07-10 23:47:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tonic::async_trait]
|
|
|
|
impl Handler for NeovimHandler {
|
|
|
|
type Writer = Compat<Stdout>;
|
|
|
|
|
|
|
|
async fn handle_request(
|
|
|
|
&self,
|
|
|
|
name: String,
|
2022-07-16 03:45:32 +02:00
|
|
|
args: Vec<Value>,
|
|
|
|
neovim: Neovim<Compat<Stdout>>,
|
2022-07-10 23:47:14 +02:00
|
|
|
) -> Result<Value, Value> {
|
|
|
|
match name.as_ref() {
|
|
|
|
"ping" => Ok(Value::from("pong")),
|
2022-07-16 03:45:32 +02:00
|
|
|
"create" => {
|
|
|
|
if args.len() < 1 {
|
|
|
|
return Err(Value::from("[!] no session key"));
|
|
|
|
}
|
2022-10-18 02:22:04 +02:00
|
|
|
let res = self.dispatcher.create_workspace(args[0].to_string())
|
|
|
|
.await
|
|
|
|
.map_err(|e| Value::from(e.to_string()))?
|
|
|
|
.into_inner();
|
|
|
|
|
|
|
|
Ok(res.session_key.into())
|
2022-07-16 03:45:32 +02:00
|
|
|
},
|
2022-10-18 02:22:04 +02:00
|
|
|
"join" => {
|
2022-07-16 03:45:32 +02:00
|
|
|
if args.len() < 1 {
|
|
|
|
return Err(Value::from("[!] no session key"));
|
|
|
|
}
|
2022-10-18 02:22:04 +02:00
|
|
|
|
|
|
|
self.dispatcher.join_workspace(
|
|
|
|
args[0].as_str().unwrap().to_string(), // TODO throw err if it's not a string?
|
|
|
|
).await.map_err(|e| Value::from(e.to_string()))?;
|
|
|
|
|
|
|
|
Ok("OK".into())
|
2022-07-16 03:45:32 +02:00
|
|
|
},
|
2022-10-18 02:22:04 +02:00
|
|
|
"cursor-start" => {
|
2022-07-16 03:45:32 +02:00
|
|
|
if args.len() < 1 {
|
|
|
|
return Err(Value::from("[!] no session key"));
|
|
|
|
}
|
2022-10-18 02:22:04 +02:00
|
|
|
let (tx, stream) = mpsc::channel(50);
|
|
|
|
let mut rx = self.dispatcher.start_cursor_worker(
|
|
|
|
args[0].as_str().unwrap().to_string(), stream
|
|
|
|
).await.map_err(|e| Value::from(e.to_string()))?;
|
|
|
|
let sink = self.sink.clone();
|
|
|
|
sink.lock().await.replace(tx);
|
|
|
|
let _worker = tokio::spawn(async move {
|
|
|
|
let mut col : i64;
|
|
|
|
let mut row : i64 = 0;
|
|
|
|
let ns = neovim.create_namespace("Cursor").await.unwrap();
|
|
|
|
while let Some(update) = rx.recv().await {
|
|
|
|
neovim.exec_lua(format!("print('{:?}')", update).as_str(), vec![]).await.unwrap();
|
|
|
|
let buf = neovim.get_current_buf().await.unwrap();
|
|
|
|
buf.clear_namespace(ns, 0, -1).await.unwrap();
|
|
|
|
row = update.row as i64;
|
|
|
|
col = update.col as i64;
|
|
|
|
buf.add_highlight(ns, "ErrorMsg", row-1, col-1, col).await.unwrap();
|
|
|
|
}
|
|
|
|
sink.lock().await.take();
|
2022-07-16 03:45:32 +02:00
|
|
|
});
|
2022-10-18 02:22:04 +02:00
|
|
|
Ok("OK".into())
|
2022-07-10 23:47:14 +02:00
|
|
|
},
|
2022-07-11 02:08:37 +02:00
|
|
|
_ => {
|
|
|
|
eprintln!("[!] unexpected call");
|
|
|
|
Ok(Value::from(""))
|
|
|
|
},
|
2022-07-10 23:47:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-11 02:08:37 +02:00
|
|
|
async fn handle_notify(
|
|
|
|
&self,
|
|
|
|
name: String,
|
2022-10-18 02:22:04 +02:00
|
|
|
args: Vec<Value>,
|
2022-07-11 02:08:37 +02:00
|
|
|
_neovim: Neovim<Compat<Stdout>>,
|
|
|
|
) {
|
|
|
|
match name.as_ref() {
|
|
|
|
"insert" => {},
|
2022-10-18 02:22:04 +02:00
|
|
|
"cursor" => {
|
|
|
|
if args.len() >= 3 {
|
|
|
|
if let Some(sink) = self.sink.lock().await.as_ref() {
|
|
|
|
sink.send(CursorUpdate {
|
|
|
|
buffer: args[0].as_i64().unwrap(),
|
|
|
|
row: args[1].as_i64().unwrap(),
|
|
|
|
col: args[2].as_i64().unwrap(),
|
|
|
|
username: "root".into()
|
|
|
|
}).await.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2022-07-11 02:08:37 +02:00
|
|
|
"tick" => eprintln!("tock"),
|
|
|
|
_ => eprintln!("[!] unexpected notify",)
|
2022-07-10 23:47:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-16 03:45:32 +02:00
|
|
|
|
2022-10-18 02:22:04 +02:00
|
|
|
pub async fn run_nvim_client(dispatcher: Dispatcher) -> Result<(), Box<dyn std::error::Error + 'static>> {
|
|
|
|
let handler: NeovimHandler = NeovimHandler::new(dispatcher);
|
2022-07-16 03:45:32 +02:00
|
|
|
let (_nvim, io_handler) = new_parent(handler).await;
|
|
|
|
|
|
|
|
// Any error should probably be logged, as stderr is not visible to users.
|
|
|
|
match io_handler.await {
|
|
|
|
Err(err) => eprintln!("Error joining IO loop: {:?}", err),
|
|
|
|
Ok(Err(err)) => eprintln!("Process ended with error: {:?}", err),
|
|
|
|
Ok(Ok(())) => eprintln!("Finished"),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|