1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 21:32:13 +03:00

write into tmux

This commit is contained in:
g4c 2021-09-15 11:14:39 +08:00 committed by Wez Furlong
parent 3054fd045e
commit 1a73a2feaa
3 changed files with 69 additions and 20 deletions

View File

@ -46,12 +46,13 @@ pub(crate) struct TmuxTab {
pub panes: HashSet<TmuxPaneId>, // tmux panes within tmux window pub panes: HashSet<TmuxPaneId>, // tmux panes within tmux window
} }
pub(crate) type TmuxCmdQueue = VecDeque<Box<dyn TmuxCommand>>;
pub(crate) struct TmuxDomainState { pub(crate) struct TmuxDomainState {
pub pane_id: PaneId, pub pane_id: PaneId,
pub domain_id: DomainId, pub domain_id: DomainId,
// parser: RefCell<Parser>, // parser: RefCell<Parser>,
state: RefCell<State>, state: RefCell<State>,
pub cmd_queue: RefCell<VecDeque<Box<dyn TmuxCommand>>>, pub cmd_queue: Arc<Mutex<TmuxCmdQueue>>,
pub gui_window: RefCell<Option<MuxWindowBuilder>>, pub gui_window: RefCell<Option<MuxWindowBuilder>>,
pub gui_tabs: RefCell<Vec<TmuxTab>>, pub gui_tabs: RefCell<Vec<TmuxTab>>,
pub remote_panes: RefCell<HashMap<TmuxPaneId, RefTmuxRemotePane>>, pub remote_panes: RefCell<HashMap<TmuxPaneId, RefTmuxRemotePane>>,
@ -73,7 +74,8 @@ impl TmuxDomainState {
*self.state.borrow_mut() = State::Idle; *self.state.borrow_mut() = State::Idle;
} }
State::WaitingForResponse => { State::WaitingForResponse => {
let cmd = self.cmd_queue.borrow_mut().pop_front().unwrap(); let mut cmd_queue = self.cmd_queue.as_ref().lock().unwrap();
let cmd = cmd_queue.pop_front().unwrap();
let domain_id = self.domain_id; let domain_id = self.domain_id;
*self.state.borrow_mut() = State::Idle; *self.state.borrow_mut() = State::Idle;
let resp = response.clone(); let resp = response.clone();
@ -120,17 +122,9 @@ impl TmuxDomainState {
} }
// send pending commands to tmux // send pending commands to tmux
if *self.state.borrow() == State::Idle && !self.cmd_queue.borrow().is_empty() { let cmd_queue = self.cmd_queue.as_ref().lock().unwrap();
let domain_id = self.domain_id; if *self.state.borrow() == State::Idle && !cmd_queue.is_empty() {
promise::spawn::spawn(async move { TmuxDomainState::kick_off(self.domain_id);
let mux = Mux::get().expect("to be called on main thread");
if let Some(domain) = mux.get_domain(domain_id) {
if let Some(tmux_domain) = domain.downcast_ref::<TmuxDomain>() {
tmux_domain.send_next_command();
}
}
})
.detach();
} }
} }
@ -138,7 +132,8 @@ impl TmuxDomainState {
if *self.state.borrow() != State::Idle { if *self.state.borrow() != State::Idle {
return; return;
} }
if let Some(first) = self.cmd_queue.borrow().front() { let cmd_queue = self.cmd_queue.as_ref().lock().unwrap();
if let Some(first) = cmd_queue.front() {
let cmd = first.get_command(); let cmd = first.get_command();
log::error!("sending cmd {:?}", cmd); log::error!("sending cmd {:?}", cmd);
let mux = Mux::get().expect("to be called on main thread"); let mux = Mux::get().expect("to be called on main thread");
@ -150,6 +145,18 @@ impl TmuxDomainState {
} }
} }
pub fn kick_off(domain_id: usize) {
promise::spawn::spawn_into_main_thread(async move {
let mux = Mux::get().expect("to be called on main thread");
if let Some(domain) = mux.get_domain(domain_id) {
if let Some(tmux_domain) = domain.downcast_ref::<TmuxDomain>() {
tmux_domain.send_next_command();
}
}
})
.detach();
}
pub fn create_gui_window(&self) { pub fn create_gui_window(&self) {
if self.gui_window.borrow().is_none() { if self.gui_window.borrow().is_none() {
let mux = Mux::get().expect("should be call at main thread"); let mux = Mux::get().expect("should be call at main thread");
@ -174,12 +181,13 @@ impl TmuxDomain {
pane_id, pane_id,
// parser, // parser,
state: RefCell::new(State::WaitForInitialGuard), state: RefCell::new(State::WaitForInitialGuard),
cmd_queue: RefCell::new(cmd_queue), cmd_queue: Arc::new(Mutex::new(cmd_queue)),
gui_window: RefCell::new(None), gui_window: RefCell::new(None),
gui_tabs: RefCell::new(Vec::default()), gui_tabs: RefCell::new(Vec::default()),
remote_panes: RefCell::new(HashMap::default()), remote_panes: RefCell::new(HashMap::default()),
tmux_session: RefCell::new(None), tmux_session: RefCell::new(None),
}); });
Self { inner } Self { inner }
} }

View File

@ -9,11 +9,13 @@ use crate::Pane;
use anyhow::anyhow; use anyhow::anyhow;
use portable_pty::{MasterPty, PtySize}; use portable_pty::{MasterPty, PtySize};
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Debug;
use std::fmt::Write;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Condvar, Mutex}; use std::sync::{Arc, Condvar, Mutex};
use tmux_cc::*; use tmux_cc::*;
pub(crate) trait TmuxCommand: Send { pub(crate) trait TmuxCommand: Send + Debug {
fn get_command(&self) -> String; fn get_command(&self) -> String;
fn process_result(&self, domain_id: DomainId, result: &Guarded) -> anyhow::Result<()>; fn process_result(&self, domain_id: DomainId, result: &Guarded) -> anyhow::Result<()>;
} }
@ -118,7 +120,9 @@ impl TmuxDomainState {
} }
let pane_pty = TmuxPty { let pane_pty = TmuxPty {
domain_id: self.domain_id,
rx: channel.1.clone(), rx: channel.1.clone(),
cmd_queue: self.cmd_queue.clone(),
active_lock: active_lock.clone(), active_lock: active_lock.clone(),
master_pane: ref_pane, master_pane: ref_pane,
}; };
@ -170,6 +174,7 @@ impl TmuxDomainState {
} }
} }
#[derive(Debug)]
pub(crate) struct ListAllPanes; pub(crate) struct ListAllPanes;
impl TmuxCommand for ListAllPanes { impl TmuxCommand for ListAllPanes {
fn get_command(&self) -> String { fn get_command(&self) -> String {
@ -250,6 +255,7 @@ impl TmuxCommand for ListAllPanes {
} }
} }
#[derive(Debug)]
pub(crate) struct CapturePane(TmuxPaneId); pub(crate) struct CapturePane(TmuxPaneId);
impl TmuxCommand for CapturePane { impl TmuxCommand for CapturePane {
fn get_command(&self) -> String { fn get_command(&self) -> String {
@ -276,3 +282,23 @@ impl TmuxCommand for CapturePane {
Ok(()) Ok(())
} }
} }
#[derive(Debug)]
pub(crate) struct SendKeys {
pub keys: Vec<u8>,
pub pane: TmuxPaneId,
}
impl TmuxCommand for SendKeys {
fn get_command(&self) -> String {
let mut s = String::new();
for &byte in self.keys.iter() {
write!(&mut s, "0x{:X}\r", byte).expect("unable to write key");
}
format!("send-keys -t {} {}", self.pane, s)
// FIXME: An unexpected duplicated command will prompt next line, why?
}
fn process_result(&self, _domain_id: DomainId, _result: &Guarded) -> anyhow::Result<()> {
Ok(())
}
}

View File

@ -1,3 +1,7 @@
use crate::{
tmux::{RefTmuxRemotePane, TmuxCmdQueue, TmuxDomainState},
tmux_commands::SendKeys,
};
use flume; use flume;
use portable_pty::{Child, ExitStatus, MasterPty}; use portable_pty::{Child, ExitStatus, MasterPty};
use std::{ use std::{
@ -5,8 +9,6 @@ use std::{
sync::{Arc, Condvar, Mutex}, sync::{Arc, Condvar, Mutex},
}; };
use crate::tmux::RefTmuxRemotePane;
pub(crate) struct TmuxReader { pub(crate) struct TmuxReader {
rx: flume::Receiver<String>, rx: flume::Receiver<String>,
} }
@ -27,15 +29,26 @@ impl Read for TmuxReader {
// A local tmux pane(tab) based on a tmux pty // A local tmux pane(tab) based on a tmux pty
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct TmuxPty { pub(crate) struct TmuxPty {
pub domain_id: usize,
pub master_pane: RefTmuxRemotePane, pub master_pane: RefTmuxRemotePane,
pub rx: flume::Receiver<String>, pub rx: flume::Receiver<String>,
pub cmd_queue: Arc<Mutex<TmuxCmdQueue>>,
pub active_lock: Arc<(Mutex<bool>, Condvar)>, pub active_lock: Arc<(Mutex<bool>, Condvar)>,
// TODO: wx
} }
impl Write for TmuxPty { impl Write for TmuxPty {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// TODO: write to wx of pty let pane_id = {
let pane_lock = self.master_pane.lock().unwrap();
pane_lock.pane_id
};
log::info!("pane:{}, content:{:?}", &pane_id, buf);
let mut cmd_queue = self.cmd_queue.lock().unwrap();
cmd_queue.push_back(Box::new(SendKeys {
pane: pane_id,
keys: buf.to_vec(),
}));
TmuxDomainState::kick_off(self.domain_id);
Ok(0) Ok(0)
} }
@ -91,8 +104,10 @@ impl MasterPty for TmuxPty {
fn try_clone_writer(&self) -> Result<Box<dyn std::io::Write + Send>, anyhow::Error> { fn try_clone_writer(&self) -> Result<Box<dyn std::io::Write + Send>, anyhow::Error> {
Ok(Box::new(TmuxPty { Ok(Box::new(TmuxPty {
domain_id: self.domain_id,
master_pane: self.master_pane.clone(), master_pane: self.master_pane.clone(),
rx: self.rx.clone(), rx: self.rx.clone(),
cmd_queue: self.cmd_queue.clone(),
active_lock: self.active_lock.clone(), active_lock: self.active_lock.clone(),
})) }))
} }