1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use std::collections::VecDeque;
16 use utils::use_colored_tty;
18 #[derive(Debug, PartialEq)]
25 #[derive(Debug, PartialEq)]
28 pub lines: Vec<DiffLine>,
32 fn new(line_number: u32) -> Mismatch {
34 line_number: line_number,
40 // Produces a diff between the expected output and actual output of rustfmt.
41 pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
42 let mut line_number = 1;
43 let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
44 let mut lines_since_mismatch = context_size + 1;
45 let mut results = Vec::new();
46 let mut mismatch = Mismatch::new(0);
48 for result in diff::lines(expected, actual) {
50 diff::Result::Left(str) => {
51 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
52 results.push(mismatch);
53 mismatch = Mismatch::new(line_number - context_queue.len() as u32);
56 while let Some(line) = context_queue.pop_front() {
57 mismatch.lines.push(DiffLine::Context(line.to_owned()));
60 mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
61 lines_since_mismatch = 0;
63 diff::Result::Right(str) => {
64 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
65 results.push(mismatch);
66 mismatch = Mismatch::new(line_number - context_queue.len() as u32);
69 while let Some(line) = context_queue.pop_front() {
70 mismatch.lines.push(DiffLine::Context(line.to_owned()));
73 mismatch.lines.push(DiffLine::Expected(str.to_owned()));
75 lines_since_mismatch = 0;
77 diff::Result::Both(str, _) => {
78 if context_queue.len() >= context_size {
79 let _ = context_queue.pop_front();
82 if lines_since_mismatch < context_size {
83 mismatch.lines.push(DiffLine::Context(str.to_owned()));
84 } else if context_size > 0 {
85 context_queue.push_back(str);
89 lines_since_mismatch += 1;
94 results.push(mismatch);
100 pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, color: Color)
102 F: Fn(u32) -> String,
104 match term::stdout() {
105 Some(ref t) if use_colored_tty(color) && t.supports_color() => {
106 print_diff_fancy(diff, get_section_title, term::stdout().unwrap())
108 _ => print_diff_basic(diff, get_section_title),
112 fn print_diff_fancy<F>(
114 get_section_title: F,
115 mut t: Box<term::Terminal<Output = io::Stdout>>,
117 F: Fn(u32) -> String,
119 for mismatch in diff {
120 let title = get_section_title(mismatch.line_number);
121 writeln!(t, "{}", title).unwrap();
123 for line in mismatch.lines {
125 DiffLine::Context(ref str) => {
127 writeln!(t, " {}⏎", str).unwrap();
129 DiffLine::Expected(ref str) => {
130 t.fg(term::color::GREEN).unwrap();
131 writeln!(t, "+{}⏎", str).unwrap();
133 DiffLine::Resulting(ref str) => {
134 t.fg(term::color::RED).unwrap();
135 writeln!(t, "-{}⏎", str).unwrap();
143 pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F)
145 F: Fn(u32) -> String,
147 for mismatch in diff {
148 let title = get_section_title(mismatch.line_number);
149 println!("{}", title);
151 for line in mismatch.lines {
153 DiffLine::Context(ref str) => {
154 println!(" {}⏎", str);
156 DiffLine::Expected(ref str) => {
157 println!("+{}⏎", str);
159 DiffLine::Resulting(ref str) => {
160 println!("-{}⏎", str);
169 use super::{make_diff, Mismatch};
170 use super::DiffLine::*;
174 let src = "one\ntwo\nthree\nfour\nfive\n";
175 let dest = "one\ntwo\ntrois\nfour\nfive\n";
176 let diff = make_diff(src, dest, 1);
183 Context("two".into()),
184 Resulting("three".into()),
185 Expected("trois".into()),
186 Context("four".into()),
195 let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
196 let dest = "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
197 let diff = make_diff(src, dest, 1);
204 Context("two".into()),
205 Resulting("three".into()),
206 Expected("trois".into()),
207 Context("four".into()),
213 Resulting("five".into()),
214 Expected("cinq".into()),
215 Context("six".into()),
223 fn diff_zerocontext() {
224 let src = "one\ntwo\nthree\nfour\nfive\n";
225 let dest = "one\ntwo\ntrois\nfour\nfive\n";
226 let diff = make_diff(src, dest, 0);
232 lines: vec![Resulting("three".into()), Expected("trois".into())],
239 fn diff_trailing_newline() {
240 let src = "one\ntwo\nthree\nfour\nfive";
241 let dest = "one\ntwo\nthree\nfour\nfive\n";
242 let diff = make_diff(src, dest, 1);
248 lines: vec![Context("five".into()), Expected("".into())],