Implement possibility to copy output of commands to paste buffers.

This commit is contained in:
Oleksandr Kozachuk
2022-12-17 14:54:16 +01:00
parent 6286ce4238
commit 9347bc3972
5 changed files with 48 additions and 5 deletions
+1
View File
@@ -19,3 +19,4 @@ home = "0.5.4"
sha1 = "0.10.5" sha1 = "0.10.5"
base64 = "0.20.0" base64 = "0.20.0"
rpassword = "7.2.0" rpassword = "7.2.0"
shlex = "1.1.0"
+2
View File
@@ -16,6 +16,7 @@ peg::parser! {
/ ls_cmd() / ls_cmd()
/ mv_cmd() / mv_cmd()
/ rm_cmd() / rm_cmd()
/ pb_cmd()
/ enc_cmd() / enc_cmd()
/ pass_cmd() / pass_cmd()
/ noop_cmd() / noop_cmd()
@@ -75,6 +76,7 @@ peg::parser! {
rule noop_cmd() -> Command<'input> = (" " / "\r" / "\n" / "\t")* ("#" comment())? { Command::Noop } rule noop_cmd() -> Command<'input> = (" " / "\r" / "\n" / "\t")* ("#" comment())? { Command::Noop }
rule help_cmd() -> Command<'input> = "help" { Command::Help } rule help_cmd() -> Command<'input> = "help" { Command::Help }
rule quit_cmd() -> Command<'input> = "quit" { Command::Quit } rule quit_cmd() -> Command<'input> = "quit" { Command::Quit }
rule pb_cmd() -> Command<'input> = "pb" _ e:$(([' '..='~'])+) { Command::PasteBuffer(e.to_string()) }
rule ls_cmd() -> Command<'input> = "ls" f:comment()? { Command::Ls(f.unwrap_or(".".to_string())) } rule ls_cmd() -> Command<'input> = "ls" f:comment()? { Command::Ls(f.unwrap_or(".".to_string())) }
rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) } rule add_cmd() -> Command<'input> = "add" _ name:name() { Command::Add(Rc::new(RefCell::new(name))) }
rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) } rule error_cmd() -> Command<'input> = "error" _ e:$(([' '..='~'])+) { Command::Error(LKErr::Error(e)) }
+21
View File
@@ -8,6 +8,7 @@ use crate::lk::LK;
use crate::parser::command_parser; use crate::parser::command_parser;
use crate::password::{fix_password_recursion, PasswordRef}; use crate::password::{fix_password_recursion, PasswordRef};
use crate::structs::{Command, LKErr, Radix, HISTORY_FILE}; use crate::structs::{Command, LKErr, Radix, HISTORY_FILE};
use crate::utils::{ call_cmd_with_input, get_copy_command_from_env };
#[derive(Debug)] #[derive(Debug)]
pub struct LKRead { pub struct LKRead {
@@ -183,6 +184,25 @@ impl<'a> LKEval<'a> {
out.push(pass); out.push(pass);
} }
fn cmd_pb(&self, out: &mut Vec<String>, command: &String) {
match command_parser::cmd(command) {
Ok(cmd) => {
let print = LKEval::new(cmd, self.state.clone(), prompt_password).eval();
let data = print.out.join("\n");
let (copy_command, copy_cmd_args) = get_copy_command_from_env();
match call_cmd_with_input(&copy_command, &copy_cmd_args, &data) {
Ok(s) if s.len() > 0 => {
out.push(format!("Copied output with the command {}, and got following output:", copy_command));
out.push(s.trim().to_string());
}
Ok(_) => out.push(format!("Copied output with command {}", copy_command)),
Err(e) => out.push(format!("error: failed to copy: {}", e.to_string())),
};
}
Err(e) => out.push(format!("error: faild to parse command {}: {}", command, e.to_string())),
};
}
fn cmd_ls(&self, out: &mut Vec<String>, filter: String) { fn cmd_ls(&self, out: &mut Vec<String>, filter: String) {
let re = match Regex::new(&filter) { let re = match Regex::new(&filter) {
Ok(re) => re, Ok(re) => re,
@@ -247,6 +267,7 @@ impl<'a> LKEval<'a> {
None => out.push("error: password not found".to_string()), None => out.push("error: password not found".to_string()),
}, },
Command::Enc(name) => self.cmd_enc(&mut out, name), Command::Enc(name) => self.cmd_enc(&mut out, name),
Command::PasteBuffer(command) => self.cmd_pb(&mut out, command),
Command::Pass(name) => match self.get_password(name) { Command::Pass(name) => match self.get_password(name) {
Some(p) => { Some(p) => {
self.state.borrow_mut().secrets.insert( self.state.borrow_mut().secrets.insert(
+1
View File
@@ -26,6 +26,7 @@ pub enum Command<'a> {
Rm(Name), Rm(Name),
Enc(Name), Enc(Name),
Pass(Name), Pass(Name),
PasteBuffer(String),
Comment(Name, Comment), Comment(Name, Comment),
Error(LKErr<'a>), Error(LKErr<'a>),
Noop, Noop,
+23 -5
View File
@@ -1,8 +1,11 @@
use std::env;
use std::io; use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use shlex::split;
use std::ffi::OsString;
pub fn call_cmd_with_input(cmd: &str, args: Vec<&str>, input: &str) -> io::Result<String> { pub fn call_cmd_with_input(cmd: &str, args: &Vec<String>, input: &str) -> io::Result<String> {
let mut cmd = Command::new(cmd).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; let mut cmd = Command::new(cmd).args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
let mut stdin = cmd.stdin.take().unwrap(); let mut stdin = cmd.stdin.take().unwrap();
let stdout = cmd.stdout.as_mut().unwrap(); let stdout = cmd.stdout.as_mut().unwrap();
@@ -20,15 +23,30 @@ pub fn call_cmd_with_input(cmd: &str, args: Vec<&str>, input: &str) -> io::Resul
} }
} }
pub fn get_copy_command_from_env() -> (String, Vec<String>) {
let cmd_os_str = env::var_os("LESSKEY_PB").unwrap_or_else(|| match env::consts::OS {
_ if env::var("TMUX").is_ok() => OsString::from("tmux load-buffer -"),
"macos" => OsString::from("pbcopy"),
"linux" => OsString::from("xclip"),
_ => OsString::from("cat"),
});
let args = split(&cmd_os_str.to_string_lossy()).unwrap_or_else(|| vec!["cat".to_string()]);
(args[0].clone(), args[1..].to_vec())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn cmd_exec_test() { fn cmd_exec_test() {
assert_eq!(call_cmd_with_input("true", vec![], "").unwrap(), "".to_string()); assert_eq!(call_cmd_with_input("true", &vec![], "").unwrap(), "".to_string());
assert_eq!(call_cmd_with_input("cat", vec![], "ok").unwrap(), "ok".to_string()); assert_eq!(call_cmd_with_input("cat", &vec![], "ok").unwrap(), "ok".to_string());
assert_ne!(call_cmd_with_input("cat", vec![], "notok").unwrap(), "ok".to_string()); assert_eq!(call_cmd_with_input("cat", &vec![], r###"line 1
assert_eq!(call_cmd_with_input("echo", vec!["-n", "test is ok"], "").unwrap(), "test is ok".to_string()); line 2
line 3
line 4"###).unwrap(), "line 1\nline 2\nline 3\nline 4".to_string());
assert_ne!(call_cmd_with_input("cat", &vec![], "notok").unwrap(), "ok".to_string());
assert_eq!(call_cmd_with_input("echo", &vec!["-n".to_string(), "test is ok".to_string()], "").unwrap(), "test is ok".to_string());
} }
} }