summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/colors.rs18
-rw-r--r--cli/diff.rs171
-rw-r--r--cli/fmt.rs25
-rw-r--r--cli/main.rs2
6 files changed, 223 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 29ff6ddb2..f26d6e7e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -445,6 +445,7 @@ dependencies = [
"deno_core",
"deno_typescript",
"dirs",
+ "dissimilar",
"dlopen",
"dprint-plugin-typescript",
"futures 0.3.5",
@@ -554,6 +555,12 @@ dependencies = [
]
[[package]]
+name = "dissimilar"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39de161cd2ebbd6e5783db53a82a47b6a47dcfef754130839603561745528b94"
+
+[[package]]
name = "dlopen"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index d6176bcf6..81eb9d7fb 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -28,6 +28,7 @@ bytes = "0.5.4"
byteorder = "1.3.4"
clap = "2.33.1"
dirs = "2.0.2"
+dissimilar = "1.0"
dlopen = "0.1.8"
dprint-plugin-typescript = "0.19.2"
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
diff --git a/cli/colors.rs b/cli/colors.rs
index 764704a5b..b9a5a7353 100644
--- a/cli/colors.rs
+++ b/cli/colors.rs
@@ -52,6 +52,12 @@ pub fn red_bold(s: String) -> impl fmt::Display {
style(&s, style_spec)
}
+pub fn green_bold(s: String) -> impl fmt::Display {
+ let mut style_spec = ColorSpec::new();
+ style_spec.set_fg(Some(Ansi256(10))).set_bold(true);
+ style(&s, style_spec)
+}
+
pub fn italic_bold(s: String) -> impl fmt::Display {
let mut style_spec = ColorSpec::new();
style_spec.set_bold(true).set_italic(true);
@@ -64,6 +70,18 @@ pub fn black_on_white(s: String) -> impl fmt::Display {
style(&s, style_spec)
}
+pub fn white_on_red(s: String) -> impl fmt::Display {
+ let mut style_spec = ColorSpec::new();
+ style_spec.set_bg(Some(Red)).set_fg(Some(White));
+ style(&s, style_spec)
+}
+
+pub fn white_on_green(s: String) -> impl fmt::Display {
+ let mut style_spec = ColorSpec::new();
+ style_spec.set_bg(Some(Ansi256(10))).set_fg(Some(White));
+ style(&s, style_spec)
+}
+
pub fn yellow(s: String) -> impl fmt::Display {
let mut style_spec = ColorSpec::new();
style_spec.set_fg(Some(Ansi256(11)));
diff --git a/cli/diff.rs b/cli/diff.rs
new file mode 100644
index 000000000..e6d7fa4bb
--- /dev/null
+++ b/cli/diff.rs
@@ -0,0 +1,171 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use crate::colors;
+use dissimilar::{diff as difference, Chunk};
+use std::fmt;
+use std::fmt::Write;
+
+fn fmt_add() -> String {
+ format!("{}", colors::green_bold("+".to_string()))
+}
+
+fn fmt_add_text(x: String) -> String {
+ format!("{}", colors::green(x))
+}
+
+fn fmt_add_text_highlight(x: String) -> String {
+ format!("{}", colors::white_on_green(x))
+}
+
+fn fmt_rem() -> String {
+ format!("{}", colors::red_bold("-".to_string()))
+}
+
+fn fmt_rem_text(x: String) -> String {
+ format!("{}", colors::red(x))
+}
+
+fn fmt_rem_text_highlight(x: String) -> String {
+ format!("{}", colors::white_on_red(x))
+}
+
+fn write_line_diff(
+ diff: &mut String,
+ orig_line: &mut usize,
+ edit_line: &mut usize,
+ line_number_width: usize,
+ orig: &mut String,
+ edit: &mut String,
+) -> fmt::Result {
+ let split = orig.split('\n').enumerate();
+ for (i, s) in split {
+ write!(
+ diff,
+ "{:0width$}{} ",
+ *orig_line + i,
+ colors::gray("|".to_string()),
+ width = line_number_width
+ )?;
+ write!(diff, "{}", fmt_rem())?;
+ write!(diff, "{}", s)?;
+ writeln!(diff)?;
+ }
+
+ let split = edit.split('\n').enumerate();
+ for (i, s) in split {
+ write!(
+ diff,
+ "{:0width$}{} ",
+ *edit_line + i,
+ colors::gray("|".to_string()),
+ width = line_number_width
+ )?;
+ write!(diff, "{}", fmt_add())?;
+ write!(diff, "{}", s)?;
+ writeln!(diff)?;
+ }
+
+ *orig_line += orig.split('\n').count();
+ *edit_line += edit.split('\n').count();
+
+ orig.clear();
+ edit.clear();
+
+ Ok(())
+}
+
+/// Print diff of the same file_path, before and after formatting.
+///
+/// Diff format is loosely based on Github diff formatting.
+pub fn diff(orig_text: &str, edit_text: &str) -> Result<String, fmt::Error> {
+ let lines = edit_text.split('\n').count();
+ let line_number_width = lines.to_string().chars().count();
+
+ let mut diff = String::new();
+
+ let mut text1 = orig_text.to_string();
+ let mut text2 = edit_text.to_string();
+
+ if !text1.ends_with('\n') {
+ writeln!(text1)?;
+ }
+ if !text2.ends_with('\n') {
+ writeln!(text2)?;
+ }
+
+ let mut orig_line: usize = 1;
+ let mut edit_line: usize = 1;
+ let mut orig: String = String::new();
+ let mut edit: String = String::new();
+ let mut changes = false;
+
+ let chunks = difference(&text1, &text2);
+ for chunk in chunks {
+ match chunk {
+ Chunk::Delete(s) => {
+ let split = s.split('\n').enumerate();
+ for (i, s) in split {
+ if i > 0 {
+ orig.push_str("\n");
+ }
+ orig.push_str(&fmt_rem_text_highlight(s.to_string()));
+ }
+ changes = true
+ }
+ Chunk::Insert(s) => {
+ let split = s.split('\n').enumerate();
+ for (i, s) in split {
+ if i > 0 {
+ edit.push_str("\n");
+ }
+ edit.push_str(&fmt_add_text_highlight(s.to_string()));
+ }
+ changes = true
+ }
+ Chunk::Equal(s) => {
+ let split = s.split('\n').enumerate();
+ for (i, s) in split {
+ if i > 0 {
+ if changes {
+ write_line_diff(
+ &mut diff,
+ &mut orig_line,
+ &mut edit_line,
+ line_number_width,
+ &mut orig,
+ &mut edit,
+ )?;
+ changes = false
+ } else {
+ orig.clear();
+ edit.clear();
+ orig_line += 1;
+ edit_line += 1;
+ }
+ }
+ orig.push_str(&fmt_rem_text(s.to_string()));
+ edit.push_str(&fmt_add_text(s.to_string()));
+ }
+ }
+ }
+ }
+ Ok(diff)
+}
+
+#[test]
+fn test_diff() {
+ let simple_console_log_unfmt = "console.log('Hello World')";
+ let simple_console_log_fmt = "console.log(\"Hello World\");";
+ assert_eq!(
+ colors::strip_ansi_codes(
+ &diff(simple_console_log_unfmt, simple_console_log_fmt).unwrap()
+ ),
+ "1| -console.log('Hello World')\n1| +console.log(\"Hello World\");\n"
+ );
+
+ let line_number_unfmt = "\n\n\n\nconsole.log(\n'Hello World'\n)";
+ let line_number_fmt = "console.log(\n\"Hello World\"\n);";
+ assert_eq!(
+ colors::strip_ansi_codes(&diff(line_number_unfmt, line_number_fmt).unwrap()),
+ "1| -\n2| -\n3| -\n4| -\n5| -console.log(\n1| +console.log(\n6| -'Hello World'\n2| +\"Hello World\"\n7| -)\n3| +);\n"
+ )
+}
diff --git a/cli/fmt.rs b/cli/fmt.rs
index 5d1becffa..0d7a909bc 100644
--- a/cli/fmt.rs
+++ b/cli/fmt.rs
@@ -7,6 +7,8 @@
//! the future it can be easily extended to provide
//! the same functions as ops available in JS runtime.
+use crate::colors;
+use crate::diff::diff;
use crate::fs::files_in_subtree;
use crate::op_error::OpError;
use deno_core::ErrBox;
@@ -63,7 +65,9 @@ async fn check_source_files(
) -> Result<(), ErrBox> {
let not_formatted_files_count = Arc::new(AtomicUsize::new(0));
let formatter = Arc::new(dprint::Formatter::new(config));
- let output_lock = Arc::new(Mutex::new(0)); // prevent threads outputting at the same time
+
+ // prevent threads outputting at the same time
+ let output_lock = Arc::new(Mutex::new(0));
run_parallelized(paths, {
let not_formatted_files_count = not_formatted_files_count.clone();
@@ -74,6 +78,25 @@ async fn check_source_files(
Ok(formatted_text) => {
if formatted_text != file_text {
not_formatted_files_count.fetch_add(1, Ordering::SeqCst);
+ let _g = output_lock.lock().unwrap();
+ match diff(&file_text, &formatted_text) {
+ Ok(diff) => {
+ println!();
+ println!(
+ "{} {}:",
+ colors::bold("from".to_string()),
+ file_path.display().to_string()
+ );
+ println!("{}", diff);
+ }
+ Err(e) => {
+ eprintln!(
+ "Error generating diff: {}",
+ file_path.to_string_lossy()
+ );
+ eprintln!(" {}", e);
+ }
+ }
}
}
Err(e) => {
diff --git a/cli/main.rs b/cli/main.rs
index 7da0e2df3..cf819ce5f 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
#![deny(warnings)]
+extern crate dissimilar;
#[macro_use]
extern crate lazy_static;
#[macro_use]
@@ -25,6 +26,7 @@ mod checksum;
pub mod colors;
pub mod deno_dir;
pub mod diagnostics;
+mod diff;
mod disk_cache;
mod doc;
mod file_fetcher;