running subshells in the foreground

This commit is contained in:
rabite 2019-03-18 02:04:07 +01:00
parent 6bb16d2638
commit c719ec7a3c
4 changed files with 65 additions and 14 deletions

View File

@ -652,6 +652,34 @@ impl FileBrowser {
Ok(())
}
pub fn run_subshell(&mut self) -> HResult<()> {
self.core.get_sender().send(Events::InputEnabled(false))?;
self.core.screen.cursor_show().log();
self.core.screen.drop_screen();
let shell = std::env::var("SHELL").unwrap_or("bash".into());
let status = std::process::Command::new(&shell).status();
self.core.screen.reset_screen();
self.core.get_sender().send(Events::InputEnabled(true))?;
match status {
Ok(status) =>
self.show_status(&format!("\"{}\" exited with {}",
shell, status)).log(),
Err(err) =>
self.show_status(&format!("Can't run this \"{}\": {}",
shell, err)).log()
}
Ok(())
}
pub fn get_footer(&self) -> HResult<String> {
let xsize = self.get_coordinates()?.xsize();
let ypos = self.get_coordinates()?.position().y();
@ -759,6 +787,7 @@ impl Widget for FileBrowser {
Key::Char('m') => { self.add_bookmark()?; },
Key::Char('w') => { self.proc_view.lock()?.popup()?; },
Key::Char('l') => self.log_view.lock()?.popup()?,
Key::Char('z') => self.run_subshell()?,
_ => { self.main_widget_mut()?.on_key(key)?; },
}
self.update_preview()?;

View File

@ -64,11 +64,12 @@ fn main() -> HResult<()> {
// do this early so it might be ready when needed
crate::files::load_tags().ok();
let core = WidgetCore::new().expect("Can't create WidgetCore!");
let mut core = WidgetCore::new().expect("Can't create WidgetCore!");
match run(core.clone()) {
Ok(_) => Ok(()),
Err(err) => {
core.screen.drop_screen();
eprintln!("{:?}\n{:?}", err, err.cause());
return Err(err);
}

View File

@ -114,7 +114,9 @@ impl Listable for ListView<Vec<Process>> {
impl ListView<Vec<Process>> {
fn run_proc(&mut self, cmd: &str) -> HResult<()> {
let handle = std::process::Command::new("sh")
let shell = std::env::var("SHELL").unwrap_or("sh".into());
let handle = std::process::Command::new(shell)
.arg("-c")
.arg(cmd)
.stdin(std::process::Stdio::null())

View File

@ -10,31 +10,47 @@ use parse_ansi::parse_bytes;
use crate::fail::HResult;
pub type TermMode = AlternateScreen<MouseTerminal<RawTerminal<BufWriter<Stdout>>>>;
#[derive(Clone)]
pub struct Screen {
screen: Arc<Mutex<RawTerminal<MouseTerminal<AlternateScreen<BufWriter<Stdout>>>>>>
screen: Arc<Mutex<Option<TermMode>>>
}
impl Screen {
pub fn new() -> HResult<Screen> {
let screen = BufWriter::new(std::io::stdout());
let screen = AlternateScreen::from(screen);
let mut screen = MouseTerminal::from(screen).into_raw_mode()?;
let screen = BufWriter::new(std::io::stdout()).into_raw_mode()?;
let mut screen = MouseTerminal::from(screen);
let mut screen = AlternateScreen::from(screen);
screen.cursor_hide()?;
screen.flush()?;
screen.clear()?;
Ok(Screen {
screen: Arc::new(Mutex::new(screen))
screen: Arc::new(Mutex::new(Some(screen)))
})
}
pub fn drop_screen(&mut self) {
self.cursor_show();
self.to_main_screen();
self.screen = Arc::new(Mutex::new(None));
// Terminal stays fucked without this. Why?
std::process::Command::new("reset").arg("-I").spawn();
}
pub fn reset_screen(&mut self) -> HResult<()> {
let screen = Screen::new()?.screen.lock()?.take()?;
*self.screen.lock()? = Some(screen);
Ok(())
}
}
impl Write for Screen {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.screen.lock().unwrap().write(buf)
self.screen.lock().unwrap().as_mut().unwrap().write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.screen.lock().unwrap().flush()
self.screen.lock().unwrap().as_mut().unwrap().flush()
}
}
@ -80,12 +96,15 @@ pub trait ScreenExt: Write {
write!(self, "\x1bkhunter: {}\x1b\\", title)?;
Ok(())
}
fn to_main_screen(&mut self) -> HResult<()> {
write!(self, "{}", termion::screen::ToMainScreen)?;
self.flush()?;
Ok(())
}
}
impl ScreenExt for AlternateScreen<Box<Stdout>> {}
impl ScreenExt for AlternateScreen<Stdout> {}
impl ScreenExt for AlternateScreen<BufWriter<Stdout>> {}
impl ScreenExt for Screen {}
impl ScreenExt for TermMode {}
pub fn xsize() -> u16 {
let (xsize, _) = termion::terminal_size().unwrap();