diff --git a/src/app.rs b/src/app.rs index b0b573cf..e7ece7ef 100644 --- a/src/app.rs +++ b/src/app.rs @@ -77,7 +77,11 @@ pub struct Config<'a> { /// Command to start the pager pub pager: Option<&'a str>, + /// Whether or not to use ANSI italics pub use_italic_text: bool, + + /// Lines to highlight + pub highlight_lines: Vec, } fn is_truecolor_terminal() -> bool { @@ -264,6 +268,11 @@ impl App { Some("always") => true, _ => false, }, + highlight_lines: self + .matches + .values_of("highlight-line") + .and_then(|ws| ws.map(|w| w.parse().ok()).collect()) + .unwrap_or_default(), }) } diff --git a/src/clap_app.rs b/src/clap_app.rs index 1fba4b1a..abecb68a 100644 --- a/src/clap_app.rs +++ b/src/clap_app.rs @@ -175,6 +175,7 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { .arg( Arg::with_name("line-range") .long("line-range") + .short("r") .multiple(true) .takes_value(true) .number_of_values(1) @@ -188,6 +189,19 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { '--line-range 40:' prints lines 40 to the end of the file", ), ) + .arg( + Arg::with_name("highlight-line") + .long("highlight-line") + .short("H") + .takes_value(true) + .number_of_values(1) + .multiple(true) + .value_name("N") + .help("Highlight the given line.") + .long_help( + "Highlight the N-th line with a different background color", + ), + ) .arg( Arg::with_name("color") .long("color") diff --git a/src/printer.rs b/src/printer.rs index 0cf63a7c..0c549feb 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -7,6 +7,7 @@ use ansi_term::Style; use console::AnsiCodeIterator; use syntect::easy::HighlightLines; +use syntect::highlighting::Color; use syntect::highlighting::Theme; use syntect::parsing::SyntaxSet; @@ -79,6 +80,7 @@ pub struct InteractivePrinter<'a> { pub line_changes: Option, highlighter: Option>, syntax_set: &'a SyntaxSet, + background_color_highlight: Option, } impl<'a> InteractivePrinter<'a> { @@ -90,6 +92,8 @@ impl<'a> InteractivePrinter<'a> { ) -> Self { let theme = assets.get_theme(&config.theme); + let background_color_highlight = theme.settings.line_highlight; + let colors = if config.colored_output { Colors::colored(theme, config.true_color) } else { @@ -156,6 +160,7 @@ impl<'a> InteractivePrinter<'a> { line_changes, highlighter, syntax_set: &assets.syntax_set, + background_color_highlight, } } @@ -287,6 +292,17 @@ impl<'a> Printer for InteractivePrinter<'a> { let mut cursor_total: usize = 0; let mut panel_wrap: Option = None; + // Line highlighting + let highlight_this_line = self + .config + .highlight_lines + .iter() + .any(|&l| l == line_number); + + let background_color = self + .background_color_highlight + .filter(|_| highlight_this_line); + // Line decorations. if self.panel_width > 0 { let decorations = self @@ -313,9 +329,29 @@ impl<'a> Printer for InteractivePrinter<'a> { write!( handle, "{}", - as_terminal_escaped(style, text_trimmed, true_color, colored_output, italics,) + as_terminal_escaped( + style, + text_trimmed, + true_color, + colored_output, + italics, + background_color + ) )?; - write!(handle, "{}", &text[text_trimmed.len()..])?; + + if text.len() != text_trimmed.len() { + if let Some(background_color) = background_color { + let mut ansi_style = Style::default(); + ansi_style.background = Some(to_ansi_color(background_color, true_color)); + let width = if cursor_total <= cursor_max { + cursor_max - cursor_total + 1 + } else { + 0 + }; + write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?; + } + write!(handle, "{}", &text[text_trimmed.len()..])?; + } } if line.bytes().next_back() != Some(b'\n') { @@ -370,7 +406,8 @@ impl<'a> Printer for InteractivePrinter<'a> { ), self.config.true_color, self.config.colored_output, - self.config.use_italic_text + self.config.use_italic_text, + background_color ) )?; break; @@ -410,7 +447,8 @@ impl<'a> Printer for InteractivePrinter<'a> { ), self.config.true_color, self.config.colored_output, - self.config.use_italic_text + self.config.use_italic_text, + background_color ), panel_wrap.clone().unwrap() )?; @@ -423,6 +461,17 @@ impl<'a> Printer for InteractivePrinter<'a> { } } + if let Some(background_color) = background_color { + let mut ansi_style = Style::default(); + ansi_style.background = + Some(to_ansi_color(background_color, self.config.true_color)); + + write!( + handle, + "{}", + ansi_style.paint(" ".repeat(cursor_max - cursor)) + )?; + } write!(handle, "\n")?; } diff --git a/src/terminal.rs b/src/terminal.rs index eeb15cbd..f01e9d60 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -19,8 +19,9 @@ pub fn as_terminal_escaped( true_color: bool, colored: bool, italics: bool, + background_color: Option, ) -> String { - let style = if !colored { + let mut style = if !colored { Style::default() } else { let color = to_ansi_color(style.foreground, true_color); @@ -36,5 +37,6 @@ pub fn as_terminal_escaped( } }; + style.background = background_color.map(|c| to_ansi_color(c, true_color)); style.paint(text).to_string() }