#![cfg(not(test))]
-
extern crate env_logger;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;
use rustfmt::{run, Input, Summary};
use rustfmt::file_lines::FileLines;
-use rustfmt::config::{get_toml_path, Config, WriteMode};
+use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;
Version,
/// Print detailed configuration help.
ConfigHelp,
- /// Output default config to a file
- ConfigOutputDefault { path: String },
+ /// Output default config to a file, or stdout if None
+ ConfigOutputDefault {
+ path: Option<String>,
+ },
/// No file specified, read from stdin
Stdin {
input: String,
skip_children: bool,
verbose: bool,
write_mode: Option<WriteMode>,
+ color: Option<Color>,
file_lines: FileLines, // Default is all lines in all files.
+ unstable_features: bool,
}
impl CliOptions {
let mut options = CliOptions::default();
options.skip_children = matches.opt_present("skip-children");
options.verbose = matches.opt_present("verbose");
+ let unstable_features = matches.opt_present("unstable-features");
+ let rust_nightly = option_env!("CFG_RELEASE_CHANNEL")
+ .map(|c| c == "nightly")
+ .unwrap_or(false);
+ if unstable_features && !rust_nightly {
+ return Err(FmtError::from(
+ "Unstable features are only available on Nightly channel",
+ ));
+ } else {
+ options.unstable_features = unstable_features;
+ }
if let Some(ref write_mode) = matches.opt_str("write-mode") {
if let Ok(write_mode) = WriteMode::from_str(write_mode) {
options.write_mode = Some(write_mode);
} else {
- return Err(FmtError::from(
- format!("Invalid write-mode: {}", write_mode),
- ));
+ return Err(FmtError::from(format!(
+ "Invalid write-mode: {}",
+ write_mode
+ )));
+ }
+ }
+
+ if let Some(ref color) = matches.opt_str("color") {
+ match Color::from_str(color) {
+ Ok(color) => options.color = Some(color),
+ _ => return Err(FmtError::from(format!("Invalid color: {}", color))),
}
}
config.set().skip_children(self.skip_children);
config.set().verbose(self.verbose);
config.set().file_lines(self.file_lines);
+ config.set().unstable_features(self.unstable_features);
if let Some(write_mode) = self.write_mode {
config.set().write_mode(write_mode);
}
+ if let Some(color) = self.color {
+ config.set().color(color);
+ }
}
}
fn make_opts() -> Options {
let mut opts = Options::new();
- opts.optflag("h", "help", "show this message");
- opts.optflag("V", "version", "show version information");
- opts.optflag("v", "verbose", "print verbose output");
+
+ opts.optflag("h", "help", "Show this message");
+ opts.optflag("V", "version", "Show version information");
+ opts.optflag("v", "verbose", "Print verbose output");
+ opts.optflag("", "skip-children", "Don't reformat child modules");
+ opts.optflag(
+ "",
+ "unstable-features",
+ "Enables unstable features. Only available on nightly channel",
+ );
+ opts.optflag(
+ "",
+ "config-help",
+ "Show details of rustfmt configuration options",
+ );
+ opts.optflag(
+ "",
+ "error-on-unformatted",
+ "Error if unable to get comments or string literals within max_width, \
+ or they are left with trailing whitespaces",
+ );
+
opts.optopt(
"",
"write-mode",
- "how to write output (not usable when piping from stdin)",
+ "How to write output (not usable when piping from stdin)",
"[replace|overwrite|display|plain|diff|coverage|checkstyle]",
);
- opts.optflag("", "skip-children", "don't reformat child modules");
-
- opts.optflag(
+ opts.optopt(
"",
- "config-help",
- "show details of rustfmt configuration options",
+ "color",
+ "Use colored output (if supported)",
+ "[always|never|auto]",
);
opts.optopt(
"",
"dump-default-config",
- "Dumps the default configuration to a file and exits.",
+ "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
"PATH",
);
opts.optopt(
match determine_operation(&matches)? {
Operation::Help => {
- print_usage(opts, "");
+ print_usage_to_stdout(opts, "");
Summary::print_exit_codes();
Ok(Summary::default())
}
Ok(Summary::default())
}
Operation::ConfigOutputDefault { path } => {
- let mut file = File::create(path)?;
let toml = Config::default().all_options().to_toml()?;
- file.write_all(toml.as_bytes())?;
+ if let Some(path) = path {
+ let mut file = File::create(path)?;
+ file.write_all(toml.as_bytes())?;
+ } else {
+ io::stdout().write_all(toml.as_bytes())?;
+ }
Ok(Summary::default())
}
Operation::Stdin { input, config_path } => {
config.set().file_lines(file_lines.parse()?);
for f in config.file_lines().files() {
if f != "stdin" {
- println!("Warning: Extra file listed in file_lines option '{}'", f);
+ eprintln!("Warning: Extra file listed in file_lines option '{}'", f);
}
}
}
for f in options.file_lines.files() {
if !files.contains(&PathBuf::from(f)) {
- println!("Warning: Extra file listed in file_lines option '{}'", f);
+ eprintln!("Warning: Extra file listed in file_lines option '{}'", f);
}
}
let mut error_summary = Summary::default();
for file in files {
if !file.exists() {
- println!("Error: file `{}` does not exist", file.to_str().unwrap());
+ eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
error_summary.add_operational_error();
} else if file.is_dir() {
- println!("Error: `{}` is a directory", file.to_str().unwrap());
+ eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
error_summary.add_operational_error();
} else {
// Check the file directory if the config-path could not be read or not provided
}
}
Err(e) => {
- print_usage(&opts, &e.to_string());
+ print_usage_to_stderr(&opts, &e.to_string());
1
}
};
std::process::exit(exit_code);
}
-fn print_usage(opts: &Options, reason: &str) {
- let reason = format!(
- "{}\n\nusage: {} [options] <file>...",
- reason,
- env::args_os().next().unwrap().to_string_lossy()
- );
- println!("{}", opts.usage(&reason));
+macro_rules! print_usage {
+ ($print:ident, $opts:ident, $reason:expr) => ({
+ let msg = format!(
+ "{}\n\nusage: {} [options] <file>...",
+ $reason,
+ env::args_os().next().unwrap().to_string_lossy()
+ );
+ $print!("{}", $opts.usage(&msg));
+ })
+}
+
+fn print_usage_to_stdout(opts: &Options, reason: &str) {
+ print_usage!(println, opts, reason);
+}
+
+fn print_usage_to_stderr(opts: &Options, reason: &str) {
+ print_usage!(eprintln, opts, reason);
}
fn print_version() {
return Ok(Operation::ConfigHelp);
}
- if let Some(path) = matches.opt_str("dump-default-config") {
- return Ok(Operation::ConfigOutputDefault { path });
+ if matches.opt_present("dump-default-config") {
+ // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
+ // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
+ // argument *plus* a free argument. Thus we check for that case in this branch -- this is
+ // required for backward compatibility.
+ if let Some(path) = matches.free.get(0) {
+ return Ok(Operation::ConfigOutputDefault {
+ path: Some(path.clone()),
+ });
+ } else {
+ return Ok(Operation::ConfigOutputDefault {
+ path: matches.opt_str("dump-default-config"),
+ });
+ }
}
if matches.opt_present("version") {