Skip to content

Commit

Permalink
Add side-by-side diff view
Browse files Browse the repository at this point in the history
Closes #86
  • Loading branch information
dandavison committed Jul 10, 2020
1 parent ca44215 commit c10ae85
Show file tree
Hide file tree
Showing 10 changed files with 652 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ homepage = "https://github.com/dandavison/delta"
license = "MIT"
readme = "README.md"
repository = "https://github.com/dandavison/delta"
version = "0.2.1"
version = "0.3.0"

[[bin]]
name = "delta"
Expand Down
5 changes: 5 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ pub struct Opt {
#[structopt(short = "n", long = "line-numbers")]
pub line_numbers: bool,

/// Display a side-by-side diff view instead of the traditional view.
#[structopt(long = "side-by-side")]
pub side_by_side: bool,

#[structopt(long = "diff-highlight")]
/// Emulate diff-highlight (https://github.com/git/git/tree/master/contrib/diff-highlight)
pub diff_highlight: bool,
Expand Down Expand Up @@ -516,6 +520,7 @@ pub struct ComputedValues {
pub syntax_theme: Option<SyntaxTheme>,
pub syntax_dummy_theme: SyntaxTheme,
pub true_color: bool,
pub available_terminal_width: usize,
pub decorations_width: Width,
pub background_color_extends_to_terminal_width: bool,
pub paging_mode: PagingMode,
Expand Down
14 changes: 14 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ use crate::cli;
use crate::color;
use crate::delta::State;
use crate::env;
use crate::features::side_by_side;
use crate::style::Style;

pub struct Config {
pub available_terminal_width: usize,
pub background_color_extends_to_terminal_width: bool,
pub commit_style: Style,
pub decorations_width: cli::Width,
Expand Down Expand Up @@ -50,11 +52,14 @@ pub struct Config {
pub plus_non_emph_style: Style,
pub plus_style: Style,
pub line_numbers: bool,
pub side_by_side: bool,
pub side_by_side_data: side_by_side::SideBySideData,
pub syntax_dummy_theme: SyntaxTheme,
pub syntax_set: SyntaxSet,
pub syntax_theme: Option<SyntaxTheme>,
pub tab_width: usize,
pub true_color: bool,
pub truncation_symbol: String,
pub tokenization_regex: Regex,
pub whitespace_error_style: Style,
pub zero_style: Style,
Expand Down Expand Up @@ -112,7 +117,13 @@ impl From<cli::Opt> for Config {
process::exit(1);
});

let side_by_side_data = side_by_side::SideBySideData::new(
&opt.computed.decorations_width,
&opt.computed.available_terminal_width,
);

Self {
available_terminal_width: opt.computed.available_terminal_width,
background_color_extends_to_terminal_width: opt
.computed
.background_color_extends_to_terminal_width,
Expand Down Expand Up @@ -150,12 +161,15 @@ impl From<cli::Opt> for Config {
plus_non_emph_style,
plus_style,
line_numbers: opt.line_numbers,
side_by_side: opt.side_by_side,
side_by_side_data,
syntax_dummy_theme: SyntaxTheme::default(),
syntax_set: opt.computed.syntax_set,
syntax_theme: opt.computed.syntax_theme,
tab_width: opt.tab_width,
tokenization_regex,
true_color: opt.computed.true_color,
truncation_symbol: "→".to_string(),
whitespace_error_style,
zero_style,
}
Expand Down
23 changes: 16 additions & 7 deletions src/edits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::align;
/// Infer the edit operations responsible for the differences between a collection of old and new
/// lines. A "line" is a string. An annotated line is a Vec of (op, &str) pairs, where the &str
/// slices are slices of the line, and their concatenation equals the line. Return the input minus
/// and plus lines, in annotated form.
/// and plus lines, in annotated form. Also return a specification of the inferred alignment of
/// minus and plus lines.
pub fn infer_edits<'a, EditOperation>(
minus_lines: &'a [String],
plus_lines: &'a [String],
Expand All @@ -20,19 +21,21 @@ pub fn infer_edits<'a, EditOperation>(
max_line_distance: f64,
max_line_distance_for_naively_paired_lines: f64,
) -> (
Vec<Vec<(EditOperation, &'a str)>>, // annotated minus lines
Vec<Vec<(EditOperation, &'a str)>>, // annotated plus lines
Vec<Vec<(EditOperation, &'a str)>>, // annotated minus lines
Vec<Vec<(EditOperation, &'a str)>>, // annotated plus lines
Vec<(Option<usize>, Option<usize>)>, // line alignment
)
where
EditOperation: Copy,
EditOperation: PartialEq,
{
let mut annotated_minus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
let mut annotated_plus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
let mut line_alignment = Vec::<(Option<usize>, Option<usize>)>::new();

let mut plus_index = 0; // plus lines emitted so far

'minus_lines_loop: for minus_line in minus_lines {
'minus_lines_loop: for (minus_index, minus_line) in minus_lines.iter().enumerate() {
let mut considered = 0; // plus lines considered so far as match for minus_line
for plus_line in &plus_lines[plus_index..] {
let alignment = align::Alignment::new(
Expand All @@ -57,10 +60,12 @@ where
// Emit as unpaired the plus lines already considered and rejected
for plus_line in &plus_lines[plus_index..(plus_index + considered)] {
annotated_plus_lines.push(vec![(noop_insertion, plus_line)]);
line_alignment.push((None, Some(plus_index)));
plus_index += 1;
}
plus_index += considered;
annotated_minus_lines.push(annotated_minus_line);
annotated_plus_lines.push(annotated_plus_line);
line_alignment.push((Some(minus_index), Some(plus_index)));
plus_index += 1;

// Greedy: move on to the next minus line.
Expand All @@ -71,13 +76,16 @@ where
}
// No homolog was found for minus i; emit as unpaired.
annotated_minus_lines.push(vec![(noop_deletion, minus_line)]);
line_alignment.push((Some(minus_index), None));
}
// Emit any remaining plus lines
for plus_line in &plus_lines[plus_index..] {
annotated_plus_lines.push(vec![(noop_insertion, plus_line)]);
line_alignment.push((None, Some(plus_index)));
plus_index += 1;
}

(annotated_minus_lines, annotated_plus_lines)
(annotated_minus_lines, annotated_plus_lines, line_alignment)
}

/// Split line into tokens for alignment. The alignment algorithm aligns sequences of substrings;
Expand Down Expand Up @@ -736,7 +744,8 @@ mod tests {
0.0,
);
// compare_annotated_lines(actual_edits, expected_edits);
assert_eq!(actual_edits, expected_edits);
// TODO: test line alignment
assert_eq!((actual_edits.0, actual_edits.1), expected_edits);
}

// Assert that no edits are inferred for the supplied minus and plus lines.
Expand Down
55 changes: 34 additions & 21 deletions src/features/line_numbers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use regex::Regex;

use crate::config;
use crate::delta::State;
use crate::features::side_by_side;
use crate::features::OptionValueFunction;
use crate::style::Style;

Expand Down Expand Up @@ -63,6 +64,7 @@ pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
pub fn format_and_paint_line_numbers<'a>(
line_numbers_data: &'a mut LineNumbersData,
state: &State,
side_by_side_panel: Option<side_by_side::PanelSide>,
config: &'a config::Config,
) -> Vec<ansi_term::ANSIGenericString<'a, str>> {
let m_ref = &mut line_numbers_data.hunk_minus_line_number;
Expand Down Expand Up @@ -94,25 +96,36 @@ pub fn format_and_paint_line_numbers<'a>(

let mut formatted_numbers = Vec::new();

formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.left_format_data,
&config.line_numbers_left_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
));
formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.right_format_data,
&config.line_numbers_right_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
));
let (emit_left, emit_right) = match (config.side_by_side, side_by_side_panel) {
(false, _) => (true, true),
(true, Some(side_by_side::PanelSide::Left)) => (true, false),
(true, Some(side_by_side::PanelSide::Right)) => (false, true),
(true, None) => unreachable!(),
};

if emit_left {
formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.left_format_data,
&config.line_numbers_left_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
));
}

if emit_right {
formatted_numbers.extend(format_and_paint_line_number_field(
&line_numbers_data.right_format_data,
&config.line_numbers_right_style,
minus_number,
plus_number,
line_numbers_data.hunk_max_line_number_width,
&minus_style,
&plus_style,
));
}
formatted_numbers
}

Expand Down Expand Up @@ -506,7 +519,7 @@ pub mod tests {
assert_eq!(lines.next().unwrap(), " ⋮10000│bb = 2");
}

const TWO_MINUS_LINES_DIFF: &str = "\
pub const TWO_MINUS_LINES_DIFF: &str = "\
diff --git i/a.py w/a.py
index 223ca50..e69de29 100644
--- i/a.py
Expand All @@ -516,7 +529,7 @@ index 223ca50..e69de29 100644
-b = 2
";

const TWO_PLUS_LINES_DIFF: &str = "\
pub const TWO_PLUS_LINES_DIFF: &str = "\
diff --git c/a.py i/a.py
new file mode 100644
index 0000000..223ca50
Expand All @@ -527,7 +540,7 @@ index 0000000..223ca50
+b = 2
";

const ONE_MINUS_ONE_PLUS_LINE_DIFF: &str = "\
pub const ONE_MINUS_ONE_PLUS_LINE_DIFF: &str = "\
diff --git i/a.py w/a.py
index 223ca50..367a6f6 100644
--- i/a.py
Expand Down
5 changes: 5 additions & 0 deletions src/features/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ pub fn make_builtin_features() -> HashMap<String, BuiltinFeature> {
navigate::make_feature().into_iter().collect(),
),
("raw".to_string(), raw::make_feature().into_iter().collect()),
(
"side-by-side".to_string(),
side_by_side::make_feature().into_iter().collect(),
),
]
.into_iter()
.collect()
Expand Down Expand Up @@ -80,6 +84,7 @@ pub mod diff_so_fancy;
pub mod line_numbers;
pub mod navigate;
pub mod raw;
pub mod side_by_side;

#[cfg(test)]
pub mod tests {
Expand Down
Loading

0 comments on commit c10ae85

Please sign in to comment.