mirror of
https://github.com/uutils/coreutils
synced 2024-12-12 14:22:41 +00:00
ls: gnu color-norm
test fix (#6481)
This commit is contained in:
parent
92c3de5387
commit
92665144c9
6 changed files with 342 additions and 103 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -1383,9 +1383,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lscolors"
|
||||
version = "0.16.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab0b209ec3976527806024406fe765474b9a1750a0ed4b8f0372364741f50e7b"
|
||||
checksum = "02a5d67fc8a616f260ee9a36868547da09ac24178a4b84708cd8ea781372fbe4"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
]
|
||||
|
@ -1484,9 +1484,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.49.0"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68"
|
||||
checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
|
|
@ -290,7 +290,7 @@ hostname = "0.4"
|
|||
indicatif = "0.17.8"
|
||||
itertools = "0.13.0"
|
||||
libc = "0.2.153"
|
||||
lscolors = { version = "0.16.0", default-features = false, features = [
|
||||
lscolors = { version = "0.18.0", default-features = false, features = [
|
||||
"gnu_legacy",
|
||||
] }
|
||||
memchr = "2.7.2"
|
||||
|
|
162
src/uu/ls/src/colors.rs
Normal file
162
src/uu/ls/src/colors.rs
Normal file
|
@ -0,0 +1,162 @@
|
|||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use super::get_metadata_with_deref_opt;
|
||||
use super::PathData;
|
||||
use lscolors::{Indicator, LsColors, Style};
|
||||
use std::fs::{DirEntry, Metadata};
|
||||
use std::io::{BufWriter, Stdout};
|
||||
|
||||
/// We need this struct to be able to store the previous style.
|
||||
/// This because we need to check the previous value in case we don't need
|
||||
/// the reset
|
||||
pub(crate) struct StyleManager<'a> {
|
||||
/// last style that is applied, if `None` that means reset is applied.
|
||||
pub(crate) current_style: Option<Style>,
|
||||
/// `true` if the initial reset is applied
|
||||
pub(crate) initial_reset_is_done: bool,
|
||||
pub(crate) colors: &'a LsColors,
|
||||
}
|
||||
|
||||
impl<'a> StyleManager<'a> {
|
||||
pub(crate) fn new(colors: &'a LsColors) -> Self {
|
||||
Self {
|
||||
initial_reset_is_done: false,
|
||||
current_style: None,
|
||||
colors,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_style(&mut self, new_style: Option<&Style>, name: &str) -> String {
|
||||
let mut style_code = String::new();
|
||||
let mut force_suffix_reset: bool = false;
|
||||
|
||||
// if reset is done we need to apply normal style before applying new style
|
||||
if self.is_reset() {
|
||||
if let Some(norm_sty) = self.get_normal_style().copied() {
|
||||
style_code.push_str(&self.get_style_code(&norm_sty));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(new_style) = new_style {
|
||||
// we only need to apply a new style if it's not the same as the current
|
||||
// style for example if normal is the current style and a file with
|
||||
// normal style is to be printed we could skip printing new color
|
||||
// codes
|
||||
if !self.is_current_style(new_style) {
|
||||
style_code.push_str(&self.reset(!self.initial_reset_is_done));
|
||||
style_code.push_str(&self.get_style_code(new_style));
|
||||
}
|
||||
}
|
||||
// if new style is None and current style is Normal we should reset it
|
||||
else if matches!(self.get_normal_style().copied(), Some(norm_style) if self.is_current_style(&norm_style))
|
||||
{
|
||||
style_code.push_str(&self.reset(false));
|
||||
// even though this is an unnecessary reset for gnu compatibility we allow it here
|
||||
force_suffix_reset = true;
|
||||
}
|
||||
|
||||
format!("{}{}{}", style_code, name, self.reset(force_suffix_reset))
|
||||
}
|
||||
|
||||
/// Resets the current style and returns the default ANSI reset code to
|
||||
/// reset all text formatting attributes. If `force` is true, the reset is
|
||||
/// done even if the reset has been applied before.
|
||||
pub(crate) fn reset(&mut self, force: bool) -> String {
|
||||
// todo:
|
||||
// We need to use style from `Indicator::Reset` but as of now ls colors
|
||||
// uses a fallback mechanism and because of that if `Indicator::Reset`
|
||||
// is not specified it would fallback to `Indicator::Normal` which seems
|
||||
// to be non compatible with gnu
|
||||
if self.current_style.is_some() || force {
|
||||
self.initial_reset_is_done = true;
|
||||
self.current_style = None;
|
||||
return "\x1b[0m".to_string();
|
||||
}
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub(crate) fn get_style_code(&mut self, new_style: &Style) -> String {
|
||||
self.current_style = Some(*new_style);
|
||||
let mut nu_a_style = new_style.to_nu_ansi_term_style();
|
||||
nu_a_style.prefix_with_reset = false;
|
||||
let mut ret = nu_a_style.paint("").to_string();
|
||||
// remove the suffix reset
|
||||
ret.truncate(ret.len() - 4);
|
||||
ret
|
||||
}
|
||||
|
||||
pub(crate) fn is_current_style(&mut self, new_style: &Style) -> bool {
|
||||
matches!(&self.current_style,Some(style) if style == new_style )
|
||||
}
|
||||
|
||||
pub(crate) fn is_reset(&mut self) -> bool {
|
||||
self.current_style.is_none()
|
||||
}
|
||||
|
||||
pub(crate) fn get_normal_style(&self) -> Option<&Style> {
|
||||
self.colors.style_for_indicator(Indicator::Normal)
|
||||
}
|
||||
pub(crate) fn apply_normal(&mut self) -> String {
|
||||
if let Some(sty) = self.get_normal_style().copied() {
|
||||
return self.get_style_code(&sty);
|
||||
}
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub(crate) fn apply_style_based_on_metadata(
|
||||
&mut self,
|
||||
path: &PathData,
|
||||
md_option: Option<&Metadata>,
|
||||
name: &str,
|
||||
) -> String {
|
||||
let style = self
|
||||
.colors
|
||||
.style_for_path_with_metadata(&path.p_buf, md_option);
|
||||
self.apply_style(style, name)
|
||||
}
|
||||
|
||||
pub(crate) fn apply_style_based_on_dir_entry(
|
||||
&mut self,
|
||||
dir_entry: &DirEntry,
|
||||
name: &str,
|
||||
) -> String {
|
||||
let style = self.colors.style_for(dir_entry);
|
||||
self.apply_style(style, name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Colors the provided name based on the style determined for the given path
|
||||
/// This function is quite long because it tries to leverage DirEntry to avoid
|
||||
/// unnecessary calls to stat()
|
||||
/// and manages the symlink errors
|
||||
pub(crate) fn color_name(
|
||||
name: &str,
|
||||
path: &PathData,
|
||||
style_manager: &mut StyleManager,
|
||||
out: &mut BufWriter<Stdout>,
|
||||
target_symlink: Option<&PathData>,
|
||||
) -> String {
|
||||
if !path.must_dereference {
|
||||
// If we need to dereference (follow) a symlink, we will need to get the metadata
|
||||
if let Some(de) = &path.de {
|
||||
// There is a DirEntry, we don't need to get the metadata for the color
|
||||
return style_manager.apply_style_based_on_dir_entry(de, name);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(target) = target_symlink {
|
||||
// use the optional target_symlink
|
||||
// Use fn get_metadata_with_deref_opt instead of get_metadata() here because ls
|
||||
// should not exit with an err, if we are unable to obtain the target_metadata
|
||||
let md_res = get_metadata_with_deref_opt(&target.p_buf, path.must_dereference);
|
||||
let md = md_res.or(path.p_buf.symlink_metadata());
|
||||
style_manager.apply_style_based_on_metadata(path, md.ok().as_ref(), name)
|
||||
} else {
|
||||
let md_option = path.get_metadata(out);
|
||||
let symlink_metadata = path.p_buf.symlink_metadata().ok();
|
||||
let md = md_option.or(symlink_metadata.as_ref());
|
||||
style_manager.apply_style_based_on_metadata(path, md, name)
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ use clap::{
|
|||
crate_version, Arg, ArgAction, Command,
|
||||
};
|
||||
use glob::{MatchOptions, Pattern};
|
||||
use lscolors::{LsColors, Style};
|
||||
use lscolors::LsColors;
|
||||
|
||||
use ansi_width::ansi_width;
|
||||
use std::{cell::OnceCell, num::IntErrorKind};
|
||||
|
@ -68,6 +68,8 @@ use uucore::{
|
|||
use uucore::{help_about, help_section, help_usage, parse_glob, show, show_error, show_warning};
|
||||
mod dired;
|
||||
use dired::{is_dired_arg_present, DiredOutput};
|
||||
mod colors;
|
||||
use colors::{color_name, StyleManager};
|
||||
#[cfg(not(feature = "selinux"))]
|
||||
static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)";
|
||||
#[cfg(feature = "selinux")]
|
||||
|
@ -2038,7 +2040,7 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
|
|||
let mut dirs = Vec::<PathData>::new();
|
||||
let mut out = BufWriter::new(stdout());
|
||||
let mut dired = DiredOutput::default();
|
||||
let mut style_manager = StyleManager::new();
|
||||
let mut style_manager = config.color.as_ref().map(StyleManager::new);
|
||||
let initial_locs_len = locs.len();
|
||||
|
||||
for loc in locs {
|
||||
|
@ -2072,6 +2074,15 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
|
|||
sort_entries(&mut files, config, &mut out);
|
||||
sort_entries(&mut dirs, config, &mut out);
|
||||
|
||||
if let Some(style_manager) = style_manager.as_mut() {
|
||||
// ls will try to write a reset before anything is written if normal
|
||||
// color is given
|
||||
if style_manager.get_normal_style().is_some() {
|
||||
let to_write = style_manager.reset(true);
|
||||
write!(out, "{}", to_write)?;
|
||||
}
|
||||
}
|
||||
|
||||
display_items(&files, config, &mut out, &mut dired, &mut style_manager)?;
|
||||
|
||||
for (pos, path_data) in dirs.iter().enumerate() {
|
||||
|
@ -2245,7 +2256,7 @@ fn enter_directory(
|
|||
out: &mut BufWriter<Stdout>,
|
||||
listed_ancestors: &mut HashSet<FileInformation>,
|
||||
dired: &mut DiredOutput,
|
||||
style_manager: &mut StyleManager,
|
||||
style_manager: &mut Option<StyleManager>,
|
||||
) -> UResult<()> {
|
||||
// Create vec of entries with initial dot files
|
||||
let mut entries: Vec<PathData> = if config.files == Files::All {
|
||||
|
@ -2469,7 +2480,7 @@ fn display_items(
|
|||
config: &Config,
|
||||
out: &mut BufWriter<Stdout>,
|
||||
dired: &mut DiredOutput,
|
||||
style_manager: &mut StyleManager,
|
||||
style_manager: &mut Option<StyleManager>,
|
||||
) -> UResult<()> {
|
||||
// `-Z`, `--context`:
|
||||
// Display the SELinux security context or '?' if none is found. When used with the `-l`
|
||||
|
@ -2521,6 +2532,11 @@ fn display_items(
|
|||
|
||||
let padding = calculate_padding_collection(items, config, out);
|
||||
|
||||
// we need to apply normal color to non filename output
|
||||
if let Some(style_manager) = style_manager {
|
||||
write!(out, "{}", style_manager.apply_normal())?;
|
||||
}
|
||||
|
||||
let mut names_vec = Vec::new();
|
||||
for i in items {
|
||||
let more_info = display_additional_leading_info(i, &padding, config, out)?;
|
||||
|
@ -2691,10 +2707,15 @@ fn display_item_long(
|
|||
config: &Config,
|
||||
out: &mut BufWriter<Stdout>,
|
||||
dired: &mut DiredOutput,
|
||||
style_manager: &mut StyleManager,
|
||||
style_manager: &mut Option<StyleManager>,
|
||||
quoted: bool,
|
||||
) -> UResult<()> {
|
||||
let mut output_display: String = String::new();
|
||||
|
||||
// apply normal color to non filename outputs
|
||||
if let Some(style_manager) = style_manager {
|
||||
write!(output_display, "{}", style_manager.apply_normal()).unwrap();
|
||||
}
|
||||
if config.dired {
|
||||
output_display += " ";
|
||||
}
|
||||
|
@ -3146,7 +3167,7 @@ fn display_item_name(
|
|||
prefix_context: Option<usize>,
|
||||
more_info: String,
|
||||
out: &mut BufWriter<Stdout>,
|
||||
style_manager: &mut StyleManager,
|
||||
style_manager: &mut Option<StyleManager>,
|
||||
) -> String {
|
||||
// This is our return value. We start by `&path.display_name` and modify it along the way.
|
||||
let mut name = escape_name(&path.display_name, &config.quoting_style);
|
||||
|
@ -3155,8 +3176,8 @@ fn display_item_name(
|
|||
name = create_hyperlink(&name, path);
|
||||
}
|
||||
|
||||
if let Some(ls_colors) = &config.color {
|
||||
name = color_name(name, path, ls_colors, style_manager, out, None);
|
||||
if let Some(style_manager) = style_manager {
|
||||
name = color_name(&name, path, style_manager, out, None);
|
||||
}
|
||||
|
||||
if config.format != Format::Long && !more_info.is_empty() {
|
||||
|
@ -3202,7 +3223,7 @@ fn display_item_name(
|
|||
// We might as well color the symlink output after the arrow.
|
||||
// This makes extra system calls, but provides important information that
|
||||
// people run `ls -l --color` are very interested in.
|
||||
if let Some(ls_colors) = &config.color {
|
||||
if let Some(style_manager) = style_manager {
|
||||
// We get the absolute path to be able to construct PathData with valid Metadata.
|
||||
// This is because relative symlinks will fail to get_metadata.
|
||||
let mut absolute_target = target.clone();
|
||||
|
@ -3228,9 +3249,8 @@ fn display_item_name(
|
|||
name.push_str(&path.p_buf.read_link().unwrap().to_string_lossy());
|
||||
} else {
|
||||
name.push_str(&color_name(
|
||||
escape_name(target.as_os_str(), &config.quoting_style),
|
||||
&escape_name(target.as_os_str(), &config.quoting_style),
|
||||
path,
|
||||
ls_colors,
|
||||
style_manager,
|
||||
out,
|
||||
Some(&target_data),
|
||||
|
@ -3292,92 +3312,6 @@ fn create_hyperlink(name: &str, path: &PathData) -> String {
|
|||
format!("\x1b]8;;file://{hostname}{absolute_path}\x07{name}\x1b]8;;\x07")
|
||||
}
|
||||
|
||||
/// We need this struct to be able to store the previous style.
|
||||
/// This because we need to check the previous value in case we don't need
|
||||
/// the reset
|
||||
struct StyleManager {
|
||||
current_style: Option<Style>,
|
||||
}
|
||||
|
||||
impl StyleManager {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
current_style: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_style(&mut self, new_style: &Style, name: &str) -> String {
|
||||
if let Some(current) = &self.current_style {
|
||||
if *current == *new_style {
|
||||
// Current style is the same as new style, apply without reset.
|
||||
let mut style = new_style.to_nu_ansi_term_style();
|
||||
style.prefix_with_reset = false;
|
||||
return style.paint(name).to_string();
|
||||
}
|
||||
}
|
||||
|
||||
// We are getting a new style, we need to reset it
|
||||
self.current_style = Some(new_style.clone());
|
||||
new_style
|
||||
.to_nu_ansi_term_style()
|
||||
.reset_before_style()
|
||||
.paint(name)
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_style_based_on_metadata(
|
||||
path: &PathData,
|
||||
md_option: Option<&Metadata>,
|
||||
ls_colors: &LsColors,
|
||||
style_manager: &mut StyleManager,
|
||||
name: &str,
|
||||
) -> String {
|
||||
match ls_colors.style_for_path_with_metadata(&path.p_buf, md_option) {
|
||||
Some(style) => style_manager.apply_style(style, name),
|
||||
None => name.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Colors the provided name based on the style determined for the given path
|
||||
/// This function is quite long because it tries to leverage DirEntry to avoid
|
||||
/// unnecessary calls to stat()
|
||||
/// and manages the symlink errors
|
||||
fn color_name(
|
||||
name: String,
|
||||
path: &PathData,
|
||||
ls_colors: &LsColors,
|
||||
style_manager: &mut StyleManager,
|
||||
out: &mut BufWriter<Stdout>,
|
||||
target_symlink: Option<&PathData>,
|
||||
) -> String {
|
||||
if !path.must_dereference {
|
||||
// If we need to dereference (follow) a symlink, we will need to get the metadata
|
||||
if let Some(de) = &path.de {
|
||||
// There is a DirEntry, we don't need to get the metadata for the color
|
||||
return match ls_colors.style_for(de) {
|
||||
Some(style) => style_manager.apply_style(style, &name),
|
||||
None => name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(target) = target_symlink {
|
||||
// use the optional target_symlink
|
||||
// Use fn get_metadata_with_deref_opt instead of get_metadata() here because ls
|
||||
// should not exit with an err, if we are unable to obtain the target_metadata
|
||||
let md_res = get_metadata_with_deref_opt(target.p_buf.as_path(), path.must_dereference);
|
||||
let md = md_res.or(path.p_buf.symlink_metadata());
|
||||
apply_style_based_on_metadata(path, md.ok().as_ref(), ls_colors, style_manager, &name)
|
||||
} else {
|
||||
let md_option = path.get_metadata(out);
|
||||
let symlink_metadata = path.p_buf.symlink_metadata().ok();
|
||||
let md = md_option.or(symlink_metadata.as_ref());
|
||||
|
||||
apply_style_based_on_metadata(path, md, ls_colors, style_manager, &name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn display_symlink_count(_metadata: &Metadata) -> String {
|
||||
// Currently not sure of how to get this on Windows, so I'm punting.
|
||||
|
|
|
@ -4673,3 +4673,133 @@ fn test_acl_display() {
|
|||
.succeeds()
|
||||
.stdout_contains("+");
|
||||
}
|
||||
|
||||
// Make sure that "ls --color" correctly applies color "normal" to text and
|
||||
// files. Specifically, it should use the NORMAL setting to format non-file name
|
||||
// output and file names that don't have a designated color (unless the FILE
|
||||
// setting is also configured).
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_ls_color_norm() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch("exe");
|
||||
at.set_mode("exe", 0o755);
|
||||
at.touch("no_color");
|
||||
at.set_mode("no_color", 0o444);
|
||||
let colors = "no=7:ex=01;32";
|
||||
let strip = |input: &str| {
|
||||
let re = Regex::new(r"-r.*norm").unwrap();
|
||||
re.replace_all(input, "norm").to_string()
|
||||
};
|
||||
|
||||
// Uncolored file names should inherit NORMAL attributes.
|
||||
let expected = "\x1b[0m\x1b[07mnorm \x1b[0m\x1b[01;32mexe\x1b[0m\n\x1b[07mnorm no_color\x1b[0m"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", colors)
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-gGU")
|
||||
.arg("--color")
|
||||
.arg("exe")
|
||||
.arg("no_color")
|
||||
.succeeds()
|
||||
.stdout_str_apply(strip)
|
||||
.stdout_contains(expected);
|
||||
|
||||
let expected = "\x1b[0m\x1b[07m\x1b[0m\x1b[01;32mexe\x1b[0m \x1b[07mno_color\x1b[0m\n"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", colors)
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-xU")
|
||||
.arg("--color")
|
||||
.arg("exe")
|
||||
.arg("no_color")
|
||||
.succeeds()
|
||||
.stdout_contains(expected);
|
||||
|
||||
let expected =
|
||||
"\x1b[0m\x1b[07mnorm no_color\x1b[0m\n\x1b[07mnorm \x1b[0m\x1b[01;32mexe\x1b[0m\n"; // spell-checker:disable-line
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", colors)
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-gGU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_str_apply(strip)
|
||||
.stdout_contains(expected);
|
||||
|
||||
let expected = "\x1b[0m\x1b[07mno_color\x1b[0m \x1b[07m\x1b[0m\x1b[01;32mexe\x1b[0m"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", colors)
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-xU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_contains(expected);
|
||||
|
||||
// NORMAL does not override FILE
|
||||
let expected = "\x1b[0m\x1b[07mnorm \x1b[0m\x1b[01mno_color\x1b[0m\n\x1b[07mnorm \x1b[0m\x1b[01;32mexe\x1b[0m\n"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", format!("{}:fi=1", colors))
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-gGU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_str_apply(strip)
|
||||
.stdout_contains(expected);
|
||||
|
||||
// uncolored ordinary files that do _not_ inherit from NORMAL.
|
||||
let expected =
|
||||
"\x1b[0m\x1b[07mnorm \x1b[0mno_color\x1b[0m\n\x1b[07mnorm \x1b[0m\x1b[01;32mexe\x1b[0m\n"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", format!("{}:fi=", colors))
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-gGU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_str_apply(strip)
|
||||
.stdout_contains(expected);
|
||||
|
||||
let expected =
|
||||
"\x1b[0m\x1b[07mnorm \x1b[0mno_color\x1b[0m\n\x1b[07mnorm \x1b[0m\x1b[01;32mexe\x1b[0m\n"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", format!("{}:fi=0", colors))
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-gGU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_str_apply(strip)
|
||||
.stdout_contains(expected);
|
||||
|
||||
// commas (-m), indicator chars (-F) and the "total" line, do not currently
|
||||
// use NORMAL attributes
|
||||
let expected = "\x1b[0m\x1b[07mno_color\x1b[0m, \x1b[07m\x1b[0m\x1b[01;32mexe\x1b[0m\n"; // spell-checker:disable-line
|
||||
scene
|
||||
.ucmd()
|
||||
.env("LS_COLORS", colors)
|
||||
.env("TIME_STYLE", "+norm")
|
||||
.arg("-mU")
|
||||
.arg("--color")
|
||||
.arg("no_color")
|
||||
.arg("exe")
|
||||
.succeeds()
|
||||
.stdout_contains(expected);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# `build-gnu.bash` ~ builds GNU coreutils (from supplied sources)
|
||||
#
|
||||
|
||||
# spell-checker:ignore (paths) abmon deref discrim eacces getlimits getopt ginstall inacc infloop inotify reflink ; (misc) INT_OFLOW OFLOW baddecode submodules xstrtol ; (vars/env) SRCDIR vdir rcexp xpart dired OSTYPE ; (utils) gnproc greadlink gsed
|
||||
# spell-checker:ignore (paths) abmon deref discrim eacces getlimits getopt ginstall inacc infloop inotify reflink ; (misc) INT_OFLOW OFLOW baddecode submodules xstrtol ; (vars/env) SRCDIR vdir rcexp xpart dired OSTYPE ; (utils) gnproc greadlink gsed multihardlink
|
||||
|
||||
set -e
|
||||
|
||||
|
@ -343,3 +343,16 @@ test \$n_stat1 -ge \$n_stat2 \\' tests/ls/stat-free-color.sh
|
|||
|
||||
# no need to replicate this output with hashsum
|
||||
sed -i -e "s|Try 'md5sum --help' for more information.\\\n||" tests/cksum/md5sum.pl
|
||||
|
||||
# Our ls command always outputs ANSI color codes prepended with a zero. However,
|
||||
# in the case of GNU, it seems inconsistent. Nevertheless, it looks like it
|
||||
# doesn't matter whether we prepend a zero or not.
|
||||
sed -i -E 's/\^\[\[([1-9]m)/^[[0\1/g; s/\^\[\[m/^[[0m/g' tests/ls/color-norm.sh
|
||||
# It says in the test itself that having more than one reset is a bug, so we
|
||||
# don't need to replicate that behavior.
|
||||
sed -i -E 's/(\^\[\[0m)+/\^\[\[0m/g' tests/ls/color-norm.sh
|
||||
|
||||
# GNU's ls seems to output color codes in the order given in the environment
|
||||
# variable, but our ls seems to output them in a predefined order. Nevertheless,
|
||||
# the order doesn't matter, so it's okay.
|
||||
sed -i 's/44;37/37;44/' tests/ls/multihardlink.sh
|
Loading…
Reference in a new issue