Add a new get_modified_lines() API to get only the new
changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583e0e3e222
Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147fa794f58
Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286175c0c6f
Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c2adf7eec
Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge:e48dd81a
2a84352d
Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
This commit is contained in:
parent
e0e3e22248
commit
fc377f3fb0
@ -1766,7 +1766,7 @@ See also: [`match_block_trailing_comma`](#match_block_trailing_comma).
|
||||
What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage
|
||||
|
||||
- **Default value**: `"Overwrite"`
|
||||
- **Possible values**: `"Checkstyle"`, `"Coverage"`, `"Diff"`, `"Display"`, `"Overwrite"`, `"Plain"`, `"Replace"`
|
||||
- **Possible values**: `"Checkstyle"`, `"Coverage"`, `"Diff"`, `"Display"`, `"Overwrite"`, `"Plain"`, `"Replace"`, `"Modified"`
|
||||
- **Stable**: No
|
||||
|
||||
## `blank_lines_upper_bound`
|
||||
|
@ -128,6 +128,8 @@ pub fn to_list_tactic(self) -> ListTactic {
|
||||
Plain,
|
||||
// Outputs a checkstyle XML file.
|
||||
Checkstyle,
|
||||
// Output the changed lines
|
||||
Modified,
|
||||
}
|
||||
|
||||
configuration_option_enum! { Color:
|
||||
@ -298,7 +300,7 @@ pub fn to_toml(&self) -> Result<String, String> {
|
||||
|
||||
// Macro hygiene won't allow us to make `set_$i()` methods on Config
|
||||
// for each item, so this struct is used to give the API to set values:
|
||||
// `config.get().option(false)`. It's pretty ugly. Consider replacing
|
||||
// `config.set().option(false)`. It's pretty ugly. Consider replacing
|
||||
// with `config.set_option(false)` if we ever get a stable/usable
|
||||
// `concat_idents!()`.
|
||||
pub struct ConfigSetter<'a>(&'a mut Config);
|
||||
@ -677,7 +679,7 @@ pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
|
||||
// Control options (changes the operation of rustfmt, rather than the formatting)
|
||||
write_mode: WriteMode, WriteMode::Overwrite, false,
|
||||
"What Write Mode to use when none is supplied: \
|
||||
Replace, Overwrite, Display, Plain, Diff, Coverage";
|
||||
Replace, Overwrite, Display, Plain, Diff, Coverage, Modified";
|
||||
color: Color, Color::Auto, false,
|
||||
"What Color option to use when none is supplied: Always, Never, Auto";
|
||||
required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use checkstyle::{output_checkstyle_file, output_footer, output_header};
|
||||
use config::{Config, NewlineStyle, WriteMode};
|
||||
use rustfmt_diff::{make_diff, print_diff, Mismatch};
|
||||
use rustfmt_diff::{make_diff, output_modified, print_diff, Mismatch};
|
||||
use syntax::codemap::FileName;
|
||||
|
||||
// A map of the files of a crate, with their new content
|
||||
@ -167,6 +167,15 @@ fn create_diff(
|
||||
return Ok(has_diff);
|
||||
}
|
||||
}
|
||||
WriteMode::Modified => {
|
||||
let filename = filename_to_path();
|
||||
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
|
||||
let mismatch = make_diff(&ori, &fmt, 0);
|
||||
let has_diff = !mismatch.is_empty();
|
||||
output_modified(out, mismatch);
|
||||
return Ok(has_diff);
|
||||
}
|
||||
}
|
||||
WriteMode::Checkstyle => {
|
||||
let filename = filename_to_path();
|
||||
let diff = create_diff(filename, text, config)?;
|
||||
|
63
src/lib.rs
63
src/lib.rs
@ -29,7 +29,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io::{self, stdout, Write};
|
||||
use std::io::{self, stdout, BufRead, Write};
|
||||
use std::iter::repeat;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
@ -693,6 +693,67 @@ fn duration_to_f32(d: Duration) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// A single span of changed lines, with 0 or more removed lines
|
||||
/// and a vector of 0 or more inserted lines.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ModifiedChunk {
|
||||
/// The first affected line before formatting.
|
||||
pub line_number: u32,
|
||||
/// The number of lines which have been replaced
|
||||
pub lines_removed: u32,
|
||||
/// The new lines
|
||||
pub lines: Vec<String>,
|
||||
}
|
||||
|
||||
/// Set of changed sections of a file.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ModifiedLines {
|
||||
/// The set of changed chunks.
|
||||
pub chunks: Vec<ModifiedChunk>,
|
||||
}
|
||||
|
||||
/// Format a file and return a `ModifiedLines` data structure describing
|
||||
/// the changed ranges of lines.
|
||||
pub fn get_modified_lines(
|
||||
input: Input,
|
||||
config: &Config,
|
||||
) -> Result<(Summary, FileMap, FormatReport, ModifiedLines), (io::Error, Summary)> {
|
||||
let mut data = Vec::new();
|
||||
|
||||
let mut config = config.clone();
|
||||
config.set().write_mode(config::WriteMode::Modified);
|
||||
let (summary, filemap, formatreport) = format_input(input, &config, Some(&mut data))?;
|
||||
|
||||
let mut lines = data.lines();
|
||||
let mut chunks = Vec::new();
|
||||
while let Some(Ok(header)) = lines.next() {
|
||||
// Parse the header line
|
||||
let values: Vec<_> = header
|
||||
.split(' ')
|
||||
.map(|s| s.parse::<u32>().unwrap())
|
||||
.collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
let line_number = values[0];
|
||||
let num_removed = values[1];
|
||||
let num_added = values[2];
|
||||
let mut added_lines = Vec::new();
|
||||
for _ in 0..num_added {
|
||||
added_lines.push(lines.next().unwrap().unwrap());
|
||||
}
|
||||
chunks.push(ModifiedChunk {
|
||||
line_number: line_number,
|
||||
lines_removed: num_removed,
|
||||
lines: added_lines,
|
||||
});
|
||||
}
|
||||
Ok((
|
||||
summary,
|
||||
filemap,
|
||||
formatreport,
|
||||
ModifiedLines { chunks: chunks },
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Input {
|
||||
File(PathBuf),
|
||||
|
@ -13,6 +13,7 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::io;
|
||||
use term;
|
||||
use std::io::Write;
|
||||
use utils::use_colored_tty;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@ -24,14 +25,19 @@ pub enum DiffLine {
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Mismatch {
|
||||
/// The line number in the formatted version.
|
||||
pub line_number: u32,
|
||||
/// The line number in the original version.
|
||||
pub line_number_orig: u32,
|
||||
/// The set of lines (context and old/new) in the mismatch.
|
||||
pub lines: Vec<DiffLine>,
|
||||
}
|
||||
|
||||
impl Mismatch {
|
||||
fn new(line_number: u32) -> Mismatch {
|
||||
fn new(line_number: u32, line_number_orig: u32) -> Mismatch {
|
||||
Mismatch {
|
||||
line_number: line_number,
|
||||
line_number_orig: line_number_orig,
|
||||
lines: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -77,17 +83,21 @@ pub fn writeln(&mut self, msg: &str, color: Option<term::color::Color>) {
|
||||
// Produces a diff between the expected output and actual output of rustfmt.
|
||||
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
|
||||
let mut line_number = 1;
|
||||
let mut line_number_orig = 1;
|
||||
let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
|
||||
let mut lines_since_mismatch = context_size + 1;
|
||||
let mut results = Vec::new();
|
||||
let mut mismatch = Mismatch::new(0);
|
||||
let mut mismatch = Mismatch::new(0, 0);
|
||||
|
||||
for result in diff::lines(expected, actual) {
|
||||
match result {
|
||||
diff::Result::Left(str) => {
|
||||
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
|
||||
results.push(mismatch);
|
||||
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
|
||||
mismatch = Mismatch::new(
|
||||
line_number - context_queue.len() as u32,
|
||||
line_number_orig - context_queue.len() as u32,
|
||||
);
|
||||
}
|
||||
|
||||
while let Some(line) = context_queue.pop_front() {
|
||||
@ -95,12 +105,16 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
|
||||
}
|
||||
|
||||
mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
|
||||
line_number_orig += 1;
|
||||
lines_since_mismatch = 0;
|
||||
}
|
||||
diff::Result::Right(str) => {
|
||||
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
|
||||
results.push(mismatch);
|
||||
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
|
||||
mismatch = Mismatch::new(
|
||||
line_number - context_queue.len() as u32,
|
||||
line_number_orig - context_queue.len() as u32,
|
||||
);
|
||||
}
|
||||
|
||||
while let Some(line) = context_queue.pop_front() {
|
||||
@ -123,6 +137,7 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
|
||||
}
|
||||
|
||||
line_number += 1;
|
||||
line_number_orig += 1;
|
||||
lines_since_mismatch += 1;
|
||||
}
|
||||
}
|
||||
@ -158,6 +173,42 @@ pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, color: Color)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a Mismatch into a serialised form which just includes
|
||||
/// enough information to modify the original file.
|
||||
/// Each section starts with a line with three integers, space separated:
|
||||
/// lineno num_removed num_added
|
||||
/// followd by (num_added) lines of added text. The line numbers are
|
||||
/// relative to the original file.
|
||||
pub fn output_modified<W>(mut out: W, diff: Vec<Mismatch>)
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
for mismatch in diff {
|
||||
let (num_removed, num_added) = mismatch.lines.iter().fold((0, 0), |(rem, add), line| {
|
||||
match *line {
|
||||
DiffLine::Context(_) => panic!("No Context expected"),
|
||||
DiffLine::Expected(_) => (rem, add + 1),
|
||||
DiffLine::Resulting(_) => (rem + 1, add),
|
||||
}
|
||||
});
|
||||
// Write a header with enough information to separate the modified lines.
|
||||
writeln!(
|
||||
out,
|
||||
"{} {} {}",
|
||||
mismatch.line_number_orig, num_removed, num_added
|
||||
).unwrap();
|
||||
|
||||
for line in mismatch.lines {
|
||||
match line {
|
||||
DiffLine::Context(_) | DiffLine::Resulting(_) => (),
|
||||
DiffLine::Expected(ref str) => {
|
||||
writeln!(out, "{}", str).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{make_diff, Mismatch};
|
||||
@ -173,6 +224,7 @@ fn diff_simple() {
|
||||
vec![
|
||||
Mismatch {
|
||||
line_number: 2,
|
||||
line_number_orig: 2,
|
||||
lines: vec![
|
||||
Context("two".to_owned()),
|
||||
Resulting("three".to_owned()),
|
||||
@ -194,6 +246,7 @@ fn diff_simple2() {
|
||||
vec![
|
||||
Mismatch {
|
||||
line_number: 2,
|
||||
line_number_orig: 2,
|
||||
lines: vec![
|
||||
Context("two".to_owned()),
|
||||
Resulting("three".to_owned()),
|
||||
@ -203,6 +256,7 @@ fn diff_simple2() {
|
||||
},
|
||||
Mismatch {
|
||||
line_number: 5,
|
||||
line_number_orig: 5,
|
||||
lines: vec![
|
||||
Resulting("five".to_owned()),
|
||||
Expected("cinq".to_owned()),
|
||||
@ -223,6 +277,7 @@ fn diff_zerocontext() {
|
||||
vec![
|
||||
Mismatch {
|
||||
line_number: 3,
|
||||
line_number_orig: 3,
|
||||
lines: vec![Resulting("three".to_owned()), Expected("trois".to_owned())],
|
||||
},
|
||||
]
|
||||
@ -239,6 +294,7 @@ fn diff_trailing_newline() {
|
||||
vec![
|
||||
Mismatch {
|
||||
line_number: 5,
|
||||
line_number_orig: 5,
|
||||
lines: vec![Context("five".to_owned()), Expected("".to_owned())],
|
||||
},
|
||||
]
|
||||
|
@ -143,6 +143,31 @@ fn checkstyle_test() {
|
||||
assert_output(Path::new(filename), Path::new(expected_filename));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modified_test() {
|
||||
// Test "modified" output
|
||||
let filename = "tests/writemode/source/modified.rs";
|
||||
let (_summary, _filemap, _report, modified) =
|
||||
get_modified_lines(Input::File(filename.into()), &Config::default()).unwrap();
|
||||
assert_eq!(
|
||||
modified,
|
||||
ModifiedLines {
|
||||
chunks: vec![
|
||||
ModifiedChunk {
|
||||
line_number: 4,
|
||||
lines_removed: 4,
|
||||
lines: vec!["fn blah() {}".into()],
|
||||
},
|
||||
ModifiedChunk {
|
||||
line_number: 9,
|
||||
lines_removed: 6,
|
||||
lines: vec!["#[cfg(a, b)]".into(), "fn main() {}".into()],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function for comparing the results of rustfmt
|
||||
// to a known output file generated by one of the write modes.
|
||||
fn assert_output(source: &Path, expected_filename: &Path) {
|
||||
@ -503,6 +528,7 @@ fn rustfmt_diff_make_diff_tests() {
|
||||
vec![
|
||||
Mismatch {
|
||||
line_number: 1,
|
||||
line_number_orig: 1,
|
||||
lines: vec![
|
||||
DiffLine::Context("a".into()),
|
||||
DiffLine::Resulting("b".into()),
|
||||
|
14
tests/writemode/source/modified.rs
Normal file
14
tests/writemode/source/modified.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// rustfmt-write_mode: modified
|
||||
// Test "modified" output
|
||||
|
||||
fn
|
||||
blah
|
||||
()
|
||||
{ }
|
||||
|
||||
|
||||
#[cfg
|
||||
( a , b
|
||||
)]
|
||||
fn
|
||||
main() {}
|
5
tests/writemode/target/modified.txt
Normal file
5
tests/writemode/target/modified.txt
Normal file
@ -0,0 +1,5 @@
|
||||
4 4 1
|
||||
fn blah() {}
|
||||
10 5 2
|
||||
#[cfg(a, b)]
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user