rustfmt: Add option to specify line ranges for formatting

This commit adds the `--experimental-file-lines` option to rustfmt. This
allows specifying line ranges to format from the command line.

Refs #434
This commit is contained in:
Kamal Marhubi 2016-04-10 13:03:54 -04:00
parent 9fa5a91fc5
commit bef5d095a4
2 changed files with 40 additions and 5 deletions

View file

@ -73,6 +73,25 @@ the command line. For example `rustfmt --write-mode=display src/filename.rs`
`cargo fmt` uses `--write-mode=replace` by default. `cargo fmt` uses `--write-mode=replace` 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 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 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 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 a failure to read a file. Exit status `2` is returned if there are syntax errors

View file

@ -18,6 +18,7 @@ extern crate env_logger;
extern crate getopts; extern crate getopts;
use rustfmt::{run, Input, Summary}; use rustfmt::{run, Input, Summary};
use rustfmt::file_lines::FileLines;
use rustfmt::config::{Config, WriteMode}; use rustfmt::config::{Config, WriteMode};
use std::{env, error}; use std::{env, error};
@ -57,6 +58,7 @@ struct CliOptions {
skip_children: bool, skip_children: bool,
verbose: bool, verbose: bool,
write_mode: Option<WriteMode>, write_mode: Option<WriteMode>,
file_lines: FileLines, // Default is all lines in all files.
} }
impl CliOptions { impl CliOptions {
@ -73,12 +75,17 @@ impl CliOptions {
} }
} }
if let Some(ref file_lines) = matches.opt_str("file-lines") {
options.file_lines = try!(file_lines.parse());
}
Ok(options) Ok(options)
} }
fn apply_to(&self, config: &mut Config) { fn apply_to(self, config: &mut Config) {
config.skip_children = self.skip_children; config.skip_children = self.skip_children;
config.verbose = self.verbose; config.verbose = self.verbose;
config.file_lines = self.file_lines;
if let Some(write_mode) = self.write_mode { if let Some(write_mode) = self.write_mode {
config.write_mode = write_mode; config.write_mode = write_mode;
} }
@ -168,6 +175,10 @@ fn make_opts() -> Options {
"Recursively searches the given path for the rustfmt.toml config file. If not \ "Recursively searches the given path for the rustfmt.toml config file. If not \
found reverts to the input file path", found reverts to the input file path",
"[Path for the configuration file]"); "[Path for the configuration file]");
opts.optopt("",
"file-lines",
"Format specified line ranges. See README for more detail on the JSON format.",
"JSON");
opts opts
} }
@ -198,8 +209,12 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
Ok(run(Input::Text(input), &config)) Ok(run(Input::Text(input), &config))
} }
Operation::Format { files, config_path } => { Operation::Format { mut files, config_path } => {
let options = try!(CliOptions::from_matches(&matches)); let options = try!(CliOptions::from_matches(&matches));
// Add any additional files that were specified via `--file-lines`.
files.extend(options.file_lines.files().cloned().map(PathBuf::from));
let mut config = Config::default(); let mut config = Config::default();
let mut path = None; let mut path = None;
// Load the config path file if provided // Load the config path file if provided
@ -227,7 +242,7 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
config = config_tmp; config = config_tmp;
} }
options.apply_to(&mut config); options.clone().apply_to(&mut config);
error_summary.add(run(Input::File(file), &config)); error_summary.add(run(Input::File(file), &config));
} }
Ok(error_summary) Ok(error_summary)
@ -306,8 +321,8 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
Some(dir) Some(dir)
}); });
// if no file argument is supplied, read from stdin // if no file argument is supplied and `--file-lines` is not specified, read from stdin
if matches.free.is_empty() { if matches.free.is_empty() && !matches.opt_present("file-lines") {
let mut buffer = String::new(); let mut buffer = String::new();
try!(io::stdin().read_to_string(&mut buffer)); try!(io::stdin().read_to_string(&mut buffer));
@ -318,6 +333,7 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
}); });
} }
// We append files from `--file-lines` later in `execute()`.
let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect(); let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();
Ok(Operation::Format { Ok(Operation::Format {