ui: embed editor cleanups
parent
ce646abc7a
commit
62bfe2a91f
|
@ -126,14 +126,6 @@ impl ViewMode {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_embed(&self) -> bool {
|
||||
if let ViewMode::Embed = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Composer {
|
||||
|
@ -543,23 +535,24 @@ impl Component for Composer {
|
|||
/* Regardless of view mode, do the following */
|
||||
self.form.draw(grid, header_area, context);
|
||||
if let Some(ref mut embed_pty) = self.embed {
|
||||
let body_area = (upper_left!(header_area), bottom_right!(body_area));
|
||||
clear_area(grid, body_area);
|
||||
let embed_area = (upper_left!(header_area), bottom_right!(body_area));
|
||||
match embed_pty {
|
||||
EmbedStatus::Running(_, _) => {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
clear_area(grid, embed_area);
|
||||
copy_area(
|
||||
grid,
|
||||
&guard.grid,
|
||||
body_area,
|
||||
embed_area,
|
||||
((0, 0), pos_dec(guard.terminal_size, (1, 1))),
|
||||
);
|
||||
guard.set_terminal_size((width!(body_area), height!(body_area)));
|
||||
guard.set_terminal_size((width!(embed_area), height!(embed_area)));
|
||||
context.dirty_areas.push_back(area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
EmbedStatus::Stopped(_, _) => {
|
||||
clear_area(grid, body_area);
|
||||
write_string_to_grid(
|
||||
"process has stopped, press 'e' to re-activate",
|
||||
grid,
|
||||
|
@ -569,9 +562,7 @@ impl Component for Composer {
|
|||
body_area,
|
||||
None,
|
||||
);
|
||||
context.dirty_areas.push_back(body_area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
context.dirty_areas.push_back(area);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -706,7 +697,10 @@ impl Component for Composer {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
if self.cursor == Cursor::Headers && self.form.process_event(event, context) {
|
||||
if self.cursor == Cursor::Headers
|
||||
&& self.mode.is_edit()
|
||||
&& self.form.process_event(event, context)
|
||||
{
|
||||
if let UIEvent::InsertInput(_) = event {
|
||||
self.has_changes = true;
|
||||
}
|
||||
|
@ -762,6 +756,12 @@ impl Component for Composer {
|
|||
}
|
||||
UIEvent::EmbedInput((Key::Ctrl('z'), _)) => {
|
||||
self.embed.as_ref().unwrap().lock().unwrap().stop();
|
||||
match self.embed.take() {
|
||||
Some(EmbedStatus::Running(e, f)) | Some(EmbedStatus::Stopped(e, f)) => {
|
||||
self.embed = Some(EmbedStatus::Stopped(e, f));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Normal));
|
||||
|
@ -824,6 +824,10 @@ impl Component for Composer {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.mode = ViewMode::Edit;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Normal));
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -852,15 +856,22 @@ impl Component for Composer {
|
|||
self.set_dirty();
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char('e')) if self.mode.is_embed() => {
|
||||
UIEvent::Input(Key::Char('e')) if self.embed.is_some() => {
|
||||
self.embed.as_ref().unwrap().lock().unwrap().wake_up();
|
||||
match self.embed.take() {
|
||||
Some(EmbedStatus::Running(e, f)) | Some(EmbedStatus::Stopped(e, f)) => {
|
||||
self.embed = Some(EmbedStatus::Running(e, f));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.mode = ViewMode::Embed;
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Embed));
|
||||
self.set_dirty();
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char('e')) => {
|
||||
UIEvent::Input(Key::Char('e')) if self.mode.is_edit() => {
|
||||
/* Edit draft in $EDITOR */
|
||||
let settings = &context.settings;
|
||||
let editor = if let Some(editor_cmd) = settings.composing.editor_cmd.as_ref() {
|
||||
|
@ -901,6 +912,9 @@ impl Component for Composer {
|
|||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Embed));
|
||||
context.replies.push_back(UIEvent::Fork(ForkType::Embed(
|
||||
self.embed.as_ref().unwrap().lock().unwrap().child_pid,
|
||||
)));
|
||||
self.mode = ViewMode::Embed;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -196,6 +196,13 @@ impl Drop for State {
|
|||
fn drop(&mut self) {
|
||||
// When done, restore the defaults to avoid messing with the terminal.
|
||||
self.switch_to_main_screen();
|
||||
if let Some(ForkType::Embed(child_pid)) = self.child.take() {
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag};
|
||||
/* Try wait, we don't want to block */
|
||||
if let Err(e) = waitpid(child_pid, Some(WaitPidFlag::WNOHANG)) {
|
||||
eprintln!("Failed to wait on subprocess {}: {}", child_pid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use melib::ERROR;
|
|||
use nix::fcntl::{open, OFlag};
|
||||
use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||
use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt, Winsize};
|
||||
use nix::sys::{stat, wait::waitpid};
|
||||
use nix::sys::stat;
|
||||
use nix::unistd::{dup2, fork, ForkResult};
|
||||
use nix::{ioctl_none_bad, ioctl_write_ptr_bad};
|
||||
use std::ffi::CString;
|
||||
|
@ -66,8 +66,6 @@ pub fn create_pty(
|
|||
/* Open slave end for pseudoterminal */
|
||||
let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty())?;
|
||||
|
||||
let child_pid = match fork() {
|
||||
Ok(ForkResult::Child) => {
|
||||
// assign stdin, stdout, stderr to the tty
|
||||
dup2(slave_fd, STDIN_FILENO).unwrap();
|
||||
dup2(slave_fd, STDOUT_FILENO).unwrap();
|
||||
|
@ -76,12 +74,24 @@ pub fn create_pty(
|
|||
nix::unistd::setsid().unwrap();
|
||||
match unsafe { set_controlling_terminal(slave_fd) } {
|
||||
Ok(c) if c < 0 => {
|
||||
log(format!("Could not execute `{}`: ioctl(fd, TIOCSCTTY, NULL) returned {}", command, c,), ERROR);
|
||||
log(
|
||||
format!(
|
||||
"Could not execute `{}`: ioctl(fd, TIOCSCTTY, NULL) returned {}",
|
||||
command, c,
|
||||
),
|
||||
ERROR,
|
||||
);
|
||||
std::process::exit(c);
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
log(format!("Could not execute `{}`: ioctl(fd, TIOCSCTTY, NULL) returned {}", command, err,), ERROR);
|
||||
log(
|
||||
format!(
|
||||
"Could not execute `{}`: ioctl(fd, TIOCSCTTY, NULL) returned {}",
|
||||
command, err,
|
||||
),
|
||||
ERROR,
|
||||
);
|
||||
std::process::exit(-1);
|
||||
}
|
||||
}
|
||||
|
@ -103,12 +113,6 @@ pub fn create_pty(
|
|||
Ok(ForkResult::Parent { child }) => child,
|
||||
Err(e) => panic!(e),
|
||||
};
|
||||
waitpid(child_pid, None).unwrap();
|
||||
std::process::exit(0);
|
||||
}
|
||||
Ok(ForkResult::Parent { child }) => child,
|
||||
Err(e) => panic!(e),
|
||||
};
|
||||
|
||||
let stdin = unsafe { std::fs::File::from_raw_fd(master_fd.clone().into_raw_fd()) };
|
||||
let mut embed_grid = EmbedGrid::new(stdin, child_pid);
|
||||
|
|
|
@ -633,7 +633,7 @@ impl EmbedGrid {
|
|||
.write_all((terminal_size.0).to_string().as_bytes())
|
||||
.unwrap();
|
||||
stdin.write_all(&[b't']).unwrap();
|
||||
stdin.flush();
|
||||
stdin.flush().unwrap();
|
||||
} else {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
}
|
||||
|
@ -653,7 +653,7 @@ impl EmbedGrid {
|
|||
.write_all((cursor.0 + 1).to_string().as_bytes())
|
||||
.unwrap();
|
||||
stdin.write_all(&[b'R']).unwrap();
|
||||
stdin.flush();
|
||||
stdin.flush().unwrap();
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'A', State::Csi1(buf)) => {
|
||||
|
|
|
@ -28,6 +28,7 @@ use super::terminal::*;
|
|||
|
||||
use melib::backends::FolderHash;
|
||||
use melib::{EnvelopeHash, RefreshEvent};
|
||||
use nix::unistd::Pid;
|
||||
use std;
|
||||
use std::fmt;
|
||||
use std::thread;
|
||||
|
@ -69,7 +70,7 @@ pub enum ForkType {
|
|||
/// Already finished fork, we only want to restore input/output
|
||||
Finished,
|
||||
/// Embed pty
|
||||
Embed,
|
||||
Embed(Pid),
|
||||
Generic(std::process::Child),
|
||||
NewDraft(File, std::process::Child),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue