Cleanup
This commit is contained in:
parent
3a0c42175b
commit
a8672a3197
55
src/command.rs
Normal file
55
src/command.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use std::{
|
||||
io::Write,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use tui::widgets::Paragraph;
|
||||
|
||||
use crate::App;
|
||||
|
||||
pub struct CommandResult<'a> {
|
||||
pub status_success: bool,
|
||||
pub stdout: Paragraph<'a>,
|
||||
pub stderr: Paragraph<'a>,
|
||||
}
|
||||
|
||||
impl Default for CommandResult<'_> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
status_success: true,
|
||||
stdout: Paragraph::new(""),
|
||||
stderr: Paragraph::new(""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(app: &mut App) {
|
||||
let mut child = Command::new("jq")
|
||||
.arg("-C")
|
||||
.arg(&app.cmdline)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Could not spawn child process");
|
||||
|
||||
let mut stdin = child.stdin.take().expect("Could not take stdin");
|
||||
let text_orig_clone = app.text_orig.clone();
|
||||
std::thread::spawn(move || {
|
||||
stdin
|
||||
.write_all(text_orig_clone.as_bytes())
|
||||
.expect("Failed to write to stdin");
|
||||
});
|
||||
|
||||
// Collect the output
|
||||
let output = child.wait_with_output().expect("Failed to read stdout");
|
||||
|
||||
let stderr_string = ansi4tui::bytes_to_text(output.stderr);
|
||||
let stdout_string = ansi4tui::bytes_to_text(output.stdout);
|
||||
|
||||
app.command_result = CommandResult {
|
||||
status_success: output.status.success(),
|
||||
stdout: Paragraph::new(stdout_string),
|
||||
stderr: Paragraph::new(stderr_string),
|
||||
}
|
||||
}
|
98
src/main.rs
98
src/main.rs
@ -1,9 +1,9 @@
|
||||
// Easy mode
|
||||
#![allow(dead_code, unused_imports)]
|
||||
// Hard mode
|
||||
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
|
||||
// #![allow(clippy::cast_possible_truncation, clippy::multiple_crate_versions)]
|
||||
#![allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)]
|
||||
|
||||
mod command;
|
||||
use command::CommandResult;
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
process::{Command, Stdio},
|
||||
@ -11,6 +11,7 @@ use std::{
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use tui::text::Text;
|
||||
use tui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
@ -24,47 +25,28 @@ use crossterm::{
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
|
||||
struct CommandResult {
|
||||
pub status_success: bool,
|
||||
pub stdout: String,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
impl Default for CommandResult {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
status_success: true,
|
||||
stdout: String::default(),
|
||||
stderr: String::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The state of the application
|
||||
struct App {
|
||||
pub struct App<'a> {
|
||||
/// The line the user inputs
|
||||
cmdline: String,
|
||||
|
||||
/// Original text
|
||||
text_orig: Arc<String>,
|
||||
|
||||
command_result: CommandResult,
|
||||
|
||||
/// Transformed text
|
||||
// text_transformed: String,
|
||||
// text_transformed_stderr: String,
|
||||
/// The result of a command execution
|
||||
command_result: CommandResult<'a>,
|
||||
|
||||
/// Should every keystroke transform the original text?
|
||||
autorun: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
impl App<'_> {
|
||||
#[must_use]
|
||||
pub fn new_with_input(input: String) -> Self {
|
||||
Self {
|
||||
cmdline: String::from(""),
|
||||
cmdline: String::new(),
|
||||
text_orig: Arc::new(input),
|
||||
command_result: CommandResult::default(),
|
||||
// text_transformed: String::from(""),
|
||||
autorun: true,
|
||||
}
|
||||
}
|
||||
@ -104,65 +86,36 @@ fn main() -> Result<(), io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
|
||||
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<Option<String>> {
|
||||
loop {
|
||||
terminal.draw(|f| ui(f, &app))?;
|
||||
|
||||
if let Event::Key(key) = event::read()? {
|
||||
match key.code {
|
||||
KeyCode::Esc => {
|
||||
return Ok(());
|
||||
return Ok(None);
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
app.cmdline.push(c);
|
||||
if app.autorun {
|
||||
run_command(&mut app);
|
||||
command::run(&mut app);
|
||||
}
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
app.cmdline.pop();
|
||||
if app.autorun {
|
||||
run_command(&mut app);
|
||||
command::run(&mut app);
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {}
|
||||
KeyCode::Enter => {
|
||||
return Ok(Some(app.cmdline.clone()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_command(app: &mut App) {
|
||||
let mut child = Command::new("jq")
|
||||
.arg("-C")
|
||||
.arg(&app.cmdline)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Could not spawn child process");
|
||||
|
||||
let mut stdin = child.stdin.take().expect("Could not take stdin");
|
||||
let text_orig_clone = app.text_orig.clone();
|
||||
std::thread::spawn(move || {
|
||||
stdin
|
||||
.write_all(text_orig_clone.as_bytes())
|
||||
.expect("Failed to write to stdin")
|
||||
});
|
||||
|
||||
// Collect the output
|
||||
let output = child.wait_with_output().expect("Failed to read stdout");
|
||||
|
||||
let stderr_string = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
let stdout_string = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
|
||||
app.command_result = CommandResult {
|
||||
status_success: output.status.success(),
|
||||
stdout: stdout_string,
|
||||
stderr: stderr_string,
|
||||
}
|
||||
}
|
||||
|
||||
fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
|
||||
let vertical_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
@ -193,13 +146,16 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
|
||||
f.set_cursor(
|
||||
vertical_chunks[1].x + app.cmdline.len() as u16 + 1,
|
||||
vertical_chunks[1].y + 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn ui_output<B: Backend>(f: &mut Frame<B>, output_region: Rect, app: &App) {
|
||||
if app.command_result.status_success {
|
||||
f.render_widget(
|
||||
Paragraph::new(app.command_result.stdout.as_ref())
|
||||
// TODO: Do we really have to clone here?
|
||||
app.command_result
|
||||
.stdout
|
||||
.clone()
|
||||
.block(Block::default().title("New").borders(Borders::ALL)),
|
||||
output_region,
|
||||
);
|
||||
@ -210,12 +166,18 @@ fn ui_output<B: Backend>(f: &mut Frame<B>, output_region: Rect, app: &App) {
|
||||
.split(output_region);
|
||||
|
||||
f.render_widget(
|
||||
Paragraph::new(app.command_result.stdout.as_ref())
|
||||
// TODO: Do we really have to clone here?
|
||||
app.command_result
|
||||
.stdout
|
||||
.clone()
|
||||
.block(Block::default().title("Output").borders(Borders::ALL)),
|
||||
chunks[0],
|
||||
);
|
||||
f.render_widget(
|
||||
Paragraph::new(app.command_result.stderr.as_ref())
|
||||
// TODO: Do we really have to clone here?
|
||||
app.command_result
|
||||
.stderr
|
||||
.clone()
|
||||
.block(Block::default().title("Error").borders(Borders::ALL)),
|
||||
chunks[1],
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user