Skip to content

Commit 8b40f66

Browse files
committed
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. We will remove the `experimental-` prefix once we have covered all AST elements, and are satisfied with the functionality. Refs rust-lang#434
1 parent 5e88444 commit 8b40f66

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ the command line. For example `rustfmt --write-mode=display src/filename.rs`
6565

6666
`cargo fmt` uses `--write-mode=replace` by default.
6767

68+
If you want to restrict reformatting to specific sets of lines, you can
69+
use the `--file-lines` option. Its argument is a JSON array of objects
70+
with `file` and `range` properties, where `file` is a file name, and
71+
`range` is an array representing a range of lines like `[7,13]`. Ranges
72+
are inclusive of both end points. Specifying an empty array will result in
73+
no files being formatted. For example,
74+
75+
```
76+
rustfmt --file-lines '[
77+
{"file":"src/lib.rs","range":[7,13]},
78+
{"file":"src/lib.rs","range":[21,29]},
79+
{"file":"src/foo.rs","range":[10,11]},
80+
{"file":"src/foo.rs","range":[15,15]}]'
81+
```
82+
83+
would format lines `7-13` and `21-29` of `src/lib.rs`, and lines `10-11`,
84+
and `15` of `src/foo.rs`. No other files would be formatted, even if they
85+
are included as out of line modules from `src/lib.rs`.
86+
6887
If `rustfmt` successfully reformatted the code it will exit with `0` exit
6988
status. Exit status `1` signals some unexpected error, like an unknown option or
7089
a failure to read a file. Exit status `2` is returned if there are syntax errors

src/bin/rustfmt.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern crate env_logger;
1818
extern crate getopts;
1919

2020
use rustfmt::{run, Input, Summary};
21+
use rustfmt::file_lines::FileLines;
2122
use rustfmt::config::{Config, WriteMode};
2223

2324
use std::{env, error};
@@ -57,6 +58,7 @@ struct CliOptions {
5758
skip_children: bool,
5859
verbose: bool,
5960
write_mode: Option<WriteMode>,
61+
file_lines: FileLines, // Default is all lines in all files.
6062
}
6163

6264
impl CliOptions {
@@ -73,12 +75,17 @@ impl CliOptions {
7375
}
7476
}
7577

78+
if let Some(ref file_lines) = matches.opt_str("file-lines") {
79+
options.file_lines = try!(file_lines.parse());
80+
}
81+
7682
Ok(options)
7783
}
7884

79-
fn apply_to(&self, config: &mut Config) {
85+
fn apply_to(self, config: &mut Config) {
8086
config.skip_children = self.skip_children;
8187
config.verbose = self.verbose;
88+
config.file_lines = self.file_lines;
8289
if let Some(write_mode) = self.write_mode {
8390
config.write_mode = write_mode;
8491
}
@@ -168,6 +175,10 @@ fn make_opts() -> Options {
168175
"Recursively searches the given path for the rustfmt.toml config file. If not \
169176
found reverts to the input file path",
170177
"[Path for the configuration file]");
178+
opts.optopt("",
179+
"file-lines",
180+
"Format specified line ranges. See README for more detail on the JSON format.",
181+
"JSON");
171182

172183
opts
173184
}
@@ -198,8 +209,12 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
198209

199210
Ok(run(Input::Text(input), &config))
200211
}
201-
Operation::Format { files, config_path } => {
212+
Operation::Format { mut files, config_path } => {
202213
let options = try!(CliOptions::from_matches(&matches));
214+
215+
// Add any additional files that were specified via `--file-lines`.
216+
files.extend(options.file_lines.files().cloned().map(PathBuf::from));
217+
203218
let mut config = Config::default();
204219
let mut path = None;
205220
// Load the config path file if provided
@@ -227,7 +242,7 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
227242
config = config_tmp;
228243
}
229244

230-
options.apply_to(&mut config);
245+
options.clone().apply_to(&mut config);
231246
error_summary.add(run(Input::File(file), &config));
232247
}
233248
Ok(error_summary)
@@ -306,8 +321,8 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
306321
Some(dir)
307322
});
308323

309-
// if no file argument is supplied, read from stdin
310-
if matches.free.is_empty() {
324+
// if no file argument is supplied and `--file-lines` is not specified, read from stdin
325+
if matches.free.is_empty() && !matches.opt_present("file-lines") {
311326

312327
let mut buffer = String::new();
313328
try!(io::stdin().read_to_string(&mut buffer));
@@ -318,6 +333,7 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
318333
});
319334
}
320335

336+
// We append files from `--file-lines` later in `execute()`.
321337
let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();
322338

323339
Ok(Operation::Format {

0 commit comments

Comments
 (0)