Skip to content

Commit a3c6ac0

Browse files
committed
Expose ModifiedLines and implement parsing data from the string output
This moves `Modified{Chunks,Lines}` from `src/formatting.rs` to `src/rustfmt_diff.rs` and reexports it in `src/lib.rs`. With this, a conversion from `Vec<Mismatch>` to `ModifiedLines` was implemented and now this implements complementary `Display` and `FromStr`, which simplified the previously used `output_modified` function and which allows to parse the raw data emitted with `EmitMode::ModifiedLines`.
1 parent 5794d43 commit a3c6ac0

File tree

5 files changed

+150
-63
lines changed

5 files changed

+150
-63
lines changed

src/formatting.rs

-19
Original file line numberDiff line numberDiff line change
@@ -338,25 +338,6 @@ impl ReportedErrors {
338338
}
339339
}
340340

341-
/// A single span of changed lines, with 0 or more removed lines
342-
/// and a vector of 0 or more inserted lines.
343-
#[derive(Debug, PartialEq, Eq)]
344-
pub(crate) struct ModifiedChunk {
345-
/// The first to be removed from the original text
346-
pub line_number_orig: u32,
347-
/// The number of lines which have been replaced
348-
pub lines_removed: u32,
349-
/// The new lines
350-
pub lines: Vec<String>,
351-
}
352-
353-
/// Set of changed sections of a file.
354-
#[derive(Debug, PartialEq, Eq)]
355-
pub(crate) struct ModifiedLines {
356-
/// The set of changed chunks.
357-
pub chunks: Vec<ModifiedChunk>,
358-
}
359-
360341
#[derive(Clone, Copy, Debug)]
361342
enum Timer {
362343
Disabled,

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub use crate::config::{
3333
Range, Verbosity,
3434
};
3535

36-
pub use crate::rustfmt_diff::make_diff;
36+
pub use crate::rustfmt_diff::{ModifiedChunk, ModifiedLines};
3737

3838
#[macro_use]
3939
mod utils;

src/rustfmt_diff.rs

+145-39
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::VecDeque;
2+
use std::fmt;
23
use std::io;
34
use std::io::Write;
45

@@ -33,6 +34,118 @@ impl Mismatch {
3334
}
3435
}
3536

37+
/// A single span of changed lines, with 0 or more removed lines
38+
/// and a vector of 0 or more inserted lines.
39+
#[derive(Debug, PartialEq, Eq)]
40+
pub struct ModifiedChunk {
41+
/// The first to be removed from the original text
42+
pub line_number_orig: u32,
43+
/// The number of lines which have been replaced
44+
pub lines_removed: u32,
45+
/// The new lines
46+
pub lines: Vec<String>,
47+
}
48+
49+
/// Set of changed sections of a file.
50+
#[derive(Debug, PartialEq, Eq)]
51+
pub struct ModifiedLines {
52+
/// The set of changed chunks.
53+
pub chunks: Vec<ModifiedChunk>,
54+
}
55+
56+
impl From<Vec<Mismatch>> for ModifiedLines {
57+
fn from(mismatches: Vec<Mismatch>) -> ModifiedLines {
58+
let chunks = mismatches.into_iter().map(|mismatch| {
59+
let lines = || mismatch.lines.iter();
60+
let num_removed = lines()
61+
.filter(|line| match line {
62+
DiffLine::Resulting(_) => true,
63+
_ => false,
64+
})
65+
.count();
66+
67+
let new_lines = mismatch.lines.into_iter().filter_map(|line| match line {
68+
DiffLine::Context(_) | DiffLine::Resulting(_) => None,
69+
DiffLine::Expected(str) => Some(str),
70+
});
71+
72+
ModifiedChunk {
73+
line_number_orig: mismatch.line_number_orig,
74+
lines_removed: num_removed as u32,
75+
lines: new_lines.collect(),
76+
}
77+
});
78+
79+
ModifiedLines {
80+
chunks: chunks.collect(),
81+
}
82+
}
83+
}
84+
85+
// Converts a `Mismatch` into a serialized form, which just includes
86+
// enough information to modify the original file.
87+
// Each section starts with a line with three integers, space separated:
88+
// lineno num_removed num_added
89+
// followed by (`num_added`) lines of added text. The line numbers are
90+
// relative to the original file.
91+
impl fmt::Display for ModifiedLines {
92+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93+
for chunk in &self.chunks {
94+
writeln!(
95+
f,
96+
"{} {} {}",
97+
chunk.line_number_orig,
98+
chunk.lines_removed,
99+
chunk.lines.iter().count()
100+
)?;
101+
102+
for line in &chunk.lines {
103+
writeln!(f, "{}", line)?;
104+
}
105+
}
106+
107+
Ok(())
108+
}
109+
}
110+
111+
// Allows to convert `Display`ed `ModifiedLines` back to the structural data.
112+
impl std::str::FromStr for ModifiedLines {
113+
type Err = ();
114+
115+
fn from_str(s: &str) -> Result<ModifiedLines, ()> {
116+
let mut chunks = vec![];
117+
118+
let mut lines = s.lines();
119+
while let Some(header) = lines.next() {
120+
let mut header = header.split_whitespace();
121+
let (orig, rem, new_lines) = match (header.next(), header.next(), header.next()) {
122+
(Some(orig), Some(removed), Some(added)) => (orig, removed, added),
123+
_ => return Err(()),
124+
};
125+
eprintln!("{} {} {}", orig, rem, new_lines);
126+
let (orig, rem, new_lines): (u32, u32, usize) =
127+
match (orig.parse(), rem.parse(), new_lines.parse()) {
128+
(Ok(a), Ok(b), Ok(c)) => (a, b, c),
129+
_ => return Err(()),
130+
};
131+
eprintln!("{} {} {}", orig, rem, new_lines);
132+
let lines = lines.by_ref().take(new_lines);
133+
let lines: Vec<_> = lines.map(ToOwned::to_owned).collect();
134+
if lines.len() != new_lines {
135+
return Err(());
136+
}
137+
138+
chunks.push(ModifiedChunk {
139+
line_number_orig: orig,
140+
lines_removed: rem,
141+
lines,
142+
});
143+
}
144+
145+
Ok(ModifiedLines { chunks })
146+
}
147+
}
148+
36149
// This struct handles writing output to stdout and abstracts away the logic
37150
// of printing in color, if it's possible in the executing environment.
38151
pub struct OutputWriter {
@@ -174,49 +287,11 @@ where
174287
}
175288
}
176289

177-
/// Converts a `Mismatch` into a serialized form, which just includes
178-
/// enough information to modify the original file.
179-
/// Each section starts with a line with three integers, space separated:
180-
/// lineno num_removed num_added
181-
/// followed by (`num_added`) lines of added text. The line numbers are
182-
/// relative to the original file.
183-
pub fn output_modified<W>(mut out: W, diff: Vec<Mismatch>)
184-
where
185-
W: Write,
186-
{
187-
for mismatch in diff {
188-
let (num_removed, num_added) =
189-
mismatch
190-
.lines
191-
.iter()
192-
.fold((0, 0), |(rem, add), line| match *line {
193-
DiffLine::Context(_) => panic!("No Context expected"),
194-
DiffLine::Expected(_) => (rem, add + 1),
195-
DiffLine::Resulting(_) => (rem + 1, add),
196-
});
197-
// Write a header with enough information to separate the modified lines.
198-
writeln!(
199-
out,
200-
"{} {} {}",
201-
mismatch.line_number_orig, num_removed, num_added
202-
)
203-
.unwrap();
204-
205-
for line in mismatch.lines {
206-
match line {
207-
DiffLine::Context(_) | DiffLine::Resulting(_) => (),
208-
DiffLine::Expected(ref str) => {
209-
writeln!(out, "{}", str).unwrap();
210-
}
211-
}
212-
}
213-
}
214-
}
215-
216290
#[cfg(test)]
217291
mod test {
218292
use super::DiffLine::*;
219293
use super::{make_diff, Mismatch};
294+
use super::{ModifiedChunk, ModifiedLines};
220295

221296
#[test]
222297
fn diff_simple() {
@@ -298,4 +373,35 @@ mod test {
298373
}]
299374
);
300375
}
376+
377+
#[test]
378+
fn modified_lines_from_str() {
379+
use std::str::FromStr;
380+
381+
let src = "1 6 2\nfn some() {}\nfn main() {}\n25 3 1\n struct Test {}";
382+
let lines = ModifiedLines::from_str(src).unwrap();
383+
assert_eq!(
384+
lines,
385+
ModifiedLines {
386+
chunks: vec![
387+
ModifiedChunk {
388+
line_number_orig: 1,
389+
lines_removed: 6,
390+
lines: vec!["fn some() {}".to_owned(), "fn main() {}".to_owned(),]
391+
},
392+
ModifiedChunk {
393+
line_number_orig: 25,
394+
lines_removed: 3,
395+
lines: vec![" struct Test {}".to_owned()]
396+
}
397+
]
398+
}
399+
);
400+
401+
let src = "1 5 3";
402+
assert_eq!(ModifiedLines::from_str(src), Err(()));
403+
404+
let src = "1 5 3\na\nb";
405+
assert_eq!(ModifiedLines::from_str(src), Err(()));
406+
}
301407
}

src/source_file.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syntax::source_map::SourceMap;
66

77
use crate::checkstyle::output_checkstyle_file;
88
use crate::config::{Config, EmitMode, FileName, Verbosity};
9-
use crate::rustfmt_diff::{make_diff, output_modified, print_diff};
9+
use crate::rustfmt_diff::{make_diff, print_diff, ModifiedLines};
1010

1111
#[cfg(test)]
1212
use crate::formatting::FileRecord;
@@ -107,7 +107,7 @@ where
107107
EmitMode::ModifiedLines => {
108108
let mismatch = make_diff(&original_text, formatted_text, 0);
109109
let has_diff = !mismatch.is_empty();
110-
output_modified(out, mismatch);
110+
write!(out, "{}", ModifiedLines::from(mismatch))?;
111111
return Ok(has_diff);
112112
}
113113
EmitMode::Checkstyle => {

src/test/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use std::process::{Command, Stdio};
99
use std::str::Chars;
1010

1111
use crate::config::{Color, Config, EmitMode, FileName, ReportTactic};
12-
use crate::formatting::{ModifiedChunk, ReportedErrors, SourceFile};
13-
use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, OutputWriter};
12+
use crate::formatting::{ReportedErrors, SourceFile};
13+
use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChunk, OutputWriter};
1414
use crate::source_file;
1515
use crate::{FormatReport, Input, Session};
1616

0 commit comments

Comments
 (0)