Add reorder_extern_crates and reorder_extern_crates_in_group config options

This commit is contained in:
topecongiro 2017-08-09 00:16:18 +09:00
parent b1b2dc8e0a
commit 7bf9aa25be
3 changed files with 68 additions and 29 deletions

View file

@ -558,6 +558,8 @@ create_config! {
exceeds `chain_one_line_max`"; exceeds `chain_one_line_max`";
imports_indent: IndentStyle, IndentStyle::Visual, "Indent of imports"; imports_indent: IndentStyle, IndentStyle::Visual, "Indent of imports";
imports_layout: ListTactic, ListTactic::Mixed, "Item layout inside a import block"; imports_layout: ListTactic, ListTactic::Mixed, "Item layout inside a import block";
reorder_extern_crates: bool, true, "Reorder extern crate statements alphabetically";
reorder_extern_crates_in_group: bool, true, "Reorder extern crate statements in group";
reorder_imports: bool, false, "Reorder import statements alphabetically"; reorder_imports: bool, false, "Reorder import statements alphabetically";
reorder_imports_in_group: bool, false, "Reorder import statements in group"; reorder_imports_in_group: bool, false, "Reorder import statements in group";
reorder_imported_names: bool, true, reorder_imported_names: bool, true,

View file

@ -113,11 +113,14 @@ fn compare_view_paths(a: &ast::ViewPath_, b: &ast::ViewPath_) -> Ordering {
} }
} }
fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> { fn compare_use_items(context: &RewriteContext, a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
match (&a.node, &b.node) { match (&a.node, &b.node) {
(&ast::ItemKind::Use(ref a_vp), &ast::ItemKind::Use(ref b_vp)) => { (&ast::ItemKind::Use(ref a_vp), &ast::ItemKind::Use(ref b_vp)) => {
Some(compare_view_paths(&a_vp.node, &b_vp.node)) Some(compare_view_paths(&a_vp.node, &b_vp.node))
} }
(&ast::ItemKind::ExternCrate(..), &ast::ItemKind::ExternCrate(..)) => {
Some(context.snippet(a.span).cmp(&context.snippet(b.span)))
}
_ => None, _ => None,
} }
} }
@ -214,7 +217,9 @@ impl<'a> FmtVisitor<'a> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let pos_after_last_use_item = last_pos_of_prev_use_item; let pos_after_last_use_item = last_pos_of_prev_use_item;
// Order the imports by view-path & other import path properties // Order the imports by view-path & other import path properties
ordered_use_items.sort_by(|a, b| compare_use_items(a.0, b.0).unwrap()); ordered_use_items.sort_by(|a, b| {
compare_use_items(&self.get_context(), a.0, b.0).unwrap()
});
// First, output the span before the first import // First, output the span before the first import
let prev_span_str = self.snippet(utils::mk_sp(self.last_pos, pos_before_first_use_item)); let prev_span_str = self.snippet(utils::mk_sp(self.last_pos, pos_before_first_use_item));
// Look for purely trailing space at the start of the prefix snippet before a linefeed, or // Look for purely trailing space at the start of the prefix snippet before a linefeed, or

View file

@ -36,6 +36,13 @@ fn is_use_item(item: &ast::Item) -> bool {
} }
} }
fn is_extern_crate(item: &ast::Item) -> bool {
match item.node {
ast::ItemKind::ExternCrate(..) => true,
_ => false,
}
}
pub struct FmtVisitor<'a> { pub struct FmtVisitor<'a> {
pub parse_session: &'a ParseSess, pub parse_session: &'a ParseSess,
pub codemap: &'a CodeMap, pub codemap: &'a CodeMap,
@ -627,19 +634,20 @@ impl<'a> FmtVisitor<'a> {
false false
} }
fn walk_mod_items(&mut self, m: &ast::Mod) { fn reorder_items<F>(
let mut items_left: &[ptr::P<ast::Item>] = &m.items; &mut self,
while !items_left.is_empty() { items_left: &[ptr::P<ast::Item>],
// If the next item is a `use` declaration, then extract it and any subsequent `use`s is_item: &F,
// to be potentially reordered within `format_imports`. Otherwise, just format the in_group: bool,
// next item for output. ) -> usize
if self.config.reorder_imports() && is_use_item(&*items_left[0]) { where
let reorder_imports_in_group = self.config.reorder_imports_in_group(); F: Fn(&ast::Item) -> bool,
{
let mut last = self.codemap.lookup_line_range(items_left[0].span()); let mut last = self.codemap.lookup_line_range(items_left[0].span());
let use_item_length = items_left let item_length = items_left
.iter() .iter()
.take_while(|ppi| { .take_while(|ppi| {
is_use_item(&***ppi) && (!reorder_imports_in_group || { is_item(&***ppi) && (!in_group || {
let current = self.codemap.lookup_line_range(ppi.span()); let current = self.codemap.lookup_line_range(ppi.span());
let in_same_group = current.lo < last.hi + 2; let in_same_group = current.lo < last.hi + 2;
last = current; last = current;
@ -647,20 +655,44 @@ impl<'a> FmtVisitor<'a> {
}) })
}) })
.count(); .count();
let (use_items, rest) = items_left.split_at(use_item_length); let items = &items_left[..item_length];
let at_least_one_in_file_lines = use_items let at_least_one_in_file_lines = items
.iter() .iter()
.any(|item| !out_of_file_lines_range!(self, item.span)); .any(|item| !out_of_file_lines_range!(self, item.span));
if at_least_one_in_file_lines { if at_least_one_in_file_lines {
self.format_imports(use_items); self.format_imports(items);
} else { } else {
for item in use_items { for item in items {
self.push_rewrite(item.span, None); self.push_rewrite(item.span, None);
} }
} }
item_length
}
fn walk_mod_items(&mut self, m: &ast::Mod) {
let mut items_left: &[ptr::P<ast::Item>] = &m.items;
while !items_left.is_empty() {
// If the next item is a `use` declaration, then extract it and any subsequent `use`s
// to be potentially reordered within `format_imports`. Otherwise, just format the
// next item for output.
if self.config.reorder_imports() && is_use_item(&*items_left[0]) {
let used_items_len = self.reorder_items(
&items_left,
&is_use_item,
self.config.reorder_imports_in_group(),
);
let (_, rest) = items_left.split_at(used_items_len);
items_left = rest;
} else if self.config.reorder_extern_crates() && is_extern_crate(&*items_left[0]) {
let used_items_len = self.reorder_items(
&items_left,
&is_extern_crate,
self.config.reorder_extern_crates_in_group(),
);
let (_, rest) = items_left.split_at(used_items_len);
items_left = rest; items_left = rest;
} else { } else {
// `unwrap()` is safe here because we know `items_left` // `unwrap()` is safe here because we know `items_left`