Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Highlight non-printable characters #395

Merged
merged 4 commits into from
Nov 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions assets/syntaxes/show-nonprintable.sublime-syntax
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: Highlight non-printables
file_extensions:
- show-nonprintable
scope: whitespace
contexts:
main:
- match: "•"
scope: support.function.show-nonprintable.space
- match: "├─*┤"
scope: constant.character.escape.show-nonprintable.tab
- match: "↹"
scope: constant.character.escape.show-nonprintable.tab
- match: "␊"
scope: keyword.operator.show-nonprintable.line-feed
- match: "␍"
scope: string.show-nonprintable.carriage-return
- match: "␀"
scope: entity.other.attribute-name.show-nonprintable.null
- match: "␇"
scope: entity.other.attribute-name.show-nonprintable.bell
- match: "␛"
scope: entity.other.attribute-name.show-nonprintable.escape
- match: "␈"
scope: entity.other.attribute-name.show-nonprintable.backspace
12 changes: 11 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub struct Config<'a> {
/// The explicitly configured language, if any
pub language: Option<&'a str>,

/// Whether or not to show/replace non-printable characters like space, tab and newline.
pub show_nonprintable: bool,

/// The character width of the terminal
pub term_width: usize,

Expand Down Expand Up @@ -169,7 +172,14 @@ impl App {

Ok(Config {
true_color: is_truecolor_terminal(),
language: self.matches.value_of("language"),
language: self.matches.value_of("language").or_else(|| {
if self.matches.is_present("show-all") {
Some("show-nonprintable")
} else {
None
}
}),
show_nonprintable: self.matches.is_present("show-all"),
output_wrap: if !self.interactive_output {
// We don't have the tty width when piping to another program.
// There's no point in wrapping when this is the case.
Expand Down
12 changes: 12 additions & 0 deletions src/clap_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
'--style=numbers'",
),
)
.arg(
Arg::with_name("show-all")
.long("show-all")
.alias("show-nonprintable")
.short("A")
.conflicts_with("language")
.help("Show non-printable characters (space, tab, newline, ..).")
.long_help(
"Show non-printable characters like space, tab or newline. \
Use '--tabs' to control the width of the tab-placeholders.",
),
)
.arg(
Arg::with_name("line-range")
.long("line-range")
Expand Down
1 change: 0 additions & 1 deletion src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ impl<'b> Controller<'b> {
line_ranges: &LineRanges,
) -> Result<()> {
let mut line_buffer = Vec::new();

let mut line_number: usize = 1;

while reader.read_line(&mut line_buffer)? {
Expand Down
41 changes: 40 additions & 1 deletion src/preprocessor.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use console::AnsiCodeIterator;

/// Expand tabs like an ANSI-enabled expand(1).
pub fn expand(line: &str, width: usize, cursor: &mut usize) -> String {
pub fn expand_tabs(line: &str, width: usize, cursor: &mut usize) -> String {
let mut buffer = String::with_capacity(line.len() * 2);

for chunk in AnsiCodeIterator::new(line) {
Expand Down Expand Up @@ -32,3 +32,42 @@ pub fn expand(line: &str, width: usize, cursor: &mut usize) -> String {

buffer
}

pub fn replace_nonprintable(input: &str, tab_width: usize) -> String {
let mut output = String::new();

let tab_width = if tab_width == 0 { 4 } else { tab_width };

for chr in input.chars() {
match chr {
// space
' ' => output.push('•'),
// tab
'\t' => {
if tab_width == 1 {
output.push('↹');
} else {
output.push('├');
output.push_str(&"─".repeat(tab_width - 2));
output.push('┤');
}
}
// line feed
'\x0A' => output.push('␊'),
// carriage return
'\x0D' => output.push('␍'),
// null
'\x00' => output.push('␀'),
// bell
'\x07' => output.push('␇'),
// backspace
'\x08' => output.push('␈'),
// escape
'\x1B' => output.push('␛'),
// anything else
_ => output.push(chr),
}
}

output
}
11 changes: 8 additions & 3 deletions src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use diff::get_git_diff;
use diff::LineChanges;
use errors::*;
use inputfile::{InputFile, InputFileReader};
use preprocessor::expand;
use preprocessor::{expand_tabs, replace_nonprintable};
use style::OutputWrap;
use terminal::{as_terminal_escaped, to_ansi_color};

Expand Down Expand Up @@ -177,7 +177,7 @@ impl<'a> InteractivePrinter<'a> {

fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
if self.config.tab_width > 0 {
expand(text, self.config.tab_width, cursor)
expand_tabs(text, self.config.tab_width, cursor)
} else {
text.to_string()
}
Expand Down Expand Up @@ -251,7 +251,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
line_number: usize,
line_buffer: &[u8],
) -> Result<()> {
let line = match self.content_type {
let mut line = match self.content_type {
ContentType::BINARY => {
return Ok(());
}
Expand All @@ -263,6 +263,11 @@ impl<'a> Printer for InteractivePrinter<'a> {
.unwrap_or("Invalid UTF-16BE".into()),
_ => String::from_utf8_lossy(&line_buffer).to_string(),
};

if self.config.show_nonprintable {
line = replace_nonprintable(&mut line, self.config.tab_width);
}

let regions = {
let highlighter = match self.highlighter {
Some(ref mut highlighter) => highlighter,
Expand Down