mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Merge pull request #1007 from kamalmarhubi/basic-line-ranges-v2
Add infrastructure for formatting specific line ranges
This commit is contained in:
commit
240dba5467
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -7,6 +7,7 @@ dependencies = [
|
|||||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"multimap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -80,6 +81,11 @@ dependencies = [
|
|||||||
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "0.1.71"
|
version = "0.1.71"
|
||||||
|
@ -26,3 +26,4 @@ log = "0.3"
|
|||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
getopts = "0.2"
|
getopts = "0.2"
|
||||||
itertools = "0.4.15"
|
itertools = "0.4.15"
|
||||||
|
multimap = "0.3"
|
||||||
|
19
README.md
19
README.md
@ -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 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
|
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
|
||||||
|
@ -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 {
|
||||||
|
94
src/codemap.rs
Normal file
94
src/codemap.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! This module contains utilities that work with the `CodeMap` from libsyntax / syntex_syntax.
|
||||||
|
//! This includes extension traits and methods for looking up spans and line ranges for AST nodes.
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use syntax::codemap::{BytePos, CodeMap, FileMap, Span};
|
||||||
|
|
||||||
|
use comment::FindUncommented;
|
||||||
|
|
||||||
|
/// A range of lines in a file, inclusive of both ends.
|
||||||
|
pub struct LineRange {
|
||||||
|
pub file: Rc<FileMap>,
|
||||||
|
pub lo: usize,
|
||||||
|
pub hi: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineRange {
|
||||||
|
pub fn file_name(&self) -> &str {
|
||||||
|
self.file.as_ref().name.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SpanUtils {
|
||||||
|
fn span_after(&self, original: Span, needle: &str) -> BytePos;
|
||||||
|
fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
|
||||||
|
fn span_before(&self, original: Span, needle: &str) -> BytePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LineRangeUtils {
|
||||||
|
/// Returns the `LineRange` that corresponds to `span` in `self`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `span` crosses a file boundary, which shouldn't happen.
|
||||||
|
fn lookup_line_range(&self, span: Span) -> LineRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpanUtils for CodeMap {
|
||||||
|
#[inline]
|
||||||
|
fn span_after(&self, original: Span, needle: &str) -> BytePos {
|
||||||
|
let snippet = self.span_to_snippet(original).unwrap();
|
||||||
|
let offset = snippet.find_uncommented(needle).unwrap() + needle.len();
|
||||||
|
|
||||||
|
original.lo + BytePos(offset as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn span_after_last(&self, original: Span, needle: &str) -> BytePos {
|
||||||
|
let snippet = self.span_to_snippet(original).unwrap();
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) {
|
||||||
|
offset += additional_offset + needle.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
original.lo + BytePos(offset as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn span_before(&self, original: Span, needle: &str) -> BytePos {
|
||||||
|
let snippet = self.span_to_snippet(original).unwrap();
|
||||||
|
let offset = snippet.find_uncommented(needle).unwrap();
|
||||||
|
|
||||||
|
original.lo + BytePos(offset as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineRangeUtils for CodeMap {
|
||||||
|
fn lookup_line_range(&self, span: Span) -> LineRange {
|
||||||
|
let lo = self.lookup_char_pos(span.lo);
|
||||||
|
let hi = self.lookup_char_pos(span.hi);
|
||||||
|
|
||||||
|
assert!(lo.file.name == hi.file.name,
|
||||||
|
"span crossed file boundary: lo: {:?}, hi: {:?}",
|
||||||
|
lo,
|
||||||
|
hi);
|
||||||
|
|
||||||
|
LineRange {
|
||||||
|
file: lo.file.clone(),
|
||||||
|
lo: lo.line,
|
||||||
|
hi: hi.line,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
|
||||||
|
use file_lines::FileLines;
|
||||||
use lists::{SeparatorTactic, ListTactic};
|
use lists::{SeparatorTactic, ListTactic};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
@ -200,6 +201,12 @@ impl ConfigType for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConfigType for FileLines {
|
||||||
|
fn doc_hint() -> String {
|
||||||
|
String::from("<json>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ConfigHelpItem {
|
pub struct ConfigHelpItem {
|
||||||
option_name: &'static str,
|
option_name: &'static str,
|
||||||
doc_string: &'static str,
|
doc_string: &'static str,
|
||||||
@ -327,6 +334,9 @@ macro_rules! create_config {
|
|||||||
create_config! {
|
create_config! {
|
||||||
verbose: bool, false, "Use verbose output";
|
verbose: bool, false, "Use verbose output";
|
||||||
skip_children: bool, false, "Don't reformat out of line modules";
|
skip_children: bool, false, "Don't reformat out of line modules";
|
||||||
|
file_lines: FileLines, FileLines::all(),
|
||||||
|
"Lines to format; this is not supported in rustfmt.toml, and can only be specified \
|
||||||
|
via the --file-lines option";
|
||||||
max_width: usize, 100, "Maximum width of each line";
|
max_width: usize, 100, "Maximum width of each line";
|
||||||
ideal_width: usize, 80, "Ideal width of each line";
|
ideal_width: usize, 80, "Ideal width of each line";
|
||||||
tab_spaces: usize, 4, "Number of spaces per tab";
|
tab_spaces: usize, 4, "Number of spaces per tab";
|
||||||
|
@ -16,12 +16,13 @@ use std::iter::ExactSizeIterator;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use {Indent, Spanned};
|
use {Indent, Spanned};
|
||||||
|
use codemap::SpanUtils;
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
|
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
|
||||||
DefinitiveListTactic, definitive_tactic, ListItem, format_item_list};
|
DefinitiveListTactic, definitive_tactic, ListItem, format_item_list};
|
||||||
use string::{StringFormat, rewrite_string};
|
use string::{StringFormat, rewrite_string};
|
||||||
use utils::{CodeMapSpanUtils, extra_offset, last_line_width, wrap_str, binary_search,
|
use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_width,
|
||||||
first_line_width, semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr};
|
semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr};
|
||||||
use visitor::FmtVisitor;
|
use visitor::FmtVisitor;
|
||||||
use config::{Config, StructLitStyle, MultilineStyle, ElseIfBraceStyle, ControlBraceStyle};
|
use config::{Config, StructLitStyle, MultilineStyle, ElseIfBraceStyle, ControlBraceStyle};
|
||||||
use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed};
|
use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed};
|
||||||
|
232
src/file_lines.rs
Normal file
232
src/file_lines.rs
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! This module contains types and functions to support formatting specific line ranges.
|
||||||
|
use std::{cmp, iter, str};
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
use multimap::MultiMap;
|
||||||
|
use rustc_serialize::{self, json};
|
||||||
|
|
||||||
|
use codemap::LineRange;
|
||||||
|
|
||||||
|
/// A range that is inclusive of both ends.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcDecodable)]
|
||||||
|
struct Range {
|
||||||
|
pub lo: usize,
|
||||||
|
pub hi: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a LineRange> for Range {
|
||||||
|
fn from(range: &'a LineRange) -> Range {
|
||||||
|
Range::new(range.lo, range.hi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Range {
|
||||||
|
fn new(lo: usize, hi: usize) -> Range {
|
||||||
|
Range { lo: lo, hi: hi }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(self) -> bool {
|
||||||
|
self.lo > self.hi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains(self, other: Range) -> bool {
|
||||||
|
if other.is_empty() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
!self.is_empty() && self.lo <= other.lo && self.hi >= other.hi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersects(self, other: Range) -> bool {
|
||||||
|
if self.is_empty() || other.is_empty() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
(self.lo <= other.hi && other.hi <= self.hi) ||
|
||||||
|
(other.lo <= self.hi && self.hi <= other.hi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjacent_to(self, other: Range) -> bool {
|
||||||
|
if self.is_empty() || other.is_empty() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
self.hi + 1 == other.lo || other.hi + 1 == self.lo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new `Range` with lines from `self` and `other` if they were adjacent or
|
||||||
|
/// intersect; returns `None` otherwise.
|
||||||
|
fn merge(self, other: Range) -> Option<Range> {
|
||||||
|
if self.adjacent_to(other) || self.intersects(other) {
|
||||||
|
Some(Range::new(cmp::min(self.lo, other.lo), cmp::max(self.hi, other.hi)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A set of lines in files.
|
||||||
|
///
|
||||||
|
/// It is represented as a multimap keyed on file names, with values a collection of
|
||||||
|
/// non-overlapping ranges sorted by their start point. An inner `None` is interpreted to mean all
|
||||||
|
/// lines in all files.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct FileLines(Option<MultiMap<String, Range>>);
|
||||||
|
|
||||||
|
/// Normalizes the ranges so that the invariants for `FileLines` hold: ranges are non-overlapping,
|
||||||
|
/// and ordered by their start point.
|
||||||
|
fn normalize_ranges(map: &mut MultiMap<String, Range>) {
|
||||||
|
for (_, ranges) in map.iter_all_mut() {
|
||||||
|
ranges.sort_by_key(|x| x.lo);
|
||||||
|
let merged = ranges.drain(..).coalesce(|x, y| x.merge(y).ok_or((x, y))).collect();
|
||||||
|
*ranges = merged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileLines {
|
||||||
|
/// Creates a `FileLines` that contains all lines in all files.
|
||||||
|
pub fn all() -> FileLines {
|
||||||
|
FileLines(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `FileLines` from a `MultiMap`, ensuring that the invariants hold.
|
||||||
|
fn from_multimap(map: MultiMap<String, Range>) -> FileLines {
|
||||||
|
let mut map = map;
|
||||||
|
normalize_ranges(&mut map);
|
||||||
|
FileLines(Some(map))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the files contained in `self`.
|
||||||
|
pub fn files(&self) -> Files {
|
||||||
|
Files(self.0.as_ref().map(MultiMap::keys))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if `range` is fully contained in `self`.
|
||||||
|
pub fn contains(&self, range: &LineRange) -> bool {
|
||||||
|
let map = match self.0 {
|
||||||
|
// `None` means "all lines in all files".
|
||||||
|
None => return true,
|
||||||
|
Some(ref map) => map,
|
||||||
|
};
|
||||||
|
|
||||||
|
match map.get_vec(range.file_name()) {
|
||||||
|
None => false,
|
||||||
|
Some(ranges) => ranges.iter().any(|r| r.contains(Range::from(range))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if any lines in `range` are in `self`.
|
||||||
|
pub fn intersects(&self, range: &LineRange) -> bool {
|
||||||
|
let map = match self.0 {
|
||||||
|
// `None` means "all lines in all files".
|
||||||
|
None => return true,
|
||||||
|
Some(ref map) => map,
|
||||||
|
};
|
||||||
|
|
||||||
|
match map.get_vec(range.file_name()) {
|
||||||
|
None => false,
|
||||||
|
Some(ranges) => ranges.iter().any(|r| r.intersects(Range::from(range))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FileLines files iterator.
|
||||||
|
pub struct Files<'a>(Option<::std::collections::hash_map::Keys<'a, String, Vec<Range>>>);
|
||||||
|
|
||||||
|
impl<'a> iter::Iterator for Files<'a> {
|
||||||
|
type Item = &'a String;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<&'a String> {
|
||||||
|
self.0.as_mut().and_then(Iterator::next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This impl is needed for `Config::override_value` to work for use in tests.
|
||||||
|
impl str::FromStr for FileLines {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<FileLines, String> {
|
||||||
|
let v: Vec<JsonSpan> = try!(json::decode(s).map_err(|e| e.to_string()));
|
||||||
|
let m = v.into_iter().map(JsonSpan::into_tuple).collect();
|
||||||
|
Ok(FileLines::from_multimap(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For JSON decoding.
|
||||||
|
#[derive(Clone, Debug, RustcDecodable)]
|
||||||
|
struct JsonSpan {
|
||||||
|
file: String,
|
||||||
|
range: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonSpan {
|
||||||
|
// To allow `collect()`ing into a `MultiMap`.
|
||||||
|
fn into_tuple(self) -> (String, Range) {
|
||||||
|
let (lo, hi) = self.range;
|
||||||
|
(self.file, Range::new(lo, hi))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This impl is needed for inclusion in the `Config` struct. We don't have a toml representation
|
||||||
|
// for `FileLines`, so it will just panic instead.
|
||||||
|
impl rustc_serialize::Decodable for FileLines {
|
||||||
|
fn decode<D: rustc_serialize::Decoder>(_: &mut D) -> Result<Self, D::Error> {
|
||||||
|
panic!("FileLines cannot be deserialized from a project rustfmt.toml file: please \
|
||||||
|
specify it via the `--file-lines` option instead");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::Range;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_intersects() {
|
||||||
|
assert!(Range::new(1, 2).intersects(Range::new(1, 1)));
|
||||||
|
assert!(Range::new(1, 2).intersects(Range::new(2, 2)));
|
||||||
|
assert!(!Range::new(1, 2).intersects(Range::new(0, 0)));
|
||||||
|
assert!(!Range::new(1, 2).intersects(Range::new(3, 10)));
|
||||||
|
assert!(!Range::new(1, 3).intersects(Range::new(5, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_adjacent_to() {
|
||||||
|
assert!(!Range::new(1, 2).adjacent_to(Range::new(1, 1)));
|
||||||
|
assert!(!Range::new(1, 2).adjacent_to(Range::new(2, 2)));
|
||||||
|
assert!(Range::new(1, 2).adjacent_to(Range::new(0, 0)));
|
||||||
|
assert!(Range::new(1, 2).adjacent_to(Range::new(3, 10)));
|
||||||
|
assert!(!Range::new(1, 3).adjacent_to(Range::new(5, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_contains() {
|
||||||
|
assert!(Range::new(1, 2).contains(Range::new(1, 1)));
|
||||||
|
assert!(Range::new(1, 2).contains(Range::new(2, 2)));
|
||||||
|
assert!(!Range::new(1, 2).contains(Range::new(0, 0)));
|
||||||
|
assert!(!Range::new(1, 2).contains(Range::new(3, 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_merge() {
|
||||||
|
assert_eq!(None, Range::new(1, 3).merge(Range::new(5, 5)));
|
||||||
|
assert_eq!(None, Range::new(4, 7).merge(Range::new(0, 1)));
|
||||||
|
assert_eq!(Some(Range::new(3, 7)),
|
||||||
|
Range::new(3, 5).merge(Range::new(4, 7)));
|
||||||
|
assert_eq!(Some(Range::new(3, 7)),
|
||||||
|
Range::new(3, 5).merge(Range::new(5, 7)));
|
||||||
|
assert_eq!(Some(Range::new(3, 7)),
|
||||||
|
Range::new(3, 5).merge(Range::new(6, 7)));
|
||||||
|
assert_eq!(Some(Range::new(3, 7)),
|
||||||
|
Range::new(3, 7).merge(Range::new(4, 5)));
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,9 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
|
use codemap::SpanUtils;
|
||||||
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, definitive_tactic};
|
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, definitive_tactic};
|
||||||
use types::rewrite_path;
|
use types::rewrite_path;
|
||||||
use utils::CodeMapSpanUtils;
|
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
// Formatting top-level items - functions, structs, enums, traits, impls.
|
// Formatting top-level items - functions, structs, enums, traits, impls.
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
use utils::{CodeMapSpanUtils, format_mutability, format_visibility, contains_skip, end_typaram,
|
use codemap::SpanUtils;
|
||||||
wrap_str, last_line_width, semicolon_for_expr, format_unsafety, trim_newlines};
|
use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
|
||||||
|
last_line_width, semicolon_for_expr, format_unsafety, trim_newlines};
|
||||||
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
|
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
|
||||||
DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
|
DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
|
||||||
use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs};
|
use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs};
|
||||||
|
@ -25,6 +25,7 @@ extern crate regex;
|
|||||||
extern crate diff;
|
extern crate diff;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
extern crate multimap;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{mk_sp, CodeMap, Span};
|
use syntax::codemap::{mk_sp, CodeMap, Span};
|
||||||
@ -52,7 +53,9 @@ pub use self::summary::Summary;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod utils;
|
mod utils;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod codemap;
|
||||||
pub mod filemap;
|
pub mod filemap;
|
||||||
|
pub mod file_lines;
|
||||||
pub mod visitor;
|
pub mod visitor;
|
||||||
mod checkstyle;
|
mod checkstyle;
|
||||||
mod items;
|
mod items;
|
||||||
@ -470,6 +473,7 @@ pub fn format_input<T: Write>(input: Input,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
File(PathBuf),
|
File(PathBuf),
|
||||||
Text(String),
|
Text(String),
|
||||||
|
@ -25,10 +25,11 @@ use syntax::parse::tts_to_parser;
|
|||||||
use syntax::codemap::{mk_sp, BytePos};
|
use syntax::codemap::{mk_sp, BytePos};
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
|
use codemap::SpanUtils;
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use expr::{rewrite_call, rewrite_array};
|
use expr::{rewrite_call, rewrite_array};
|
||||||
use comment::{FindUncommented, contains_comment};
|
use comment::{FindUncommented, contains_comment};
|
||||||
use utils::{CodeMapSpanUtils, wrap_str};
|
use utils::wrap_str;
|
||||||
|
|
||||||
const FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
|
const FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
|
||||||
|
|
||||||
|
@ -9,8 +9,9 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
|
use codemap::SpanUtils;
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use utils::{CodeMapSpanUtils, wrap_str, format_mutability};
|
use utils::{wrap_str, format_mutability};
|
||||||
use lists::{format_item_list, itemize_list};
|
use lists::{format_item_list, itemize_list};
|
||||||
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
||||||
use types::rewrite_path;
|
use types::rewrite_path;
|
||||||
|
@ -17,9 +17,10 @@ use syntax::codemap::{self, Span, BytePos};
|
|||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
|
|
||||||
use {Indent, Spanned};
|
use {Indent, Spanned};
|
||||||
|
use codemap::SpanUtils;
|
||||||
use lists::{format_item_list, itemize_list, format_fn_args};
|
use lists::{format_item_list, itemize_list, format_fn_args};
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use utils::{CodeMapSpanUtils, extra_offset, format_mutability, wrap_str};
|
use utils::{extra_offset, format_mutability, wrap_str};
|
||||||
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
||||||
use config::TypeDensity;
|
use config::TypeDensity;
|
||||||
|
|
||||||
|
39
src/utils.rs
39
src/utils.rs
@ -14,51 +14,14 @@ use std::cmp::Ordering;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItemKind, Path};
|
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItemKind, Path};
|
||||||
use syntax::codemap::{CodeMap, Span, BytePos};
|
use syntax::codemap::BytePos;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
use comment::FindUncommented;
|
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
|
|
||||||
use SKIP_ANNOTATION;
|
use SKIP_ANNOTATION;
|
||||||
|
|
||||||
pub trait CodeMapSpanUtils {
|
|
||||||
fn span_after(&self, original: Span, needle: &str) -> BytePos;
|
|
||||||
fn span_after_last(&self, original: Span, needle: &str) -> BytePos;
|
|
||||||
fn span_before(&self, original: Span, needle: &str) -> BytePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CodeMapSpanUtils for CodeMap {
|
|
||||||
#[inline]
|
|
||||||
fn span_after(&self, original: Span, needle: &str) -> BytePos {
|
|
||||||
let snippet = self.span_to_snippet(original).unwrap();
|
|
||||||
let offset = snippet.find_uncommented(needle).unwrap() + needle.len();
|
|
||||||
|
|
||||||
original.lo + BytePos(offset as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn span_after_last(&self, original: Span, needle: &str) -> BytePos {
|
|
||||||
let snippet = self.span_to_snippet(original).unwrap();
|
|
||||||
let mut offset = 0;
|
|
||||||
|
|
||||||
while let Some(additional_offset) = snippet[offset..].find_uncommented(needle) {
|
|
||||||
offset += additional_offset + needle.len();
|
|
||||||
}
|
|
||||||
|
|
||||||
original.lo + BytePos(offset as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn span_before(&self, original: Span, needle: &str) -> BytePos {
|
|
||||||
let snippet = self.span_to_snippet(original).unwrap();
|
|
||||||
let offset = snippet.find_uncommented(needle).unwrap();
|
|
||||||
|
|
||||||
original.lo + BytePos(offset as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Computes the length of a string's last line, minus offset.
|
// Computes the length of a string's last line, minus offset.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extra_offset(text: &str, offset: Indent) -> usize {
|
pub fn extra_offset(text: &str, offset: Indent) -> usize {
|
||||||
|
@ -15,7 +15,8 @@ use syntax::parse::ParseSess;
|
|||||||
use strings::string_buffer::StringBuffer;
|
use strings::string_buffer::StringBuffer;
|
||||||
|
|
||||||
use Indent;
|
use Indent;
|
||||||
use utils::{self, CodeMapSpanUtils};
|
use utils;
|
||||||
|
use codemap::{LineRangeUtils, SpanUtils};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use comment::rewrite_comment;
|
use comment::rewrite_comment;
|
||||||
@ -42,6 +43,15 @@ pub struct FmtVisitor<'a> {
|
|||||||
|
|
||||||
impl<'a> FmtVisitor<'a> {
|
impl<'a> FmtVisitor<'a> {
|
||||||
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
|
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
|
||||||
|
debug!("visit_stmt: {:?} {:?}",
|
||||||
|
self.codemap.lookup_char_pos(stmt.span.lo),
|
||||||
|
self.codemap.lookup_char_pos(stmt.span.hi));
|
||||||
|
|
||||||
|
// FIXME(#434): Move this check to somewhere more central, eg Rewrite.
|
||||||
|
if !self.config.file_lines.contains(&self.codemap.lookup_line_range(stmt.span)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match stmt.node {
|
match stmt.node {
|
||||||
ast::StmtKind::Decl(ref decl, _) => {
|
ast::StmtKind::Decl(ref decl, _) => {
|
||||||
if let ast::DeclKind::Item(ref item) = decl.node {
|
if let ast::DeclKind::Item(ref item) = decl.node {
|
||||||
|
29
tests/source/file-lines-1.rs
Normal file
29
tests/source/file-lines-1.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-1.rs","range":[4,8]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
tests/source/file-lines-2.rs
Normal file
29
tests/source/file-lines-2.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-2.rs","range":[10,15]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
tests/source/file-lines-3.rs
Normal file
29
tests/source/file-lines-3.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-3.rs","range":[4,8]},{"file":"tests/source/file-lines-3.rs","range":[10,15]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
tests/source/file-lines-4.rs
Normal file
30
tests/source/file-lines-4.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// rustfmt-file_lines: []
|
||||||
|
// (Test that nothing is formatted if an empty array is specified.)
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
tests/target/file-lines-1.rs
Normal file
30
tests/target/file-lines-1.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-1.rs","range":[4,8]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call()
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
tests/target/file-lines-2.rs
Normal file
24
tests/target/file-lines-2.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-2.rs","range":[10,15]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond { val1 } else { val2 }.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
tests/target/file-lines-3.rs
Normal file
25
tests/target/file-lines-3.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// rustfmt-file_lines: [{"file":"tests/source/file-lines-3.rs","range":[4,8]},{"file":"tests/source/file-lines-3.rs","range":[10,15]}]
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call()
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
let y = if cond { val1 } else { val2 }.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
tests/target/file-lines-4.rs
Normal file
30
tests/target/file-lines-4.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// rustfmt-file_lines: []
|
||||||
|
// (Test that nothing is formatted if an empty array is specified.)
|
||||||
|
|
||||||
|
fn floaters() {
|
||||||
|
let x = Foo {
|
||||||
|
field1: val1,
|
||||||
|
field2: val2,
|
||||||
|
}
|
||||||
|
.method_call().method_call();
|
||||||
|
|
||||||
|
let y = if cond {
|
||||||
|
val1
|
||||||
|
} else {
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
.method_call();
|
||||||
|
|
||||||
|
{
|
||||||
|
match x {
|
||||||
|
PushParam => {
|
||||||
|
// params are 1-indexed
|
||||||
|
stack.push(mparams[match cur.to_digit(10) {
|
||||||
|
Some(d) => d as usize - 1,
|
||||||
|
None => return Err("bad param number".to_owned()),
|
||||||
|
}]
|
||||||
|
.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user