Skip to content

Commit dee3bc1

Browse files
authored
Merge pull request #117 from sami-daniel/main
Create the side-by-side option (-y) feature for the diff command (Incomplete)
2 parents 5b791e8 + fce0881 commit dee3bc1

File tree

9 files changed

+1366
-8
lines changed

9 files changed

+1366
-8
lines changed

.github/workflows/fuzzing.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ jobs:
4646
- { name: fuzz_ed, should_pass: true }
4747
- { name: fuzz_normal, should_pass: true }
4848
- { name: fuzz_patch, should_pass: true }
49+
- { name: fuzz_side, should_pass: true }
4950
steps:
5051
- uses: actions/checkout@v4
5152
- uses: dtolnay/rust-toolchain@nightly

fuzz/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ path = "fuzz_targets/fuzz_ed.rs"
4747
test = false
4848
doc = false
4949

50-
50+
[[bin]]
51+
name = "fuzz_side"
52+
path = "fuzz_targets/fuzz_side.rs"
53+
test = false
54+
doc = false

fuzz/fuzz_targets/fuzz_side.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![no_main]
2+
#[macro_use]
3+
extern crate libfuzzer_sys;
4+
5+
use diffutilslib::side_diff;
6+
7+
use std::fs::File;
8+
use std::io::Write;
9+
use diffutilslib::params::Params;
10+
11+
fuzz_target!(|x: (Vec<u8>, Vec<u8>, /* usize, usize */ bool)| {
12+
let (original, new, /* width, tabsize, */ expand) = x;
13+
14+
// if width == 0 || tabsize == 0 {
15+
// return;
16+
// }
17+
18+
let params = Params {
19+
// width,
20+
// tabsize,
21+
expand_tabs: expand,
22+
..Default::default()
23+
};
24+
let mut output_buf = vec![];
25+
side_diff::diff(&original, &new, &mut output_buf, &params);
26+
File::create("target/fuzz.file.original")
27+
.unwrap()
28+
.write_all(&original)
29+
.unwrap();
30+
File::create("target/fuzz.file.new")
31+
.unwrap()
32+
.write_all(&new)
33+
.unwrap();
34+
File::create("target/fuzz.file")
35+
.unwrap()
36+
.write_all(&original)
37+
.unwrap();
38+
File::create("target/fuzz.diff")
39+
.unwrap()
40+
.write_all(&output_buf)
41+
.unwrap();
42+
});

src/diff.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
use crate::params::{parse_params, Format};
77
use crate::utils::report_failure_to_read_input_file;
8-
use crate::{context_diff, ed_diff, normal_diff, unified_diff};
8+
use crate::{context_diff, ed_diff, normal_diff, side_diff, unified_diff};
99
use std::env::ArgsOs;
1010
use std::ffi::OsString;
1111
use std::fs;
12-
use std::io::{self, Read, Write};
12+
use std::io::{self, stdout, Read, Write};
1313
use std::iter::Peekable;
1414
use std::process::{exit, ExitCode};
1515

@@ -79,6 +79,10 @@ pub fn main(opts: Peekable<ArgsOs>) -> ExitCode {
7979
eprintln!("{error}");
8080
exit(2);
8181
}),
82+
Format::SideBySide => {
83+
let mut output = stdout().lock();
84+
side_diff::diff(&from_content, &to_content, &mut output, &params)
85+
}
8286
};
8387
if params.brief && !result.is_empty() {
8488
println!(

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ pub mod ed_diff;
44
pub mod macros;
55
pub mod normal_diff;
66
pub mod params;
7+
pub mod side_diff;
78
pub mod unified_diff;
89
pub mod utils;
910

1011
// Re-export the public functions/types you need
1112
pub use context_diff::diff as context_diff;
1213
pub use ed_diff::diff as ed_diff;
1314
pub use normal_diff::diff as normal_diff;
15+
pub use side_diff::diff as side_by_side_diff;
1416
pub use unified_diff::diff as unified_diff;

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod ed_diff;
1818
mod macros;
1919
mod normal_diff;
2020
mod params;
21+
mod side_diff;
2122
mod unified_diff;
2223
mod utils;
2324

src/params.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub enum Format {
1111
Unified,
1212
Context,
1313
Ed,
14+
SideBySide,
1415
}
1516

1617
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -24,6 +25,7 @@ pub struct Params {
2425
pub brief: bool,
2526
pub expand_tabs: bool,
2627
pub tabsize: usize,
28+
pub width: usize,
2729
}
2830

2931
impl Default for Params {
@@ -38,6 +40,7 @@ impl Default for Params {
3840
brief: false,
3941
expand_tabs: false,
4042
tabsize: 8,
43+
width: 130,
4144
}
4245
}
4346
}
@@ -57,6 +60,7 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
5760
let mut format = None;
5861
let mut context = None;
5962
let tabsize_re = Regex::new(r"^--tabsize=(?<num>\d+)$").unwrap();
63+
let width_re = Regex::new(r"--width=(?P<long>\d+)$").unwrap();
6064
while let Some(param) = opts.next() {
6165
let next_param = opts.peek();
6266
if param == "--" {
@@ -101,6 +105,34 @@ pub fn parse_params<I: Iterator<Item = OsString>>(mut opts: Peekable<I>) -> Resu
101105
format = Some(Format::Ed);
102106
continue;
103107
}
108+
if param == "-y" || param == "--side-by-side" {
109+
if format.is_some() && format != Some(Format::SideBySide) {
110+
return Err("Conflicting output style option".to_string());
111+
}
112+
format = Some(Format::SideBySide);
113+
continue;
114+
}
115+
if width_re.is_match(param.to_string_lossy().as_ref()) {
116+
let param = param.into_string().unwrap();
117+
let width_str: &str = width_re
118+
.captures(param.as_str())
119+
.unwrap()
120+
.name("long")
121+
.unwrap()
122+
.as_str();
123+
124+
params.width = match width_str.parse::<usize>() {
125+
Ok(num) => {
126+
if num == 0 {
127+
return Err("invalid width «0»".to_string());
128+
}
129+
130+
num
131+
}
132+
Err(_) => return Err(format!("invalid width «{width_str}»")),
133+
};
134+
continue;
135+
}
104136
if tabsize_re.is_match(param.to_string_lossy().as_ref()) {
105137
// Because param matches the regular expression,
106138
// 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
112144
.unwrap()
113145
.as_str();
114146
params.tabsize = match tabsize_str.parse::<usize>() {
115-
Ok(num) => num,
147+
Ok(num) => {
148+
if num == 0 {
149+
return Err("invalid tabsize «0»".to_string());
150+
}
151+
152+
num
153+
}
116154
Err(_) => return Err(format!("invalid tabsize «{tabsize_str}»")),
117155
};
156+
118157
continue;
119158
}
120159
match match_context_diff_params(&param, next_param, format) {
@@ -704,11 +743,11 @@ mod tests {
704743
executable: os("diff"),
705744
from: os("foo"),
706745
to: os("bar"),
707-
tabsize: 0,
746+
tabsize: 1,
708747
..Default::default()
709748
}),
710749
parse_params(
711-
[os("diff"), os("--tabsize=0"), os("foo"), os("bar")]
750+
[os("diff"), os("--tabsize=1"), os("foo"), os("bar")]
712751
.iter()
713752
.cloned()
714753
.peekable()

0 commit comments

Comments
 (0)