diff -Nru rust-hexyl-0.3.1/Cargo.toml rust-hexyl-0.4.0/Cargo.toml --- rust-hexyl-0.3.1/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-hexyl-0.4.0/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -12,7 +12,7 @@ [package] name = "hexyl" -version = "0.3.1" +version = "0.4.0" authors = ["David Peter "] description = "A command-line hex viewer" homepage = "https://github.com/sharkdp/hexyl" @@ -23,6 +23,12 @@ [dependencies.ansi_term] version = "0.11" +[dependencies.atty] +version = "0.2" + [dependencies.clap] version = "2" features = ["suggestions", "color", "wrap_help"] + +[dependencies.ctrlc] +version = "3.1" diff -Nru rust-hexyl-0.3.1/Cargo.toml.orig rust-hexyl-0.4.0/Cargo.toml.orig --- rust-hexyl-0.3.1/Cargo.toml.orig 2019-01-10 07:35:52.000000000 +0000 +++ rust-hexyl-0.4.0/Cargo.toml.orig 2019-01-14 09:51:24.000000000 +0000 @@ -7,10 +7,12 @@ name = "hexyl" readme = "README.md" repository = "https://github.com/sharkdp/hexyl" -version = "0.3.1" +version = "0.4.0" [dependencies] ansi_term = "0.11" +atty = "0.2" +ctrlc = "3.1" [dependencies.clap] version = "2" diff -Nru rust-hexyl-0.3.1/.cargo_vcs_info.json rust-hexyl-0.4.0/.cargo_vcs_info.json --- rust-hexyl-0.3.1/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-hexyl-0.4.0/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "98311282e5ff423c8cc40e3990b2b673e69bab22" + "sha1": "7e46a5d788545ff88c5bcff05717a2b14f199f1e" } } diff -Nru rust-hexyl-0.3.1/debian/cargo-checksum.json rust-hexyl-0.4.0/debian/cargo-checksum.json --- rust-hexyl-0.3.1/debian/cargo-checksum.json 2019-01-10 09:38:51.000000000 +0000 +++ rust-hexyl-0.4.0/debian/cargo-checksum.json 2019-01-29 20:05:21.000000000 +0000 @@ -1 +1 @@ -{"package":"1c35a2e4ae0108d8d8d324a0a3c863097f75adb69566cfe92bf885d63983b38b","files":{}} +{"package":"97e27e1d8535147ccd4c91bf322f7d1cd3984f9346cfea70b75ed5e9156ad53f","files":{}} diff -Nru rust-hexyl-0.3.1/debian/changelog rust-hexyl-0.4.0/debian/changelog --- rust-hexyl-0.3.1/debian/changelog 2019-01-10 09:38:51.000000000 +0000 +++ rust-hexyl-0.4.0/debian/changelog 2019-01-29 20:05:21.000000000 +0000 @@ -1,3 +1,9 @@ +rust-hexyl (0.4.0-1) unstable; urgency=medium + + * Package hexyl 0.4.0 from crates.io using debcargo 2.2.9 + + -- Wolfgang Silbermayr Tue, 29 Jan 2019 21:05:21 +0100 + rust-hexyl (0.3.1-1) unstable; urgency=medium * Package hexyl 0.3.1 from crates.io using debcargo 2.2.9 diff -Nru rust-hexyl-0.3.1/debian/control rust-hexyl-0.4.0/debian/control --- rust-hexyl-0.3.1/debian/control 2019-01-10 09:38:51.000000000 +0000 +++ rust-hexyl-0.4.0/debian/control 2019-01-29 20:05:21.000000000 +0000 @@ -7,10 +7,12 @@ rustc:native, libstd-rust-dev, librust-ansi-term-0.11+default-dev, + librust-atty-0.2+default-dev, librust-clap-2+color-dev, librust-clap-2+default-dev, librust-clap-2+suggestions-dev, librust-clap-2+wrap-help-dev, + librust-ctrlc-3+default-dev (>= 3.1-~~), help2man Maintainer: Debian Rust Maintainers Uploaders: diff -Nru rust-hexyl-0.3.1/debian/rules rust-hexyl-0.4.0/debian/rules --- rust-hexyl-0.3.1/debian/rules 2019-01-10 09:38:51.000000000 +0000 +++ rust-hexyl-0.4.0/debian/rules 2019-01-29 20:05:21.000000000 +0000 @@ -9,6 +9,7 @@ help2man \ --name hexyl \ --no-info \ + --no-discard-stderr \ --version-string $(DEB_VERSION_UPSTREAM) \ debian/hexyl/usr/bin/hexyl > debian/hexyl.1 dh_installman -O--buildsystem=cargo diff -Nru rust-hexyl-0.3.1/README.md rust-hexyl-0.4.0/README.md --- rust-hexyl-0.3.1/README.md 2019-01-10 07:36:30.000000000 +0000 +++ rust-hexyl-0.4.0/README.md 2019-01-14 09:51:20.000000000 +0000 @@ -22,8 +22,8 @@ ### On Debian-based systems ``` bash -wget "https://github.com/sharkdp/hexyl/releases/download/v0.3.1/hexyl_0.3.1_amd64.deb" -sudo dpkg -i hexyl_0.3.1_amd64.deb +wget "https://github.com/sharkdp/hexyl/releases/download/v0.4.0/hexyl_0.4.0_amd64.deb" +sudo dpkg -i hexyl_0.4.0_amd64.deb ``` ### On Arch Linux diff -Nru rust-hexyl-0.3.1/src/main.rs rust-hexyl-0.4.0/src/main.rs --- rust-hexyl-0.3.1/src/main.rs 2019-01-10 08:03:08.000000000 +0000 +++ rust-hexyl-0.4.0/src/main.rs 2019-01-14 09:40:13.000000000 +0000 @@ -1,23 +1,29 @@ #[macro_use] extern crate clap; extern crate ansi_term; +extern crate atty; +extern crate ctrlc; use std::fs::File; use std::io::{self, prelude::*, StdoutLock}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; use clap::{App, AppSettings, Arg}; -use ansi_term::Colour; -use ansi_term::Colour::Fixed; +use ansi_term::Color; +use ansi_term::Color::Fixed; -const BUFFER_SIZE: usize = 64; +use atty::Stream; -const COLOR_NULL: Colour = Fixed(242); // grey -const COLOR_OFFSET: Colour = Fixed(242); // grey -const COLOR_ASCII_PRINTABLE: Colour = Fixed(81); // cyan -const COLOR_ASCII_WHITESPACE: Colour = Fixed(148); // green -const COLOR_ASCII_OTHER: Colour = Fixed(197); // magenta -const COLOR_NONASCII: Colour = Fixed(208); // orange +const BUFFER_SIZE: usize = 256; + +const COLOR_NULL: Color = Fixed(242); // grey +const COLOR_OFFSET: Color = Fixed(242); // grey +const COLOR_ASCII_PRINTABLE: Color = Color::Cyan; +const COLOR_ASCII_WHITESPACE: Color = Color::Green; +const COLOR_ASCII_OTHER: Color = Color::Purple; +const COLOR_NONASCII: Color = Color::Yellow; enum ByteCategory { Null, @@ -48,7 +54,7 @@ } } - fn color(self) -> &'static Colour { + fn color(self) -> &'static Color { use ByteCategory::*; match self.category() { @@ -76,27 +82,42 @@ struct Printer<'a> { idx: usize, - line: Vec, + /// The raw bytes used as input for the current line. + raw_line: Vec, + /// The buffered line built with each byte, ready to print to stdout. + buffer_line: Vec, stdout: StdoutLock<'a>, + show_color: bool, byte_hex_table: Vec, byte_char_table: Vec, } impl<'a> Printer<'a> { - fn new(stdout: StdoutLock) -> Printer { + fn new(stdout: StdoutLock, show_color: bool) -> Printer { Printer { idx: 1, - line: vec![], + raw_line: vec![], + buffer_line: vec![], stdout, + show_color, byte_hex_table: (0u8..=u8::max_value()) - .map(|i| format!("{} ", Byte(i).color().paint(format!("{:02x}", i)))) + .map(|i| { + let byte_hex = format!("{:02x} ", i); + if show_color { + Byte(i).color().paint(byte_hex).to_string() + } else { + byte_hex + } + }) .collect(), byte_char_table: (0u8..=u8::max_value()) .map(|i| { - format!( - "{}", - Byte(i).color().paint(format!("{}", Byte(i).as_char())) - ) + let byte_char = format!("{}", Byte(i).as_char()); + if show_color { + Byte(i).color().paint(byte_char).to_string() + } else { + byte_char + } }) .collect(), } @@ -123,23 +144,23 @@ fn print_byte(&mut self, b: u8) -> io::Result<()> { if self.idx % 16 == 1 { let style = COLOR_OFFSET.normal(); - write!( - self.stdout, - "│{}{:08x}{}│ ", - style.prefix(), - self.idx - 1, - style.suffix() - )?; + let byte_index = format!("{:08x}", self.idx - 1); + let formatted_string = if self.show_color { + format!("{}", style.paint(byte_index)) + } else { + byte_index + }; + let _ = write!(&mut self.buffer_line, "│{}│ ", formatted_string); } - write!(self.stdout, "{}", self.byte_hex_table[b as usize])?; - self.line.push(b); + write!(&mut self.buffer_line, "{}", self.byte_hex_table[b as usize])?; + self.raw_line.push(b); match self.idx % 16 { - 8 => write!(self.stdout, "┊ ")?, - 0 => { - self.print_textline()?; + 8 => { + let _ = write!(&mut self.buffer_line, "┊ "); } + 0 => self.print_textline()?, _ => {} } @@ -149,48 +170,54 @@ } fn print_textline(&mut self) -> io::Result<()> { - let len = self.line.len(); + let len = self.raw_line.len(); if len == 0 { return Ok(()); } if len < 8 { - write!( - self.stdout, + let _ = write!( + &mut self.buffer_line, "{0:1$}┊{0:2$}│", "", 3 * (8 - len), 1 + 3 * 8 - )?; + ); } else { - write!(self.stdout, "{0:1$}│", "", 3 * (16 - len))?; + let _ = write!(&mut self.buffer_line, "{0:1$}│", "", 3 * (16 - len)); } let mut idx = 1; - for &b in self.line.iter() { - write!(self.stdout, "{}", self.byte_char_table[b as usize])?; + for &b in self.raw_line.iter() { + let _ = write!( + &mut self.buffer_line, + "{}", + self.byte_char_table[b as usize] + ); if idx == 8 { - write!(self.stdout, "┊").ok(); + let _ = write!(&mut self.buffer_line, "┊"); } idx += 1; } if len < 8 { - writeln!(self.stdout, "{0:1$}┊{0:2$}│ ", "", 8 - len, 8)?; + let _ = writeln!(&mut self.buffer_line, "{0:1$}┊{0:2$}│ ", "", 8 - len, 8); } else { - writeln!(self.stdout, "{0:1$}│", "", 16 - len)?; + let _ = writeln!(&mut self.buffer_line, "{0:1$}│", "", 16 - len); } + self.stdout.write_all(&self.buffer_line)?; - self.line.clear(); + self.raw_line.clear(); + self.buffer_line.clear(); Ok(()) } } -fn run() -> io::Result<()> { +fn run() -> Result<(), Box<::std::error::Error>> { let app = App::new(crate_name!()) .setting(AppSettings::ColorAuto) .setting(AppSettings::ColoredHelp) @@ -205,10 +232,22 @@ .long("length") .takes_value(true) .value_name("N") - .help("read only N bytes from the input"), + .help("Read only N bytes from the input"), + ) + .arg( + Arg::with_name("color") + .long("color") + .takes_value(true) + .value_name("when") + .possible_values(&["always", "auto", "never"]) + .default_value("always") + .help( + "When to use colors. The auto-mode only displays colors if the output \ + goes to an interactive terminal", + ), ); - let matches = app.get_matches(); + let matches = app.get_matches_safe()?; let stdin = io::stdin(); @@ -224,23 +263,43 @@ reader = Box::new(reader.take(length)); } + let show_color = match matches.value_of("color") { + Some("never") => false, + Some("auto") => atty::is(Stream::Stdout), + _ => true, + }; + + // Set up Ctrl-C handler + let cancelled = Arc::new(AtomicBool::new(false)); + let c = cancelled.clone(); + + ctrlc::set_handler(move || { + c.store(true, Ordering::SeqCst); + }) + .expect("Error setting Ctrl-C handler"); + let stdout = io::stdout(); - let mut printer = Printer::new(stdout.lock()); + let mut printer = Printer::new(stdout.lock(), show_color); printer.header(); let mut buffer = [0; BUFFER_SIZE]; - loop { + 'mainloop: loop { let size = reader.read(&mut buffer)?; if size == 0 { break; } + if cancelled.load(Ordering::SeqCst) { + eprintln!("hexyl has been cancelled."); + std::process::exit(130); // Set exit code to 128 + SIGINT + } + for b in &buffer[..size] { let res = printer.print_byte(*b); if res.is_err() { // Broken pipe - break; + break 'mainloop; } } } @@ -258,11 +317,21 @@ let _ = ansi_term::enable_ansi_support(); let result = run(); - match result { - Err(err) => { + + if let Err(err) = result { + if let Some(clap_err) = err.downcast_ref::() { + eprint!("{}", clap_err); // Clap errors already have newlines + + match clap_err.kind { + // The exit code should not indicate an error for --help / --version + clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => { + std::process::exit(0) + } + _ => (), + } + } else { eprintln!("Error: {}", err); - std::process::exit(1); } - Ok(()) => {} + std::process::exit(1); } }