提交 56d4d4c1 编写于 作者: B Benjamin Sago

Also escape characters in links and headings

Doing this meant that the escaping functionality got used in three places, so it was extracted into a generalised function in its own module.

This is slighly slower for the case where escaped characters are displayed in the same colour as the displayable characters, which happens when listing a directory’s name when recursing. Optimise this, yeah?
上级 2d6d4624
......@@ -172,6 +172,13 @@ Vagrant.configure(2) do |config|
echo -ne "#{test_dir}/file-names/invalid-utf8-2: [\\xc3\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-3: [\\xe2\\x82\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-4: [\\xf0\\x28\\x8c\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]" | xargs -0 mkdir
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/subfile" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/another: [\\n]" | xargs -0 touch
mkdir "#{test_dir}/file-names/links"
ln -s "#{test_dir}/file-names/new-line-dir"*/* "#{test_dir}/file-names/links"
EOF
......
......@@ -23,9 +23,12 @@ use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path};
use ansi_term::{ANSIStrings, Style};
use fs::{Dir, File};
use options::{Options, View};
pub use options::Misfire;
use output::escape;
mod fs;
mod info;
......@@ -116,7 +119,9 @@ impl<'w, W: Write + 'w> Exa<'w, W> {
}
if !is_only_dir {
writeln!(self.writer, "{}:", dir.path.display())?;
let mut bits = Vec::new();
escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
writeln!(self.writer, "{}:", ANSIStrings(&bits))?;
}
let mut children = Vec::new();
......
use ansi_term::{ANSIString, Style};
pub fn escape<'a>(string: String, bits: &mut Vec<ANSIString<'a>>, good: Style, bad: Style) {
if string.chars().all(|c| c >= 0x20 as char) {
bits.push(good.paint(string));
}
else {
for c in string.chars() {
// The `escape_default` method on `char` is *almost* what we want here, but
// it still escapes non-ASCII UTF-8 characters, which are still printable.
if c >= 0x20 as char {
// TODO: This allocates way too much,
// hence the `all` check above.
let mut s = String::new();
s.push(c);
bits.push(good.paint(s));
} else {
let s = c.escape_default().collect::<String>();
bits.push(bad.paint(s));
}
}
}
}
......@@ -2,6 +2,7 @@ use ansi_term::{ANSIString, Style};
use fs::{File, FileTarget};
use output::Colours;
use output::escape;
use output::cell::TextCellContents;
......@@ -29,7 +30,7 @@ impl<'a, 'dir> FileName<'a, 'dir> {
bits.push(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
escape(parent.to_string_lossy().to_string(), &mut bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
......@@ -55,7 +56,7 @@ impl<'a, 'dir> FileName<'a, 'dir> {
bits.push(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(self.colours.symlink_path.paint(parent.to_string_lossy().to_string()));
escape(parent.to_string_lossy().to_string(), &mut bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
......@@ -118,28 +119,7 @@ impl<'a, 'dir> FileName<'a, 'dir> {
fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
let file_style = self.style();
let mut bits = Vec::new();
if self.file.name.chars().all(|c| c >= 0x20 as char) {
bits.push(file_style.paint(self.file.name.clone()));
}
else {
for c in self.file.name.chars() {
// The `escape_default` method on `char` is *almost* what we want here, but
// it still escapes non-ASCII UTF-8 characters, which are still printable.
if c >= 0x20 as char {
// TODO: This allocates way too much,
// hence the `all` check above.
let mut s = String::new();
s.push(c);
bits.push(file_style.paint(s));
} else {
let s = c.escape_default().collect::<String>();
bits.push(self.colours.control_char.paint(s));
}
}
}
escape(self.file.name.clone(), &mut bits, file_style, self.colours.control_char);
bits
}
......
......@@ -4,6 +4,7 @@ pub use self::details::Details;
pub use self::grid_details::GridDetails;
pub use self::grid::Grid;
pub use self::lines::Lines;
pub use self::escape::escape;
mod grid;
pub mod details;
......@@ -14,3 +15,4 @@ mod cell;
mod colours;
mod tree;
pub mod file_name;
mod escape;
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] return: [\r]
ascii: hello invalid-utf8-1: [�] tab: [\t]
backspace: [\u{8}] invalid-utf8-2: [�(] utf-8: pâté
bell: [\u{7}] invalid-utf8-3: [�(] vertical-tab: [\u{b}]
emoji: [🆒] invalid-utf8-4: [�(�(]
escape: [\u{1b}] new-line: [\n]
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [�] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [�(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [�(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [�(�(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]
......@@ -9,6 +9,8 @@ invalid-utf8-1: [�]
invalid-utf8-2: [�(]
invalid-utf8-3: [�(]
invalid-utf8-4: [�(�(]
links
new-line-dir: [\n]
new-line: [\n]
return: [\r]
tab: [\t]
......
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [�] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [�(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [�(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [�(�(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]
/testcases/file-names/links:
another: [\n] subfile
/testcases/file-names/new-line-dir: [\n]:
another: [\n] subfile
/testcases/file-names
├── ansi: [\u{1b}[34mblue\u{1b}[0m]
├── ascii: hello
├── backspace: [\u{8}]
├── bell: [\u{7}]
├── emoji: [🆒]
├── escape: [\u{1b}]
├── form-feed: [\u{c}]
├── invalid-utf8-1: [�]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-2: [�(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-3: [�(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-4: [�(�(]
│ └── <Error: path somehow contained a NUL?>
├── links
│ ├── another: [\n] -> /testcases/file-names/new-line-dir: [\n]/another: [\n]
│ └── subfile -> /testcases/file-names/new-line-dir: [\n]/subfile
├── new-line-dir: [\n]
│ ├── another: [\n]
│ └── subfile
├── new-line: [\n]
├── return: [\r]
├── tab: [\t]
├── utf-8: pâté
└── vertical-tab: [\u{b}]
ansi: [\u{1b}[34mblue\u{1b}[0m] ascii: hello backspace: [\u{8}]
bell: [\u{7}] emoji: [🆒] escape: [\u{1b}]
form-feed: [\u{c}] invalid-utf8-1: [�] invalid-utf8-2: [�(]
invalid-utf8-3: [�(] invalid-utf8-4: [�(�(] new-line: [\n]
return: [\r] tab: [\t] utf-8: pâté
vertical-tab: [\u{b}]
invalid-utf8-3: [�(] invalid-utf8-4: [�(�(] links
new-line-dir: [\n] new-line: [\n] return: [\r]
tab: [\t] utf-8: pâté vertical-tab: [\u{b}]
......@@ -55,9 +55,12 @@ sudo -u cassowary $exa $testcases/permissions -lghR 2>&1 | diff -q - $results/pe
$exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions || exit 1
# File names
# (Mostly escaping control characters in file names)
COLUMNS=80 $exa $testcases/file-names 2>&1 | diff -q - $results/file_names || exit 1
COLUMNS=80 $exa $testcases/file-names -x 2>&1 | diff -q - $results/file_names_x || exit 1
COLUMNS=80 $exa $testcases/file-names -R 2>&1 | diff -q - $results/file_names_R || exit 1
$exa $testcases/file-names -1 2>&1 | diff -q - $results/file_names_1 || exit 1
$exa $testcases/file-names -T 2>&1 | diff -q - $results/file_names_T || exit 1
# File types
$exa $testcases/file-names-exts -1 2>&1 | diff -q - $results/file-names-exts || exit 1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册