Many updates

This commit is contained in:
Austen Adler 2022-12-16 20:41:16 -05:00
parent a8672a3197
commit aad4453681
4 changed files with 130 additions and 17 deletions

12
Cargo.lock generated
View File

@ -226,8 +226,10 @@ name = "live-cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi4tui", "ansi4tui",
"anyhow",
"atty", "atty",
"crossterm", "crossterm",
"shellwords",
"tui", "tui",
] ]
@ -539,6 +541,16 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "shellwords"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e515aa4699a88148ed5ef96413ceef0048ce95b43fbc955a33bde0a70fcae6"
dependencies = [
"lazy_static",
"regex",
]
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.1.17" version = "0.1.17"

View File

@ -10,3 +10,5 @@ tui = "0.19"
crossterm = "0.25" crossterm = "0.25"
atty = "0.2.14" atty = "0.2.14"
ansi4tui = {path = "./ansi4tui/"} ansi4tui = {path = "./ansi4tui/"}
anyhow = "1.0.66"
shellwords = "1.1.0"

View File

@ -24,9 +24,22 @@ impl Default for CommandResult<'_> {
} }
pub fn run(app: &mut App) { pub fn run(app: &mut App) {
let mut child = Command::new("jq") let args = match shellwords::split(&app.cmdline) {
.arg("-C") Ok(a) => a,
.arg(&app.cmdline) Err(e) => {
app.command_result = CommandResult {
status_success: false,
stdout: Paragraph::new(""),
stderr: Paragraph::new(format!("Argument error: {e:?}")),
};
return;
}
};
let mut child = Command::new(&app.hidden_command)
.args(&app.hidden_options)
// .arg(&app.cmdline)
.args(args)
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())

View File

@ -3,6 +3,8 @@
#![allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)] #![allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)]
mod command; mod command;
use anyhow::bail;
use anyhow::Result;
use command::CommandResult; use command::CommandResult;
use std::{ use std::{
io::{self, Write}, io::{self, Write},
@ -27,6 +29,12 @@ use crossterm::{
/// The state of the application /// The state of the application
pub struct App<'a> { pub struct App<'a> {
/// The actual command to be called
hidden_command: String,
// A list of hidden options passed to the command
hidden_options: Vec<&'static str>,
/// The line the user inputs /// The line the user inputs
cmdline: String, cmdline: String,
@ -38,28 +46,103 @@ pub struct App<'a> {
/// Should every keystroke transform the original text? /// Should every keystroke transform the original text?
autorun: bool, autorun: bool,
/// Should this command be run when the program starts
run_initial: bool,
} }
impl App<'_> { impl App<'_> {
#[must_use] #[must_use]
pub fn new_with_input(input: String) -> Self { pub fn from_template(input: String, template: &Template) -> Self {
Self { let text_orig = Arc::new(input);
let command_result = CommandResult::default();
let hidden_command = template.command();
match template {
Template::Generic(_) => Self {
cmdline: String::new(), cmdline: String::new(),
text_orig: Arc::new(input), text_orig,
command_result: CommandResult::default(), command_result: CommandResult::default(),
autorun: true, autorun: true,
hidden_command,
hidden_options: vec![],
run_initial: true,
},
Template::Jq => Self {
cmdline: String::from("."),
text_orig,
command_result,
autorun: true,
hidden_command,
hidden_options: vec!["-C"],
run_initial: true,
},
Template::Grep | Template::Rg => Self {
cmdline: String::new(),
text_orig,
command_result: CommandResult::default(),
autorun: true,
hidden_command,
hidden_options: vec!["--color=always"],
run_initial: false,
},
Template::Sed | Template::Awk => Self {
cmdline: String::new(),
text_orig,
command_result: CommandResult::default(),
autorun: true,
hidden_command,
hidden_options: vec![],
run_initial: false,
},
} }
} }
} }
fn main() -> Result<(), io::Error> { pub enum Template {
if atty::is(atty::Stream::Stdin) { Generic(String),
return Err(io::Error::new( Jq,
io::ErrorKind::Other, Grep,
"You must send stdin to this command", Rg,
)); Sed,
Awk,
} }
impl Template {
pub fn from(s: String) -> Self {
match s.to_lowercase().trim() {
"jq" => Self::Jq,
"grep" => Self::Grep,
"rg" => Self::Rg,
"sed" => Self::Sed,
c => Self::Generic(c.to_string()),
}
}
pub fn command(&self) -> String {
match self {
Template::Generic(c) => c.to_string(),
Template::Jq => String::from("jq"),
Template::Grep => String::from("grep"),
Template::Rg => String::from("rg"),
Template::Sed => String::from("sed"),
Template::Awk => String::from("awk"),
}
}
}
fn main() -> Result<()> {
// Error if we aren't getting any stdin
if atty::is(atty::Stream::Stdin) {
bail!("You must send stdin to this command");
}
// Get the arguments
let arg = match std::env::args().nth(1) {
Some(a) => a,
None => bail!("You must pass a command"),
};
enable_raw_mode()?; enable_raw_mode()?;
let mut stdout = io::stdout(); let mut stdout = io::stdout();
// execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; // execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
@ -71,7 +154,7 @@ fn main() -> Result<(), io::Error> {
let text_orig = io::read_to_string(io::stdin())?; let text_orig = io::read_to_string(io::stdin())?;
// Run the actual application // Run the actual application
let app = App::new_with_input(text_orig); let app = App::from_template(text_orig, &Template::from(arg));
let _res = run_app(&mut terminal, app); let _res = run_app(&mut terminal, app);
// Restore terminal // Restore terminal
@ -87,6 +170,10 @@ fn main() -> Result<(), io::Error> {
} }
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<Option<String>> { fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<Option<String>> {
if app.run_initial {
command::run(&mut app);
}
loop { loop {
terminal.draw(|f| ui(f, &app))?; terminal.draw(|f| ui(f, &app))?;
@ -119,7 +206,6 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<O
fn ui<B: Backend>(f: &mut Frame<B>, app: &App) { fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
let vertical_chunks = Layout::default() let vertical_chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(2)
.constraints([Constraint::Min(3), Constraint::Length(3)].as_ref()) .constraints([Constraint::Min(3), Constraint::Length(3)].as_ref())
.split(f.size()); .split(f.size());