summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2023-07-08 17:59:29 -0400
committerDan Davison <dandavison7@gmail.com>2023-07-09 12:33:54 -0400
commit177985e258f7d176d5642546d2386788f20f7cee (patch)
tree85898d5c20c337071c24790eab728307b3cdad53
parent5767a8a9483619843fd83e4213162d8882a43a11 (diff)
WIP: map-line-numbersline-map
-rw-r--r--src/cli.rs9
-rw-r--r--src/config.rs8
-rw-r--r--src/features/line_numbers.rs15
-rw-r--r--src/main.rs4
-rw-r--r--src/options/set.rs1
-rw-r--r--src/subcommands/map_line_numbers.rs32
-rw-r--r--src/subcommands/mod.rs1
-rw-r--r--src/wrapping.rs6
8 files changed, 73 insertions, 3 deletions
diff --git a/src/cli.rs b/src/cli.rs
index e1e47503..8743dbb8 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -697,6 +697,15 @@ pub struct Opt {
/// An example is --map-styles='bold purple => red "#eeeeee", bold cyan => syntax "#eeeeee"'
pub map_styles: Option<String>,
+ #[arg(long = "map-line-numbers")]
+ /// Output a line numbers map instead of the usual delta output.
+ ///
+ /// The output is a JSON document attempting to identify, for each file, for
+ /// each line in the old version of the file, the number of the
+ /// corresponding line in the new version of the file, if there is a
+ /// corresponding line.
+ pub map_line_numbers: bool,
+
#[arg(long = "max-line-distance", default_value = "0.6", value_name = "DIST")]
/// Maximum line pair distance parameter in within-line diff algorithm.
///
diff --git a/src/config.rs b/src/config.rs
index cab21eb7..da4ac16c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -94,6 +94,7 @@ pub struct Config {
pub line_numbers_zero_style: Style,
pub line_numbers: bool,
pub styles_map: Option<HashMap<style::AnsiTermStyleEqualityKey, Style>>,
+ pub map_line_numbers: bool,
pub max_line_distance_for_naively_paired_lines: f64,
pub max_line_distance: f64,
pub max_line_length: usize,
@@ -345,7 +346,8 @@ impl From<cli::Opt> for Config {
} else {
line_fill_method
},
- line_numbers: opt.line_numbers && !handlers::hunk::is_word_diff(),
+ line_numbers: (opt.line_numbers || opt.map_line_numbers)
+ && !handlers::hunk::is_word_diff(),
line_numbers_format: LeftRight::new(
opt.line_numbers_left_format,
opt.line_numbers_right_format,
@@ -360,6 +362,7 @@ impl From<cli::Opt> for Config {
),
line_numbers_zero_style: styles["line-numbers-zero-style"],
line_buffer_size: opt.line_buffer_size,
+ map_line_numbers: opt.map_line_numbers,
max_line_distance: opt.max_line_distance,
max_line_distance_for_naively_paired_lines,
max_line_length: if opt.side_by_side {
@@ -395,7 +398,8 @@ impl From<cli::Opt> for Config {
git_plus_style: styles["git-plus-style"],
relative_paths: opt.relative_paths,
show_themes: opt.show_themes,
- side_by_side: opt.side_by_side && !handlers::hunk::is_word_diff(),
+ side_by_side: (opt.side_by_side || opt.map_line_numbers)
+ && !handlers::hunk::is_word_diff(),
side_by_side_data,
styles_map,
syntax_dummy_theme: SyntaxTheme::default(),
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs
index 1c674b0f..f6498f96 100644
--- a/src/features/line_numbers.rs
+++ b/src/features/line_numbers.rs
@@ -120,6 +120,12 @@ pub fn format_and_paint_line_numbers<'a>(
};
if emit_left {
+ if config.map_line_numbers {
+ assert!(config.side_by_side && config.wrap_config.max_lines == 1);
+ if let Some(n) = line_numbers[Minus] {
+ print!("{},{}", line_numbers_data.plus_file, n)
+ }
+ }
formatted_numbers.extend(format_and_paint_line_number_field(
line_numbers_data,
Minus,
@@ -130,6 +136,15 @@ pub fn format_and_paint_line_numbers<'a>(
}
if emit_right {
+ if config.map_line_numbers && line_numbers[Minus].is_some() {
+ println!(
+ ",{}",
+ line_numbers[Plus]
+ .map(|n| n.to_string())
+ .as_deref()
+ .unwrap_or("null")
+ )
+ }
formatted_numbers.extend(format_and_paint_line_number_field(
line_numbers_data,
Plus,
diff --git a/src/main.rs b/src/main.rs
index caf94cac..413ded4b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -112,6 +112,7 @@ fn run_app() -> std::io::Result<i32> {
};
let _show_config = opt.show_config;
+ let _map_line_numbers = opt.map_line_numbers;
let config = config::Config::from(opt);
if _show_config {
@@ -119,6 +120,9 @@ fn run_app() -> std::io::Result<i32> {
let mut stdout = stdout.lock();
subcommands::show_config::show_config(&config, &mut stdout)?;
return Ok(0);
+ } else if _map_line_numbers {
+ subcommands::map_line_numbers::map_line_numbers(&config)?;
+ return Ok(0);
}
let mut output_type =
diff --git a/src/options/set.rs b/src/options/set.rs
index 732806a7..e0026aa8 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -170,6 +170,7 @@ pub fn set_options(
inspect_raw_lines,
keep_plus_minus_markers,
line_buffer_size,
+ map_line_numbers,
map_styles,
max_line_distance,
max_line_length,
diff --git a/src/subcommands/map_line_numbers.rs b/src/subcommands/map_line_numbers.rs
new file mode 100644
index 00000000..8b3f272e
--- /dev/null
+++ b/src/subcommands/map_line_numbers.rs
@@ -0,0 +1,32 @@
+use crate::config::Config;
+use crate::delta::delta;
+use bytelines::ByteLinesReader;
+use std::io::{self, ErrorKind, Write};
+
+#[cfg(not(tarpaulin_include))]
+pub fn map_line_numbers(config: &Config) -> std::io::Result<()> {
+ let mut writer = NullWriter {};
+ if let Err(error) = delta(io::stdin().lock().byte_lines(), &mut writer, &config) {
+ match error.kind() {
+ ErrorKind::BrokenPipe => return Ok(()),
+ _ => eprintln!("{error}"),
+ }
+ };
+ Ok(())
+}
+
+struct NullWriter {}
+
+impl Write for NullWriter {
+ fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+
+ fn write_all(&mut self, mut _buf: &[u8]) -> io::Result<()> {
+ Ok(())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
diff --git a/src/subcommands/mod.rs b/src/subcommands/mod.rs
index 26f04233..901ddb98 100644
--- a/src/subcommands/mod.rs
+++ b/src/subcommands/mod.rs
@@ -1,5 +1,6 @@
pub mod diff;
pub mod list_syntax_themes;
+pub mod map_line_numbers;
pub mod parse_ansi;
mod sample_diff;
pub mod show_colors;
diff --git a/src/wrapping.rs b/src/wrapping.rs
index 40eff4f2..c327fb00 100644
--- a/src/wrapping.rs
+++ b/src/wrapping.rs
@@ -59,7 +59,11 @@ impl WrapConfig {
fatal("Invalid value for wrap-right-percent, not between 0 and 100.")
}
},
- max_lines: adapt_wrap_max_lines_argument(opt.wrap_max_lines.clone()),
+ max_lines: adapt_wrap_max_lines_argument(if opt.map_line_numbers {
+ "0".to_string()
+ } else {
+ opt.wrap_max_lines.clone()
+ }),
inline_hint_syntect_style: SyntectStyle::from_delta_style(inline_hint_style),
}
}