From 5d9f5aa05a668e7dfef87b46d89dad2884df9d41 Mon Sep 17 00:00:00 2001
From: Nick Cameron <ncameron@mozilla.com>
Date: Sun, 13 May 2018 14:13:24 +1200
Subject: [PATCH] Replace `--write-mode` with `--emit`

cc #1976
---
 README.md             | 51 +++++--------------------------------------
 bootstrap.sh          |  8 +++----
 src/bin/main.rs       | 11 +++-------
 src/config/options.rs | 20 ++++++++++++-----
 src/config/summary.rs |  2 +-
 src/lib.rs            |  3 ++-
 src/test/mod.rs       | 13 +----------
 7 files changed, 32 insertions(+), 76 deletions(-)

diff --git a/README.md b/README.md
index 4322901d18a..6dc437fd27f 100644
--- a/README.md
+++ b/README.md
@@ -105,53 +105,14 @@ just need to run on the root file (usually mod.rs or lib.rs). Rustfmt can also
 read data from stdin. Alternatively, you can use `cargo fmt` to format all
 binary and library targets of your crate.
 
-You'll probably want to specify the write mode. Currently, there are modes for
-`check`, `diff`, `replace`, `overwrite`, `display`, `coverage`, `checkstyle`, and `plain`.
+You can run `rustfmt --help` for information about argument.
 
-* `overwrite` Is the default and overwrites the original files _without_ creating backups.
-* `replace` Overwrites the original files after creating backups of the files.
-* `display` Will print the formatted files to stdout.
-* `plain` Also writes to stdout, but with no metadata.
-* `diff` Will print a diff between the original files and formatted files to stdout.
-* `check` Checks if the program's formatting matches what rustfmt would do. Silently exits
-          with code 0 if so, emits a diff and exits with code 1 if not. This option is
-          designed to be run in CI-like where a non-zero exit signifies incorrect formatting.
-* `checkstyle` Will output the lines that need to be corrected as a checkstyle XML file,
-  that can be used by tools like Jenkins.
+When running with `--check`, Rustfmt will exit with `0` if Rustfmt would not
+make any formatting changes to the input, and `1` if Rustfmt would make changes.
+In other modes, Rustfmt will exit with `1` if there was some error during
+formatting (for example a parsing or internal error) and `0` if formatting
+completed without error (whether or not changes were made).
 
-The write mode can be set by passing the `--write-mode` flag on
-the command line. For example `rustfmt --write-mode=display src/filename.rs`
-
-`cargo fmt` uses `--write-mode=overwrite` by default.
-
-If you want to restrict reformatting to specific sets of lines, you can
-use the `--file-lines` option. Its argument is a JSON array of objects
-with `file` and `range` properties, where `file` is a file name, and
-`range` is an array representing a range of lines like `[7,13]`. Ranges
-are 1-based and inclusive of both end points. Specifying an empty array
-will result in no files being formatted. For example,
-
-```
-rustfmt --file-lines '[
-    {"file":"src/lib.rs","range":[7,13]},
-    {"file":"src/lib.rs","range":[21,29]},
-    {"file":"src/foo.rs","range":[10,11]},
-    {"file":"src/foo.rs","range":[15,15]}]'
-```
-
-would format lines `7-13` and `21-29` of `src/lib.rs`, and lines `10-11`,
-and `15` of `src/foo.rs`. No other files would be formatted, even if they
-are included as out of line modules from `src/lib.rs`.
-
-If `rustfmt` successfully reformatted the code it will exit with `0` exit
-status. Exit status `1` signals some unexpected error, like an unknown option or
-a failure to read a file. Exit status `2` is returned if there are syntax errors
-in the input files. `rustfmt` can't format syntactically invalid code. Finally,
-exit status `3` is returned if there are some issues which can't be resolved
-automatically. For example, if you have a very long comment line `rustfmt`
-doesn't split it. Instead it prints a warning and exits with `3`.
-
-You can run `rustfmt --help` for more information.
 
 
 ## Running Rustfmt from your editor
diff --git a/bootstrap.sh b/bootstrap.sh
index ae37b043c05..05ac0ce2f30 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -6,12 +6,12 @@
 
 cargo build --release
 
-target/release/rustfmt --write-mode=overwrite src/lib.rs
-target/release/rustfmt --write-mode=overwrite src/bin/main.rs
-target/release/rustfmt --write-mode=overwrite src/cargo-fmt/main.rs
+target/release/rustfmt src/lib.rs
+target/release/rustfmt src/bin/main.rs
+target/release/rustfmt src/cargo-fmt/main.rs
 
 for filename in tests/target/*.rs; do
     if ! grep -q "rustfmt-" "$filename"; then
-        target/release/rustfmt --write-mode=overwrite $filename
+        target/release/rustfmt $filename
     fi
 done
diff --git a/src/bin/main.rs b/src/bin/main.rs
index c903ba18561..b8f5225633f 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -111,6 +111,7 @@ fn make_opts() -> Options {
          found reverts to the input file path",
         "[Path for the configuration file]",
     );
+    opts.optopt("", "emit", "What data to emit and how", WRITE_MODE_LIST);
     opts.optflag(
         "",
         "error-on-unformatted",
@@ -120,13 +121,13 @@ fn make_opts() -> Options {
     opts.optopt(
         "",
         "file-lines",
-        "Format specified line ranges. See README for more detail on the JSON format.",
+        "Format specified line ranges. Run with `--help file-lines` for more detail.",
         "JSON",
     );
     opts.optflagopt(
         "h",
         "help",
-        "Show this message or help about a specific topic: config or file-lines",
+        "Show this message or help about a specific topic: `config` or `file-lines`",
         "=TOPIC",
     );
     opts.optopt(
@@ -145,12 +146,6 @@ fn make_opts() -> Options {
     opts.optflag("v", "verbose", "Print verbose output");
     opts.optflag("q", "quiet", "Print less output");
     opts.optflag("V", "version", "Show version information");
-    opts.optopt(
-        "",
-        "write-mode",
-        "How to write output (not usable when piping from stdin)",
-        WRITE_MODE_LIST,
-    );
 
     opts
 }
diff --git a/src/config/options.rs b/src/config/options.rs
index b3c0acb854e..e4ba87a88f8 100644
--- a/src/config/options.rs
+++ b/src/config/options.rs
@@ -363,11 +363,11 @@ impl CliOptions {
         options.config_path = matches.opt_str("config-path").map(PathBuf::from);
 
         options.check = matches.opt_present("check");
-        if let Some(ref write_mode) = matches.opt_str("write-mode") {
+        if let Some(ref emit_str) = matches.opt_str("emit") {
             if options.check {
-                return Err(format_err!("Invalid to set write-mode and `--check`"));
+                return Err(format_err!("Invalid to use `--emit` and `--check`"));
             }
-            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
+            if let Ok(write_mode) = write_mode_from_emit_str(emit_str) {
                 if write_mode == WriteMode::Overwrite && matches.opt_present("backup") {
                     options.write_mode = Some(WriteMode::Replace);
                 } else {
@@ -375,8 +375,8 @@ impl CliOptions {
                 }
             } else {
                 return Err(format_err!(
-                    "Invalid write-mode: {}, expected one of {}",
-                    write_mode,
+                    "Invalid value for `--emit`: {}, expected one of {}",
+                    emit_str,
                     WRITE_MODE_LIST
                 ));
             }
@@ -441,3 +441,13 @@ impl CliOptions {
         }
     }
 }
+
+fn write_mode_from_emit_str(emit_str: &str) -> FmtResult<WriteMode> {
+    match emit_str {
+        "files" => Ok(WriteMode::Overwrite),
+        "stdout" => Ok(WriteMode::Display),
+        "coverage" => Ok(WriteMode::Coverage),
+        "checkstyle" => Ok(WriteMode::Checkstyle),
+        _ => Err(format_err!("Invalid value for `--emit`")),
+    }
+}
diff --git a/src/config/summary.rs b/src/config/summary.rs
index 9f339b61be7..e436856d286 100644
--- a/src/config/summary.rs
+++ b/src/config/summary.rs
@@ -23,7 +23,7 @@ pub struct Summary {
     // Code is valid, but it is impossible to format it properly.
     has_formatting_errors: bool,
 
-    // Formatted code differs from existing code (write-mode diff only).
+    // Formatted code differs from existing code (--check only).
     pub has_diff: bool,
 
     // Keeps track of time spent in parsing and formatting steps.
diff --git a/src/lib.rs b/src/lib.rs
index e30f4d586bd..5fb3e4b03e3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -68,7 +68,8 @@ pub use config::{file_lines, load_config, Config, Verbosity, WriteMode};
 
 pub type FmtResult<T> = std::result::Result<T, failure::Error>;
 
-pub const WRITE_MODE_LIST: &str = "[overwrite|display|plain|diff|coverage|checkstyle]";
+// FIXME: this is badly named since the user-facing name is `emit` not `write-mode`.
+pub const WRITE_MODE_LIST: &str = "[files|stdout|coverage|checkstyle]";
 
 #[macro_use]
 mod utils;
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 631c8076ca7..4de69296e9f 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -912,18 +912,7 @@ fn verify_check_works() {
     let temp_file = make_temp_file("temp_check.rs");
     assert_cli::Assert::command(&[
         rustfmt().to_str().unwrap(),
-        "--write-mode=check",
-        temp_file.path.to_str().unwrap(),
-    ]).succeeds()
-        .unwrap();
-}
-
-#[test]
-fn verify_diff_works() {
-    let temp_file = make_temp_file("temp_diff.rs");
-    assert_cli::Assert::command(&[
-        rustfmt().to_str().unwrap(),
-        "--write-mode=diff",
+        "--check",
         temp_file.path.to_str().unwrap(),
     ]).succeeds()
         .unwrap();