Merge pull request #117 from sami-daniel/main

Create the side-by-side option (-y) feature for the diff command (Incomplete)
This commit is contained in:
Sylvestre Ledru
2025-06-03 14:01:38 +02:00
committed by GitHub
9 changed files with 1366 additions and 8 deletions
+1
View File
@@ -46,6 +46,7 @@ jobs:
- { name: fuzz_ed, should_pass: true }
- { name: fuzz_normal, should_pass: true }
- { name: fuzz_patch, should_pass: true }
- { name: fuzz_side, should_pass: true }
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
+5 -1
View File
@@ -47,4 +47,8 @@ path = "fuzz_targets/fuzz_ed.rs"
test = false
doc = false
[[bin]]
name = "fuzz_side"
path = "fuzz_targets/fuzz_side.rs"
test = false
doc = false
+42
View File
@@ -0,0 +1,42 @@
#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
use diffutilslib::side_diff;
use std::fs::File;
use std::io::Write;
use diffutilslib::params::Params;
fuzz_target!(|x: (Vec<u8>, Vec<u8>, /* usize, usize */ bool)| {
let (original, new, /* width, tabsize, */ expand) = x;
// if width == 0 || tabsize == 0 {
// return;
// }
let params = Params {
// width,
// tabsize,
expand_tabs: expand,
..Default::default()
};
let mut output_buf = vec![];
side_diff::diff(&original, &new, &mut output_buf, &params);
File::create("target/fuzz.file.original")
.unwrap()
.write_all(&original)
.unwrap();
File::create("target/fuzz.file.new")
.unwrap()
.write_all(&new)
.unwrap();
File::create("target/fuzz.file")
.unwrap()
.write_all(&original)
.unwrap();
File::create("target/fuzz.diff")
.unwrap()
.write_all(&output_buf)
.unwrap();
});
+6 -2
View File
@@ -5,11 +5,11 @@
use crate::params::{parse_params, Format};
use crate::utils::report_failure_to_read_input_file;
use crate::{context_diff, ed_diff, normal_diff, unified_diff};
use crate::{context_diff, ed_diff, normal_diff, side_diff, unified_diff};
use std::env::ArgsOs;
use std::ffi::OsString;
use std::fs;
use std::io::{self, Read, Write};
use std::io::{self, stdout, Read, Write};
use std::iter::Peekable;
use std::process::{exit, ExitCode};
@@ -79,6 +79,10 @@ pub fn main(opts: Peekable<ArgsOs>) -> ExitCode {
eprintln!("{error}");
exit(2);
}),
Format::SideBySide => {
let mut output = stdout().lock();
side_diff::diff(&from_content, &to_content, &mut output, &params)
}
};
if params.brief && !result.is_empty() {
println!(
+2
View File
@@ -4,6 +4,7 @@ pub mod ed_diff;
pub mod macros;
pub mod normal_diff;
pub mod params;
pub mod side_diff;
pub mod unified_diff;
pub mod utils;
@@ -11,4 +12,5 @@ pub mod utils;
pub use context_diff::diff as context_diff;
pub use ed_diff::diff as ed_diff;
pub use normal_diff::diff as normal_diff;
pub use side_diff::diff as side_by_side_diff;
pub use unified_diff::diff as unified_diff;
+1
View File
@@ -18,6 +18,7 @@ mod ed_diff;
mod macros;
mod normal_diff;
mod params;
mod side_diff;
mod unified_diff;
mod utils;
+42 -3
View File
@@ -11,6 +11,7 @@ pub enum Format {
Unified,
Context,
Ed,
SideBySide,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -24,6 +25,7 @@ pub struct Params {
pub brief: bool,
pub expand_tabs: bool,
pub tabsize: usize,
pub width: usize,
}
impl Default for Params {
@@ -38,6 +40,7 @@ impl Default for Params {
brief: false,
expand_tabs: false,
tabsize: 8,
width: 130,
}
}
}
@@ -57,6 +60,7 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
let mut format = None;
let mut context = None;
let tabsize_re = Regex::new(r"^--tabsize=(?<num>\d+)$").unwrap();
let width_re = Regex::new(r"--width=(?P<long>\d+)$").unwrap();
while let Some(param) = opts.next() {
let next_param = opts.peek();
if param == "--" {
@@ -101,6 +105,34 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
format = Some(Format::Ed);
continue;
}
if param == "-y" || param == "--side-by-side" {
if format.is_some() && format != Some(Format::SideBySide) {
return Err("Conflicting output style option".to_string());
}
format = Some(Format::SideBySide);
continue;
}
if width_re.is_match(param.to_string_lossy().as_ref()) {
let param = param.into_string().unwrap();
let width_str: &str = width_re
.captures(param.as_str())
.unwrap()
.name("long")
.unwrap()
.as_str();
params.width = match width_str.parse::<usize>() {
Ok(num) => {
if num == 0 {
return Err("invalid width «0»".to_string());
}
num
}
Err(_) => return Err(format!("invalid width «{width_str}»")),
};
continue;
}
if tabsize_re.is_match(param.to_string_lossy().as_ref()) {
// Because param matches the regular expression,
// it is safe to assume it is valid UTF-8.
@@ -112,9 +144,16 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
.unwrap()
.as_str();
params.tabsize = match tabsize_str.parse::<usize>() {
Ok(num) => num,
Ok(num) => {
if num == 0 {
return Err("invalid tabsize «0»".to_string());
}
num
}
Err(_) => return Err(format!("invalid tabsize «{tabsize_str}»")),
};
continue;
}
match match_context_diff_params(&param, next_param, format) {
@@ -704,11 +743,11 @@ mod tests {
executable: os("diff"),
from: os("foo"),
to: os("bar"),
tabsize: 0,
tabsize: 1,
..Default::default()
}),
parse_params(
[os("diff"), os("--tabsize=0"), os("foo"), os("bar")]
[os("diff"), os("--tabsize=1"), os("foo"), os("bar")]
.iter()
.cloned()
.peekable()
+1266
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -3,9 +3,8 @@
// For the full copyright and license information, please view the LICENSE-*
// files that was distributed with this source code.
use std::{ffi::OsString, io::Write};
use regex::Regex;
use std::{ffi::OsString, io::Write};
use unicode_width::UnicodeWidthStr;
/// Replace tabs by spaces in the input line.