mirror of
https://github.com/atuinsh/atuin.git
synced 2025-02-03 12:10:28 +01:00
fix: Only escape control characters when writing to terminal (#1593)
When piping the output of `atuin history list` to a file, it makes more sense for the literal commands to be written rather than the escaped ones that would be printed to the terminal.
This commit is contained in:
parent
ed1ac5a2a9
commit
2bd7114cea
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
io::{self, Write},
|
||||
io::{self, IsTerminal, Write},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
@ -150,50 +150,46 @@ pub fn print_list(
|
||||
let flush_each_line = print0;
|
||||
|
||||
for h in iterator {
|
||||
match write!(
|
||||
w,
|
||||
"{}{}",
|
||||
parsed_fmt.with_args(&FmtHistory(h)),
|
||||
entry_terminator
|
||||
) {
|
||||
Ok(()) => {}
|
||||
// ignore broken pipe (issue #626)
|
||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => {
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: History output failed with the following error: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
let fh = FmtHistory(h, CmdFormat::for_output(&w));
|
||||
let args = parsed_fmt.with_args(&fh);
|
||||
check_for_write_errors(write!(w, "{args}{entry_terminator}"));
|
||||
if flush_each_line {
|
||||
match w.flush() {
|
||||
Ok(()) => {}
|
||||
// ignore broken pipe (issue #626)
|
||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => {}
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: History output failed with the following error: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
check_for_write_errors(w.flush());
|
||||
}
|
||||
}
|
||||
|
||||
if !flush_each_line {
|
||||
match w.flush() {
|
||||
Ok(()) => {}
|
||||
// ignore broken pipe (issue #626)
|
||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => {}
|
||||
Err(err) => {
|
||||
eprintln!("ERROR: History output failed with the following error: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
check_for_write_errors(w.flush());
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_write_errors(write: Result<(), io::Error>) {
|
||||
if let Err(err) = write {
|
||||
// Ignore broken pipe (issue #626)
|
||||
if err.kind() != io::ErrorKind::BrokenPipe {
|
||||
eprintln!("ERROR: History output failed with the following error: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// type wrapper around `History` so we can implement traits
|
||||
struct FmtHistory<'a>(&'a History);
|
||||
/// Wrapper around `History` so we can format output dynamically at runtime
|
||||
struct FmtHistory<'a>(&'a History, CmdFormat);
|
||||
|
||||
enum CmdFormat {
|
||||
Literal,
|
||||
Escaped,
|
||||
}
|
||||
|
||||
impl CmdFormat {
|
||||
fn for_output<O: IsTerminal>(out: &O) -> Self {
|
||||
if out.is_terminal() {
|
||||
Self::Escaped
|
||||
} else {
|
||||
Self::Literal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TIME_FMT: &[time::format_description::FormatItem<'static>] =
|
||||
format_description!("[year]-[month]-[day] [hour repr:24]:[minute]:[second]");
|
||||
@ -203,7 +199,10 @@ impl FormatKey for FmtHistory<'_> {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
fn fmt(&self, key: &str, f: &mut fmt::Formatter<'_>) -> Result<(), FormatKeyError> {
|
||||
match key {
|
||||
"command" => f.write_str(&self.0.command.trim().escape_control())?,
|
||||
"command" => match self.1 {
|
||||
CmdFormat::Literal => f.write_str(self.0.command.trim()),
|
||||
CmdFormat::Escaped => f.write_str(&self.0.command.trim().escape_control()),
|
||||
}?,
|
||||
"directory" => f.write_str(self.0.cwd.trim())?,
|
||||
"exit" => f.write_str(&self.0.exit.to_string())?,
|
||||
"duration" => {
|
||||
|
Loading…
Reference in New Issue
Block a user