project mode structure

This commit is contained in:
Penwing 2024-02-01 13:11:43 +01:00
parent 816221370a
commit 3b47ef0ca6

View file

@ -3,191 +3,213 @@ use crate::core::format_path;
use arboard::Clipboard; use arboard::Clipboard;
use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::fcntl::{fcntl, FcntlArg, OFlag};
use std::{ use std::{
env, env,
io::{BufRead, BufReader}, io::{BufRead, BufReader},
os::fd::AsRawFd, os::fd::AsRawFd,
path::{Path, PathBuf}, path::{Path, PathBuf},
process::{Child, Command, Stdio}, process::{Child, Command, Stdio},
}; };
pub struct Buffer { pub struct Buffer {
pub output_buffer: BufReader<std::process::ChildStdout>, pub output_buffer: BufReader<std::process::ChildStdout>,
pub error_buffer: BufReader<std::process::ChildStderr>, pub error_buffer: BufReader<std::process::ChildStderr>,
pub child: Child, pub child: Child,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Line { pub struct Line {
pub text: String, pub text: String,
pub error: bool, pub error: bool,
} }
impl Line { impl Line {
fn output(text: String) -> Self { fn output(text: String) -> Self {
Self { Self {
text: remove_line_break(text), text: remove_line_break(text),
error: false, error: false,
} }
} }
fn error(text: String) -> Self { fn error(text: String) -> Self {
Self { Self {
text: remove_line_break(text), text: remove_line_break(text),
error: true, error: true,
} }
} }
} }
pub struct CommandEntry { pub struct CommandEntry {
pub env: String, pub env: String,
pub command: String, pub command: String,
pub result: Vec<Line>, pub result: Vec<Line>,
pub buffer: Option<Buffer>, pub buffer: Option<Buffer>,
pub finished: bool, pub finished: bool,
} }
impl CommandEntry { impl CommandEntry {
pub fn new(env: String, command: String) -> Self { pub fn new(env: String, command: String) -> Self {
let (buffer, result) = match execute(command.clone()) { let (buffer, result) = match execute(command.clone()) {
Ok(command_buffer) => (Some(command_buffer), vec![]), Ok(command_buffer) => (Some(command_buffer), vec![]),
Err(err) => ( Err(err) => (
None, None,
vec![Line::error(format!("failed to get results: {}", err))], vec![Line::error(format!("failed to get results: {}", err))],
), ),
}; };
CommandEntry { CommandEntry {
env, env,
command, command,
result, result,
buffer, buffer,
finished: false, finished: false,
} }
} }
pub fn update(&mut self) { pub fn update(&mut self) {
if let Some(buffer) = &mut self.buffer { if let Some(buffer) = &mut self.buffer {
let mut output = String::new(); let mut output = String::new();
loop { loop {
let _ = buffer.output_buffer.read_line(&mut output); let _ = buffer.output_buffer.read_line(&mut output);
if !remove_line_break(output.to_string()).is_empty() { if !remove_line_break(output.to_string()).is_empty() {
self.result.push(Line::output(format!("{}\n", output))); self.result.push(Line::output(format!("{}\n", output)));
output = "".to_string() output = "".to_string()
} else { } else {
break; break;
} }
} }
let mut error = String::new(); let mut error = String::new();
loop { loop {
let _ = buffer.error_buffer.read_line(&mut error); let _ = buffer.error_buffer.read_line(&mut error);
if !remove_line_break(error.to_string()).is_empty() { if !remove_line_break(error.to_string()).is_empty() {
self.result.push(Line::error(format!("{}\n", error))); self.result.push(Line::error(format!("{}\n", error)));
error = "".to_string() error = "".to_string()
} else { } else {
break; break;
} }
} }
if let Ok(Some(_exit_status)) = buffer.child.try_wait() { if let Ok(Some(_exit_status)) = buffer.child.try_wait() {
//self.result.push(Line::output(format!("Command finished with status: {:?}\n", exit_status))); //self.result.push(Line::output(format!("Command finished with status: {:?}\n", exit_status)));
self.finished = true; self.buffer_dump();
} self.finished = true;
} }
} }
}
pub fn copy_error_code(&self) { fn buffer_dump(&mut self) {
let mut txt: String = "".to_string(); // if self.buffer.is_none() {
for line in self.result.iter() { // return
if line.error { // }
txt.push_str(&format!("{}\n", line.text)); //
} // let output_buffer = &self.buffer.as_ref().unwrap().output_buffer;
} // for line in output_buffer.lines() {
let mut _clipboard = Clipboard::new().expect("Failed to initialize clipboard"); // match line {
_clipboard.set_text(txt).unwrap(); // Ok(line) => self.result.push(Line::output(format!("{}\n", line))),
} // Err(_) => return,
// }
// }
// let error_buffer = &self.buffer.as_ref().unwrap().error_buffer;
// for line in error_buffer.lines() {
// match line {
// Ok(line) => self.result.push(Line::error(format!("{}\n", line))),
// Err(_) => return,
// }
// }
}
pub fn copy_error_code(&self) {
let mut txt: String = "".to_string();
for line in self.result.iter() {
if line.error {
txt.push_str(&format!("{}\n", line.text));
}
}
let mut _clipboard = Clipboard::new().expect("Failed to initialize clipboard");
_clipboard.set_text(txt).unwrap();
}
} }
pub fn send_command(command: String) -> CommandEntry { pub fn send_command(command: String) -> CommandEntry {
let env = format_path(&env::current_dir().unwrap_or_else(|_| PathBuf::from("/"))); let env = format_path(&env::current_dir().unwrap_or_else(|_| PathBuf::from("/")));
if command.len() < 2 { if command.len() < 2 {
return CommandEntry::new(env, command); return CommandEntry::new(env, command);
} }
if &command[..2] != "cd" { if &command[..2] != "cd" {
return CommandEntry::new(env, command); return CommandEntry::new(env, command);
} }
if command.len() < 4 { if command.len() < 4 {
let mut entry = let mut entry =
CommandEntry::new(env, "echo Invalid cd, should provide path >&2".to_string()); CommandEntry::new(env, "echo Invalid cd, should provide path >&2".to_string());
entry.command = command; entry.command = command;
return entry; return entry;
} }
let path_append = command[3..].replace('~', "/home/penwing"); let path_append = command[3..].replace('~', "/home/penwing");
let path = Path::new(&path_append); let path = Path::new(&path_append);
if format!("{}", path.display()) == "/" { if format!("{}", path.display()) == "/" {
let mut entry = CommandEntry::new(env, "echo Root access denied >&2".to_string()); let mut entry = CommandEntry::new(env, "echo Root access denied >&2".to_string());
entry.command = command; entry.command = command;
return entry; return entry;
} }
if env::set_current_dir(path).is_ok() { if env::set_current_dir(path).is_ok() {
let mut entry = CommandEntry::new(env, format!("echo Moved to : {}", path.display())); let mut entry = CommandEntry::new(env, format!("echo Moved to : {}", path.display()));
entry.command = command; entry.command = command;
entry entry
} else { } else {
let mut entry = CommandEntry::new( let mut entry = CommandEntry::new(
env, env,
format!("echo Could not find path : {} >&2", path.display()), format!("echo Could not find path : {} >&2", path.display()),
); );
entry.command = command; entry.command = command;
entry entry
} }
} }
pub fn execute(command: String) -> Result<Buffer, std::io::Error> { pub fn execute(command: String) -> Result<Buffer, std::io::Error> {
let mut child = Command::new("sh") let mut child = Command::new("sh")
.arg("-c") .arg("-c")
.arg(command.clone()) .arg(command.clone())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.spawn()?; .spawn()?;
let stdout = child let stdout = child
.stdout .stdout
.take() .take()
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "Failed to open stdout"))?; .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "Failed to open stdout"))?;
let stderr = child let stderr = child
.stderr .stderr
.take() .take()
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "Failed to open stderr"))?; .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "Failed to open stderr"))?;
let stdout_fd = stdout.as_raw_fd(); let stdout_fd = stdout.as_raw_fd();
let stderr_fd = stderr.as_raw_fd(); let stderr_fd = stderr.as_raw_fd();
fcntl(stdout_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; fcntl(stdout_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
fcntl(stderr_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; fcntl(stderr_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
let output_buffer = BufReader::new(stdout); let output_buffer = BufReader::new(stdout);
let error_buffer = BufReader::new(stderr); let error_buffer = BufReader::new(stderr);
Ok(Buffer { Ok(Buffer {
output_buffer, output_buffer,
error_buffer, error_buffer,
child, child,
}) })
} }
fn remove_line_break(input: String) -> String { fn remove_line_break(input: String) -> String {
let mut text = input.clone(); let mut text = input.clone();
while text.ends_with('\n') { while text.ends_with('\n') {
text.pop(); text.pop();
if text.ends_with('\r') { if text.ends_with('\r') {
text.pop(); text.pop();
} }
} }
text text
} }