1use std::sync::Arc;23use remowt_link_shared::editor::{EditorBackend, Error};4use russh::client::Handle;5use tokio::net::UnixListener;6use tracing::error;78use crate::SshHandler;910pub struct SshEditor {11 pub sess: Arc<Handle<SshHandler>>,12}13impl EditorBackend for SshEditor {14 async fn open_editor(&self, socket_path: String) -> Result<(), Error> {15 let local = std::env::temp_dir().join(format!("remowt-nvim-{}.sock", uuid::Uuid::new_v4()));16 let _ = std::fs::remove_file(&local);17 let listener = UnixListener::bind(&local).map_err(|e| Error::Failed(e.to_string()))?;1819 let sess = self.sess.clone();20 let forward = tokio::spawn(async move {21 loop {22 let Ok((mut stream, _)) = listener.accept().await else {23 break;24 };25 let sess = sess.clone();26 let remote = socket_path.clone();27 tokio::spawn(async move {28 match sess.channel_open_direct_streamlocal(remote).await {29 Ok(ch) => {30 let mut remote = ch.into_stream();31 let _ = tokio::io::copy_bidirectional(&mut stream, &mut remote).await;32 }33 Err(e) => error!("opening direct-streamlocal to nvim failed: {e}"),34 }35 });36 }37 });3839 let status = tokio::process::Command::new("neovide")40 .arg("--no-fork")41 .arg("--server")42 .arg(&local)43 .status()44 .await45 .map_err(|e| Error::Failed(format!("spawning neovide: {e}")));4647 forward.abort();48 let _ = std::fs::remove_file(&local);4950 match status? {51 s if s.success() => Ok(()),52 s => Err(Error::Failed(format!("neovide exited with {s}"))),53 }54 }55}