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)]
|
#![allow(dead_code, unused_imports)]
|
||||||
// Hard mode
|
|
||||||
#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
|
#![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::{
|
use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
@ -11,6 +11,7 @@ use std::{
|
|||||||
thread,
|
thread,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
use tui::text::Text;
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::{Backend, CrosstermBackend},
|
backend::{Backend, CrosstermBackend},
|
||||||
layout::{Constraint, Direction, Layout, Rect},
|
layout::{Constraint, Direction, Layout, Rect},
|
||||||
@ -24,47 +25,28 @@ use crossterm::{
|
|||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
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
|
/// The state of the application
|
||||||
struct App {
|
pub struct App<'a> {
|
||||||
/// The line the user inputs
|
/// The line the user inputs
|
||||||
cmdline: String,
|
cmdline: String,
|
||||||
|
|
||||||
/// Original text
|
/// Original text
|
||||||
text_orig: Arc<String>,
|
text_orig: Arc<String>,
|
||||||
|
|
||||||
command_result: CommandResult,
|
/// The result of a command execution
|
||||||
|
command_result: CommandResult<'a>,
|
||||||
/// Transformed text
|
|
||||||
// text_transformed: String,
|
|
||||||
// text_transformed_stderr: String,
|
|
||||||
|
|
||||||
/// Should every keystroke transform the original text?
|
/// Should every keystroke transform the original text?
|
||||||
autorun: bool,
|
autorun: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App<'_> {
|
||||||
|
#[must_use]
|
||||||
pub fn new_with_input(input: String) -> Self {
|
pub fn new_with_input(input: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cmdline: String::from(""),
|
cmdline: String::new(),
|
||||||
text_orig: Arc::new(input),
|
text_orig: Arc::new(input),
|
||||||
command_result: CommandResult::default(),
|
command_result: CommandResult::default(),
|
||||||
// text_transformed: String::from(""),
|
|
||||||
autorun: true,
|
autorun: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,65 +86,36 @@ fn main() -> Result<(), io::Error> {
|
|||||||
Ok(())
|
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 {
|
loop {
|
||||||
terminal.draw(|f| ui(f, &app))?;
|
terminal.draw(|f| ui(f, &app))?;
|
||||||
|
|
||||||
if let Event::Key(key) = event::read()? {
|
if let Event::Key(key) = event::read()? {
|
||||||
match key.code {
|
match key.code {
|
||||||
KeyCode::Esc => {
|
KeyCode::Esc => {
|
||||||
return Ok(());
|
return Ok(None);
|
||||||
}
|
}
|
||||||
KeyCode::Char(c) => {
|
KeyCode::Char(c) => {
|
||||||
app.cmdline.push(c);
|
app.cmdline.push(c);
|
||||||
if app.autorun {
|
if app.autorun {
|
||||||
run_command(&mut app);
|
command::run(&mut app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Backspace => {
|
KeyCode::Backspace => {
|
||||||
app.cmdline.pop();
|
app.cmdline.pop();
|
||||||
if app.autorun {
|
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) {
|
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)
|
||||||
@ -193,13 +146,16 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
|
|||||||
f.set_cursor(
|
f.set_cursor(
|
||||||
vertical_chunks[1].x + app.cmdline.len() as u16 + 1,
|
vertical_chunks[1].x + app.cmdline.len() as u16 + 1,
|
||||||
vertical_chunks[1].y + 1,
|
vertical_chunks[1].y + 1,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_output<B: Backend>(f: &mut Frame<B>, output_region: Rect, app: &App) {
|
fn ui_output<B: Backend>(f: &mut Frame<B>, output_region: Rect, app: &App) {
|
||||||
if app.command_result.status_success {
|
if app.command_result.status_success {
|
||||||
f.render_widget(
|
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)),
|
.block(Block::default().title("New").borders(Borders::ALL)),
|
||||||
output_region,
|
output_region,
|
||||||
);
|
);
|
||||||
@ -210,12 +166,18 @@ fn ui_output<B: Backend>(f: &mut Frame<B>, output_region: Rect, app: &App) {
|
|||||||
.split(output_region);
|
.split(output_region);
|
||||||
|
|
||||||
f.render_widget(
|
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)),
|
.block(Block::default().title("Output").borders(Borders::ALL)),
|
||||||
chunks[0],
|
chunks[0],
|
||||||
);
|
);
|
||||||
f.render_widget(
|
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)),
|
.block(Block::default().title("Error").borders(Borders::ALL)),
|
||||||
chunks[1],
|
chunks[1],
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user