From 6c7e2627fea95759458ee411112a00d00ab0179f Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 18 Dec 2023 18:28:12 +0100 Subject: [PATCH] gnu_legacy: with GNU, write fg first, else bg first. (#54) Fixes: https://github.com/sharkdp/lscolors/issues/77 --- src/ansi.rs | 106 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 28 deletions(-) diff --git a/src/ansi.rs b/src/ansi.rs index c153da8..6f46dee 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -64,21 +64,42 @@ impl Style { // The foreground and background colors, if specified, need to be // handled specially because the number codes are more complicated. // (see `write_background_code` and `write_foreground_code`) - if let Some(bg) = self.background { - if written_anything { - write!(f, ";")?; + + #[cfg(feature = "gnu_legacy")] + // with GNU, write foreground first, else background first. + { + if let Some(fg) = self.foreground { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + fg.write_foreground_code(f)?; } - written_anything = true; - bg.write_background_code(f)?; - } - if let Some(fg) = self.foreground { - if written_anything { - write!(f, ";")?; + if let Some(bg) = self.background { + if written_anything { + write!(f, ";")?; + } + bg.write_background_code(f)?; } - fg.write_foreground_code(f)?; } + #[cfg(not(feature = "gnu_legacy"))] + { + if let Some(bg) = self.background { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + bg.write_background_code(f)?; + } + if let Some(fg) = self.foreground { + if written_anything { + write!(f, ";")?; + } + fg.write_foreground_code(f)?; + } + } // All the codes end with an `m`, because reasons. write!(f, "m")?; @@ -397,6 +418,8 @@ macro_rules! test { mod test { use crate::style::Color::*; use crate::style::Style; + use crate::Color; + use std::default::Default; test!(plain: Style::default(); "text/plain" => "text/plain"); test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); @@ -452,6 +475,19 @@ mod test { assert_eq!(White.normal().infix(Blue.normal()).to_string(), "\x1B[34m"); assert_eq!(Blue.bold().infix(Blue.bold()).to_string(), ""); } + + #[test] + fn test_write_prefix_no_gnu_compat_order() { + let style = Style { + foreground: Some(Color::Red), + background: Some(Color::Blue), + ..Default::default() + }; + assert_eq!( + style.paint("file").to_string(), + "\u{1b}[44;31mfile\u{1b}[0m".to_string() + ); + } } #[cfg(test)] @@ -459,6 +495,8 @@ mod test { mod gnu_legacy_test { use crate::style::Color::*; use crate::style::Style; + use crate::Color; + use std::default::Default; test!(plain: Style::default(); "text/plain" => "text/plain"); test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); @@ -468,25 +506,24 @@ mod gnu_legacy_test { test!(blue_underline: Blue.underline(); "hi" => "\x1B[04;34mhi\x1B[0m"); test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[01;04;32mhi\x1B[0m"); test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[01;04;32mhi\x1B[0m"); - test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); - test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); - test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); - test!(yellow_on_blue_reset: Cyan.on(Blue).reset_before_style().fg(Yellow); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); - test!(yellow_on_blue_reset_2: Cyan.on(Blue).fg(Yellow).reset_before_style(); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); - test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); - test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); - test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); - test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[01;47;36mhi\x1B[0m"); - test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[04;47;36mhi\x1B[0m"); - test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[01;04;47;36mhi\x1B[0m"); - test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[01;04;47;36mhi\x1B[0m"); + test!(purple_on_white: Purple.on(White); "hi" => "\x1B[35;47mhi\x1B[0m"); + test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[35;47mhi\x1B[0m"); + test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[33;44mhi\x1B[0m"); + test!(yellow_on_blue_reset_2: Cyan.on(Blue).fg(Yellow).reset_before_style(); "hi" => "\x1B[0m\x1B[33;44mhi\x1B[0m"); + test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[35;47mhi\x1B[0m"); + test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[35;47mhi\x1B[0m"); + test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[33;44mhi\x1B[0m"); + test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[01;36;47mhi\x1B[0m"); + test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[04;36;47mhi\x1B[0m"); + test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[01;04;36;47mhi\x1B[0m"); + test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[01;04;36;47mhi\x1B[0m"); test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m"); - test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m"); - test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m"); + test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[38;5;100;45mhi\x1B[0m"); + test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[38;5;100;48;5;200mhi\x1B[0m"); test!(rgb: Rgb(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m"); - test!(rgb_on_blue: Rgb(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m"); - test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); - test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); + test!(rgb_on_blue: Rgb(70,130,180).on(Blue); "hi" => "\x1B[38;2;70;130;180;44mhi\x1B[0m"); + test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[34;48;2;70;130;180mhi\x1B[0m"); + test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[38;2;70;130;180;48;2;5;10;15mhi\x1B[0m"); test!(bold: Style::new().bold(); "hi" => "\x1B[01mhi\x1B[0m"); test!(bold_with_reset: Style::new().reset_before_style().bold(); "hi" => "\x1B[0m\x1B[01mhi\x1B[0m"); test!(bold_with_reset_2: Style::new().bold().reset_before_style(); "hi" => "\x1B[0m\x1B[01mhi\x1B[0m"); @@ -498,5 +535,18 @@ mod gnu_legacy_test { test!(reverse: Style::new().reverse(); "hi" => "\x1B[07mhi\x1B[0m"); test!(hidden: Style::new().hidden(); "hi" => "\x1B[08mhi\x1B[0m"); test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[09mhi\x1B[0m"); - test!(lr_on_lr: LightRed.on(LightRed); "hi" => "\x1B[101;91mhi\x1B[0m"); + test!(lr_on_lr: LightRed.on(LightRed); "hi" => "\x1B[91;101mhi\x1B[0m"); + + #[test] + fn test_write_prefix_gnu_compat_order() { + let style = Style { + foreground: Some(Color::Red), + background: Some(Color::Blue), + ..Default::default() + }; + assert_eq!( + style.paint("file").to_string(), + "\u{1b}[31;44mfile\u{1b}[0m".to_string() + ); + } }