1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +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(crate) type TmuxCmdQueue = VecDeque<Box<dyn TmuxCommand>>;
pub(crate) struct TmuxDomainState {
pub pane_id: PaneId,
pub domain_id: DomainId,
// parser: RefCell<Parser>,
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_tabs: RefCell<Vec<TmuxTab>>,
pub remote_panes: RefCell<HashMap<TmuxPaneId, RefTmuxRemotePane>>,
@ -73,7 +74,8 @@ impl TmuxDomainState {
*self.state.borrow_mut() = State::Idle;
}
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;
*self.state.borrow_mut() = State::Idle;
let resp = response.clone();
@ -120,17 +122,9 @@ impl TmuxDomainState {
}
// send pending commands to tmux
if *self.state.borrow() == State::Idle && !self.cmd_queue.borrow().is_empty() {
let domain_id = self.domain_id;
promise::spawn::spawn(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();
let cmd_queue = self.cmd_queue.as_ref().lock().unwrap();
if *self.state.borrow() == State::Idle && !cmd_queue.is_empty() {
TmuxDomainState::kick_off(self.domain_id);
}
}
@ -138,7 +132,8 @@ impl TmuxDomainState {
if *self.state.borrow() != State::Idle {
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();
log::error!("sending cmd {:?}", cmd);
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) {
if self.gui_window.borrow().is_none() {
let mux = Mux::get().expect("should be call at main thread");
@ -174,12 +181,13 @@ impl TmuxDomain {
pane_id,
// parser,
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_tabs: RefCell::new(Vec::default()),
remote_panes: RefCell::new(HashMap::default()),
tmux_session: RefCell::new(None),
});
Self { inner }
}

View File

@ -9,11 +9,13 @@ use crate::Pane;
use anyhow::anyhow;
use portable_pty::{MasterPty, PtySize};
use std::collections::HashSet;
use std::fmt::Debug;
use std::fmt::Write;
use std::rc::Rc;
use std::sync::{Arc, Condvar, Mutex};
use tmux_cc::*;
pub(crate) trait TmuxCommand: Send {
pub(crate) trait TmuxCommand: Send + Debug {
fn get_command(&self) -> String;
fn process_result(&self, domain_id: DomainId, result: &Guarded) -> anyhow::Result<()>;
}
@ -118,7 +120,9 @@ impl TmuxDomainState {
}
let pane_pty = TmuxPty {
domain_id: self.domain_id,
rx: channel.1.clone(),
cmd_queue: self.cmd_queue.clone(),
active_lock: active_lock.clone(),
master_pane: ref_pane,
};
@ -170,6 +174,7 @@ impl TmuxDomainState {
}
}
#[derive(Debug)]
pub(crate) struct ListAllPanes;
impl TmuxCommand for ListAllPanes {
fn get_command(&self) -> String {
@ -250,6 +255,7 @@ impl TmuxCommand for ListAllPanes {
}
}
#[derive(Debug)]
pub(crate) struct CapturePane(TmuxPaneId);
impl TmuxCommand for CapturePane {
fn get_command(&self) -> String {
@ -276,3 +282,23 @@ impl TmuxCommand for CapturePane {
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 portable_pty::{Child, ExitStatus, MasterPty};
use std::{
@ -5,8 +9,6 @@ use std::{
sync::{Arc, Condvar, Mutex},
};
use crate::tmux::RefTmuxRemotePane;
pub(crate) struct TmuxReader {
rx: flume::Receiver<String>,
}
@ -27,15 +29,26 @@ impl Read for TmuxReader {
// A local tmux pane(tab) based on a tmux pty
#[derive(Debug, Clone)]
pub(crate) struct TmuxPty {
pub domain_id: usize,
pub master_pane: RefTmuxRemotePane,
pub rx: flume::Receiver<String>,
pub cmd_queue: Arc<Mutex<TmuxCmdQueue>>,
pub active_lock: Arc<(Mutex<bool>, Condvar)>,
// TODO: wx
}
impl Write for TmuxPty {
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)
}
@ -91,8 +104,10 @@ impl MasterPty for TmuxPty {
fn try_clone_writer(&self) -> Result<Box<dyn std::io::Write + Send>, anyhow::Error> {
Ok(Box::new(TmuxPty {
domain_id: self.domain_id,
master_pane: self.master_pane.clone(),
rx: self.rx.clone(),
cmd_queue: self.cmd_queue.clone(),
active_lock: self.active_lock.clone(),
}))
}