From e7a5f9327ea8abbac1e953b31c6e25c1717f6c3d Mon Sep 17 00:00:00 2001 From: Sinh Pham Date: Thu, 10 Sep 2015 18:27:22 -0400 Subject: [PATCH] Add diff write mode https://github.com/nrc/rustfmt/issues/261 --- Cargo.lock | 4 +- Cargo.toml | 4 +- src/bin/rustfmt.rs | 2 +- src/filemap.rs | 14 +++++- src/lib.rs | 6 +++ src/rustfmt_diff.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++ tests/system.rs | 104 ++---------------------------------------- 7 files changed, 137 insertions(+), 106 deletions(-) create mode 100644 src/rustfmt_diff.rs diff --git a/Cargo.lock b/Cargo.lock index 63854ccae46..30f07fd4f98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "rustfmt" version = "0.0.1" dependencies = [ - "diff 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "strings 0.0.1 (git+https://github.com/nrc/strings.rs.git)", @@ -21,7 +21,7 @@ dependencies = [ [[package]] name = "diff" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] diff --git a/Cargo.toml b/Cargo.toml index 597eb8f942d..9cb4f929344 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ toml = "0.1.20" rustc-serialize = "0.3.14" unicode-segmentation = "0.1.2" regex = "0.1.41" +diff = "0.1.5" +term = "0.2.11" [dev-dependencies] -diff = "0.1.0" -term = "0.2" diff --git a/src/bin/rustfmt.rs b/src/bin/rustfmt.rs index 86a4faa05f5..9f2387f5c2c 100644 --- a/src/bin/rustfmt.rs +++ b/src/bin/rustfmt.rs @@ -82,7 +82,7 @@ fn main() { } fn print_usage>(reason: S) { - println!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[replace|overwrite|display]] ", reason.into()); + println!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[replace|overwrite|display|diff]] ", reason.into()); } fn determine_params(args: I) -> Option<(Vec, WriteMode)> diff --git a/src/filemap.rs b/src/filemap.rs index 8bb5a7285bb..91aaece6558 100644 --- a/src/filemap.rs +++ b/src/filemap.rs @@ -14,10 +14,11 @@ use strings::string_buffer::StringBuffer; use std::collections::HashMap; use std::fs::{self, File}; -use std::io::{self, Write, stdout}; +use std::io::{self, Write, Read, stdout}; use WriteMode; use NewlineStyle; use config::Config; +use rustfmt_diff::{make_diff, print_diff}; // A map of the files of a crate, with their new content pub type FileMap = HashMap; @@ -104,6 +105,17 @@ fn write_file(text: &StringBuffer, let stdout_lock = stdout.lock(); try!(write_system_newlines(stdout_lock, text, config)); } + WriteMode::Diff => { + println!("Diff of {}:\n", filename); + let mut f = try!(File::open(filename)); + let mut ori_text = String::new(); + try!(f.read_to_string(&mut ori_text)); + let mut v = Vec::new(); + try!(write_system_newlines(&mut v, text, config)); + let fmt_text = String::from_utf8(v).unwrap(); + let diff = make_diff(&ori_text, &fmt_text, 3); + print_diff(diff, |line_num| format!("\nDiff at line {}:", line_num)); + } WriteMode::Return(_) => { // io::Write is not implemented for String, working around with // Vec diff --git a/src/lib.rs b/src/lib.rs index ab748f62a95..7975c77e06d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,8 @@ extern crate strings; extern crate unicode_segmentation; extern crate regex; +extern crate diff; +extern crate term; use rustc::session::Session; use rustc::session::config as rustc_config; @@ -67,6 +69,7 @@ mod rewrite; mod string; mod comment; mod modules; +pub mod rustfmt_diff; const MIN_STRING: usize = 10; // When we get scoped annotations, we should have rustfmt::skip. @@ -82,6 +85,8 @@ pub enum WriteMode { NewFile(&'static str), // Write the output to stdout. Display, + // Write the diff to stdout. + Diff, // Return the result as a mapping from filenames to Strings. Return(&'static Fn(HashMap)), } @@ -94,6 +99,7 @@ impl FromStr for WriteMode { "replace" => Ok(WriteMode::Replace), "display" => Ok(WriteMode::Display), "overwrite" => Ok(WriteMode::Overwrite), + "diff" => Ok(WriteMode::Diff), _ => Err(()), } } diff --git a/src/rustfmt_diff.rs b/src/rustfmt_diff.rs new file mode 100644 index 00000000000..375cfd661fa --- /dev/null +++ b/src/rustfmt_diff.rs @@ -0,0 +1,109 @@ +use std::collections::VecDeque; +use diff; +use term; + +pub enum DiffLine { + Context(String), + Expected(String), + Resulting(String), +} + +pub struct Mismatch { + pub line_number: u32, + pub lines: Vec, +} + +impl Mismatch { + fn new(line_number: u32) -> Mismatch { + Mismatch { line_number: line_number, lines: Vec::new() } + } +} + +// Produces a diff between the expected output and actual output of rustfmt. +pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { + let mut line_number = 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); + + for result in diff::lines(expected, actual) { + match result { + diff::Result::Left(str) => { + if lines_since_mismatch >= context_size { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Resulting(str.to_owned())); + lines_since_mismatch = 0; + } + diff::Result::Right(str) => { + if lines_since_mismatch >= context_size { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Expected(str.to_owned())); + line_number += 1; + lines_since_mismatch = 0; + } + diff::Result::Both(str, _) => { + if context_queue.len() >= context_size { + let _ = context_queue.pop_front(); + } + + if lines_since_mismatch < context_size { + mismatch.lines.push(DiffLine::Context(str.to_owned())); + } else { + context_queue.push_back(str); + } + + line_number += 1; + lines_since_mismatch += 1; + } + } + } + + results.push(mismatch); + results.remove(0); + + results +} + +pub fn print_diff(diff: Vec, get_section_title: F) + where F: Fn(u32) -> String +{ + let mut t = term::stdout().unwrap(); + for mismatch in diff { + t.fg(term::color::BRIGHT_WHITE).unwrap(); + let title = get_section_title(mismatch.line_number); + writeln!(t, "{}", title).unwrap(); + + for line in mismatch.lines { + match line { + DiffLine::Context(ref str) => { + t.fg(term::color::WHITE).unwrap(); + writeln!(t, " {}⏎", str).unwrap(); + } + DiffLine::Expected(ref str) => { + t.fg(term::color::GREEN).unwrap(); + writeln!(t, "+{}⏎", str).unwrap(); + } + DiffLine::Resulting(ref str) => { + t.fg(term::color::RED).unwrap(); + writeln!(t, "-{}⏎", str).unwrap(); + } + } + } + } + t.reset().unwrap(); +} diff --git a/tests/system.rs b/tests/system.rs index d6ba46c9cf5..b0d96468eca 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -15,12 +15,13 @@ extern crate diff; extern crate regex; extern crate term; -use std::collections::{VecDeque, HashMap}; +use std::collections::HashMap; use std::fs; use std::io::{self, Read, BufRead, BufReader}; use std::thread; use rustfmt::*; use rustfmt::config::Config; +use rustfmt::rustfmt_diff::*; static DIFF_CONTEXT_SIZE: usize = 3; @@ -94,27 +95,7 @@ fn print_mismatches(result: HashMap>) { let mut t = term::stdout().unwrap(); for (file_name, diff) in result { - for mismatch in diff { - t.fg(term::color::BRIGHT_WHITE).unwrap(); - writeln!(t, "\nMismatch at {}:{}:", file_name, mismatch.line_number).unwrap(); - - for line in mismatch.lines { - match line { - DiffLine::Context(ref str) => { - t.fg(term::color::WHITE).unwrap(); - writeln!(t, " {}⏎", str).unwrap(); - } - DiffLine::Expected(ref str) => { - t.fg(term::color::GREEN).unwrap(); - writeln!(t, "+{}⏎", str).unwrap(); - } - DiffLine::Resulting(ref str) => { - t.fg(term::color::RED).unwrap(); - writeln!(t, "-{}⏎", str).unwrap(); - } - } - } - } + print_diff(diff, |line_num| format!("\nMismatch at {}:{}:", file_name, line_num)); } assert!(t.reset().unwrap()); @@ -206,7 +187,7 @@ fn handle_result(result: HashMap) { // TODO: speedup by running through bytes iterator f.read_to_string(&mut text).ok().expect("Failed reading target."); if fmt_text != text { - let diff = make_diff(&fmt_text, &text, DIFF_CONTEXT_SIZE); + let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE); failures.insert(file_name, diff); } } @@ -226,80 +207,3 @@ fn get_target(file_name: &str, target: Option<&str>) -> String { file_name.to_owned() } } - -pub enum DiffLine { - Context(String), - Expected(String), - Resulting(String), -} - -pub struct Mismatch { - line_number: u32, - pub lines: Vec, -} - -impl Mismatch { - fn new(line_number: u32) -> Mismatch { - Mismatch { line_number: line_number, lines: Vec::new() } - } -} - -// Produces a diff between the expected output and actual output of rustfmt. -fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { - let mut line_number = 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); - - for result in diff::lines(expected, actual) { - match result { - diff::Result::Left(str) => { - if lines_since_mismatch >= context_size { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Resulting(str.to_owned())); - lines_since_mismatch = 0; - } - diff::Result::Right(str) => { - if lines_since_mismatch >= context_size { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Expected(str.to_owned())); - line_number += 1; - lines_since_mismatch = 0; - } - diff::Result::Both(str, _) => { - if context_queue.len() >= context_size { - let _ = context_queue.pop_front(); - } - - if lines_since_mismatch < context_size { - mismatch.lines.push(DiffLine::Context(str.to_owned())); - } else { - context_queue.push_back(str); - } - - line_number += 1; - lines_since_mismatch += 1; - } - } - } - - results.push(mismatch); - results.remove(0); - - results -}