Skip to content

Commit

Permalink
Add line-numbers option
Browse files Browse the repository at this point in the history
  • Loading branch information
Catherine Noll committed May 14, 2020
1 parent 796307d commit 92fe139
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ FLAGS:
The default behavior is to output a space character in place of these markers.
--light Use default colors appropriate for a light terminal background. For more control,
see the other color options.
--line-numbers Show line numbers for each line of the diff hunk.
--list-languages List supported languages and associated file extensions.
--list-theme-names List available syntax-highlighting color themes.
--list-themes List available syntax highlighting themes, each with an example of highlighted diff
Expand Down
7 changes: 7 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ pub struct Opt {
/// or PAGER (BAT_PAGER has priority).
#[structopt(long = "paging", default_value = "auto")]
pub paging_mode: String,

/// Show line numbers for the input and output diffs. The first column shows the line number
/// for the original file, and the second column shows line number for the output file.
/// A blank cell indicates that the line does not exist in one of the files (was removed
/// or added, respectively).
#[structopt(long = "line-numbers")]
pub show_line_numbers: bool,
}

#[derive(Clone, Copy, Debug, PartialEq)]
Expand Down
2 changes: 2 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct Config<'a> {
pub no_style: Style,
pub max_buffered_lines: usize,
pub paging_mode: PagingMode,
pub show_line_numbers: bool,
}

pub fn get_config<'a>(
Expand Down Expand Up @@ -162,6 +163,7 @@ pub fn get_config<'a>(
no_style: style::get_no_style(),
max_buffered_lines: 32,
paging_mode,
show_line_numbers: opt.show_line_numbers,
}
}

Expand Down
50 changes: 44 additions & 6 deletions src/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,10 @@ fn handle_hunk_meta_line(
cli::SectionStyle::Plain => panic!(),
cli::SectionStyle::Omit => return Ok(()),
};
let (raw_code_fragment, line_number) = parse::parse_hunk_metadata(&line);
let (raw_code_fragment, line_number_in, line_number_out) = parse::parse_hunk_metadata(&line);
painter.line_number_in = line_number_in.parse::<usize>().unwrap_or(0);
painter.line_number_out = line_number_out.parse::<usize>().unwrap_or(0);

let code_fragment = prepare(raw_code_fragment, false, config);
if !code_fragment.is_empty() {
let syntax_style_sections = Painter::get_line_syntax_style_sections(
Expand All @@ -261,6 +264,7 @@ fn handle_hunk_meta_line(
style::NO_BACKGROUND_COLOR_STYLE_MODIFIER,
&code_fragment,
)]],
vec![prepare_line_numbers(None, None, config)],
&mut painter.output_buffer,
config,
"",
Expand All @@ -278,11 +282,19 @@ fn handle_hunk_meta_line(
)?;
painter.output_buffer.clear();
}
writeln!(
painter.writer,
"\n{}",
paint::paint_text_foreground(line_number, config.hunk_color, config.true_color)
)?;
if config.show_line_numbers {
writeln!(
painter.writer,
"",
)?;
}
else {
writeln!(
painter.writer,
"\n{}",
paint::paint_text_foreground(line_number_out, config.hunk_color, config.true_color)
)?;
}
Ok(())
}

Expand All @@ -307,22 +319,28 @@ fn handle_hunk_line(
{
painter.paint_buffered_lines();
}
let mut line_numbers = Vec::new();
match line.chars().next() {
Some('-') => {
if state == State::HunkPlus {
painter.paint_buffered_lines();
}
painter.minus_lines.push(prepare(&line, true, config));
line_numbers.push(prepare_line_numbers(Some(painter.line_number_in), None, config));
State::HunkMinus
}
Some('+') => {
painter.plus_lines.push(prepare(&line, true, config));
line_numbers.push(prepare_line_numbers(None, Some(painter.line_number_out), config));
State::HunkPlus
}
Some(' ') => {
let prefix = if line.is_empty() { "" } else { &line[..1] };
painter.paint_buffered_lines();
let line = prepare(&line, true, config);
line_numbers.push(prepare_line_numbers(Some(painter.line_number_in), Some(painter.line_number_out), config));
painter.line_number_in += 1;
painter.line_number_out += 1;
let syntax_style_sections = Painter::get_line_syntax_style_sections(
&line,
&mut painter.highlighter,
Expand All @@ -332,6 +350,7 @@ fn handle_hunk_line(
Painter::paint_lines(
vec![syntax_style_sections],
vec![vec![(style::NO_BACKGROUND_COLOR_STYLE_MODIFIER, &line)]],
line_numbers,
&mut painter.output_buffer,
config,
prefix,
Expand Down Expand Up @@ -375,6 +394,24 @@ fn prepare(line: &str, append_newline: bool, config: &Config) -> String {
}
}

fn _line_number_style(line_number: Option<usize>) -> String {
match line_number {
Some(x) => format!("{:^4}", x),
None => format!(" "),
}
}

pub fn prepare_line_numbers(line_number_in: Option<usize>, line_number_out: Option<usize>, config: &Config) -> String {
let formatted = format!(
"{}⋮{}",
_line_number_style(line_number_in),
_line_number_style(line_number_out),
);
let numbers = paint::paint_text_foreground(&formatted, config.hunk_color, config.true_color);
let divider = paint::paint_text_foreground("│", config.hunk_color, config.true_color);
format!("{}{}", numbers, divider)
}

/// Expand tabs as spaces.
/// tab_width = 0 is documented to mean do not replace tabs.
fn expand_tabs<'a, I>(line: I, tab_width: usize) -> String
Expand Down Expand Up @@ -662,6 +699,7 @@ mod tests {
list_theme_names: false,
list_themes: false,
max_line_distance: 0.3,
show_line_numbers: false,
}
}

Expand Down
30 changes: 28 additions & 2 deletions src/paint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use syntect::parsing::{SyntaxReference, SyntaxSet};
use crate::bat::assets::HighlightingAssets;
use crate::bat::terminal::to_ansi_color;
use crate::config;
use crate::delta::prepare_line_numbers;
use crate::edits;
use crate::paint::superimpose_style_sections::superimpose_style_sections;
use crate::style;
Expand All @@ -24,6 +25,8 @@ pub struct Painter<'a> {
pub highlighter: HighlightLines<'a>,
pub config: &'a config::Config<'a>,
pub output_buffer: String,
pub line_number_in: usize,
pub line_number_out: usize,
}

impl<'a> Painter<'a> {
Expand All @@ -43,6 +46,8 @@ impl<'a> Painter<'a> {
highlighter: dummy_highlighter,
writer,
config,
line_number_in: 0,
line_number_out: 0,
}
}

Expand Down Expand Up @@ -72,11 +77,23 @@ impl<'a> Painter<'a> {
);
let (minus_line_diff_style_sections, plus_line_diff_style_sections) =
Self::get_diff_style_sections(&self.minus_lines, &self.plus_lines, self.config);

let mut minus_line_numbers = Vec::new();
let mut plus_line_numbers = Vec::new();
for _line in &self.minus_lines {
minus_line_numbers.push(prepare_line_numbers(Some(self.line_number_in), None, self.config));
self.line_number_in += 1;
}
for _line in &self.plus_lines {
plus_line_numbers.push(prepare_line_numbers(None, Some(self.line_number_out), self.config));
self.line_number_out += 1;
}
// TODO: lines and style sections contain identical line text
if !self.minus_lines.is_empty() {
Painter::paint_lines(
minus_line_syntax_style_sections,
minus_line_diff_style_sections,
minus_line_numbers,
&mut self.output_buffer,
self.config,
self.config.minus_line_marker,
Expand All @@ -88,6 +105,7 @@ impl<'a> Painter<'a> {
Painter::paint_lines(
plus_line_syntax_style_sections,
plus_line_diff_style_sections,
plus_line_numbers,
&mut self.output_buffer,
self.config,
self.config.plus_line_marker,
Expand All @@ -104,6 +122,7 @@ impl<'a> Painter<'a> {
pub fn paint_lines(
syntax_style_sections: Vec<Vec<(Style, &str)>>,
diff_style_sections: Vec<Vec<(StyleModifier, &str)>>,
line_number_sections: Vec<String>,
output_buffer: &mut String,
config: &config::Config,
prefix: &str,
Expand All @@ -112,8 +131,11 @@ impl<'a> Painter<'a> {
) {
let background_style = config.no_style.apply(background_style_modifier);
let background_ansi_style = to_ansi_style(background_style, config.true_color);
for (syntax_sections, diff_sections) in
syntax_style_sections.iter().zip(diff_style_sections.iter())

for ((syntax_sections, diff_sections), line_numbers) in
syntax_style_sections.iter()
.zip(diff_style_sections.iter())
.zip(line_number_sections.iter())
{
let mut ansi_strings = Vec::new();
if prefix != "" {
Expand Down Expand Up @@ -144,6 +166,10 @@ impl<'a> Painter<'a> {
{
line.truncate(line.len() - ANSI_SGR_RESET.len());
}

if config.show_line_numbers {
output_buffer.push_str(&line_numbers);
}
output_buffer.push_str(&line);
output_buffer.push_str(ANSI_CSI_ERASE_IN_LINE);
output_buffer.push_str(ANSI_SGR_RESET);
Expand Down
13 changes: 8 additions & 5 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,17 @@ pub fn get_file_change_description_from_file_paths(
/// Given input like
/// "@@ -74,15 +74,14 @@ pub fn delta("
/// Return " pub fn delta("
pub fn parse_hunk_metadata(line: &str) -> (&str, &str) {
pub fn parse_hunk_metadata(line: &str) -> (&str, &str, &str) {
let mut iter = line.split("@@").skip(1);
let line_number = iter
.next()
let line_number_iter = iter.next();
let line_number_in = line_number_iter
.and_then(|s| s.split('-').nth(1).and_then(|s| s.split(',').next()))
.unwrap_or("");
let line_number_out = line_number_iter
.and_then(|s| s.split('+').nth(1).and_then(|s| s.split(',').next()))
.unwrap_or("");
let code_fragment = iter.next().unwrap_or("");
(code_fragment, line_number)
(code_fragment, line_number_in, line_number_out)
}

/// Given input like "diff --git a/src/main.rs b/src/main.rs"
Expand Down Expand Up @@ -216,7 +219,7 @@ mod tests {
fn test_parse_hunk_metadata() {
assert_eq!(
parse_hunk_metadata("@@ -74,15 +75,14 @@ pub fn delta(\n"),
(" pub fn delta(\n", "75")
(" pub fn delta(\n", "74", "75")
);
}
}

0 comments on commit 92fe139

Please # to comment.