Merge pull request #174 from marcusklaas/format-paths

Format paths
This commit is contained in:
Marcus Klaas de Vries 2015-08-16 22:59:03 +02:00
commit 68627522b0
14 changed files with 509 additions and 108 deletions

View file

@ -12,14 +12,14 @@ use rewrite::{Rewrite, RewriteContext};
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic};
use string::{StringFormat, rewrite_string};
use StructLitStyle;
use utils::{span_after, make_indent};
use utils::{span_after, make_indent, extra_offset};
use visitor::FmtVisitor;
use config::BlockIndentStyle;
use comment::{FindUncommented, rewrite_comment};
use types::rewrite_path;
use syntax::{ast, ptr};
use syntax::codemap::{Pos, Span, BytePos, mk_sp};
use syntax::print::pprust;
use syntax::visit::Visitor;
impl Rewrite for ast::Expr {
@ -99,6 +99,9 @@ impl Rewrite for ast::Expr {
width,
offset)
}
ast::Expr_::ExprPath(ref qself, ref path) => {
rewrite_path(context, qself.as_ref(), path, width, offset)
}
_ => context.codemap.span_to_snippet(self.span).ok()
}
}
@ -320,11 +323,7 @@ fn rewrite_pat_expr(context: &RewriteContext,
};
// Consider only the last line of the pat string.
let extra_offset = match result.rfind('\n') {
// 1 for newline character
Some(idx) => result.len() - idx - 1 - offset,
None => result.len()
};
let extra_offset = extra_offset(&result, offset);
// The expression may (partionally) fit on the current line.
if width > extra_offset + 1 {
@ -391,16 +390,19 @@ fn rewrite_call(context: &RewriteContext,
debug!("rewrite_call, width: {}, offset: {}", width, offset);
// TODO using byte lens instead of char lens (and probably all over the place too)
let callee_str = try_opt!(callee.rewrite(context, width, offset));
// 2 is for parens
let max_callee_width = try_opt!(width.checked_sub(2));
let callee_str = try_opt!(callee.rewrite(context, max_callee_width, offset));
debug!("rewrite_call, callee_str: `{}`", callee_str);
if args.len() == 0 {
return Some(format!("{}()", callee_str));
}
let extra_offset = extra_offset(&callee_str, offset);
// 2 is for parens.
let remaining_width = try_opt!(width.checked_sub(callee_str.len() + 2));
let offset = callee_str.len() + 1 + offset;
let remaining_width = try_opt!(width.checked_sub(extra_offset + 2));
let offset = offset + extra_offset + 1;
let block_indent = expr_block_indent(context, offset);
let inner_context = &RewriteContext { block_indent: block_indent, ..*context };
@ -425,7 +427,7 @@ fn rewrite_call(context: &RewriteContext,
indent: offset,
h_width: remaining_width,
v_width: remaining_width,
ends_with_newline: true,
ends_with_newline: false,
};
Some(format!("{}({})", callee_str, write_list(&items, &fmt)))
@ -468,7 +470,9 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
Base(&'a ast::Expr),
}
let path_str = pprust::path_to_string(path);
// 2 = " {".len()
let path_str = try_opt!(path.rewrite(context, width - 2, offset));
// Foo { a: Foo } - indent is +3, width is -5.
let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0);
let (indent, v_budget) = match context.config.struct_lit_style {
@ -537,7 +541,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
indent: indent,
h_width: h_budget,
v_width: v_budget,
ends_with_newline: true,
ends_with_newline: false,
};
let fields_str = write_list(&items, &fmt);
@ -601,7 +605,7 @@ fn rewrite_tuple_lit(context: &RewriteContext,
indent: indent,
h_width: width - 2,
v_width: width - 2,
ends_with_newline: true,
ends_with_newline: false,
};
Some(format!("({})", write_list(&items, &fmt)))

View file

@ -11,11 +11,9 @@
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
use utils::span_after;
use rewrite::{Rewrite, RewriteContext};
use config::Config;
use syntax::ast;
use syntax::print::pprust;
use syntax::codemap::{CodeMap, Span};
use syntax::codemap::Span;
// TODO (some day) remove unused imports, expand globs, compress many single imports into a list import
@ -29,20 +27,21 @@ impl Rewrite for ast::ViewPath {
path,
path_list,
self.span,
context.codemap,
context.config).unwrap_or("".to_owned()))
context).unwrap_or("".to_owned()))
}
ast::ViewPath_::ViewPathGlob(_) => {
// FIXME convert to list?
None
}
ast::ViewPath_::ViewPathSimple(ident, ref path) => {
let path_str = pprust::path_to_string(path);
let ident_str = ident.to_string();
// 4 = " as ".len()
let path_str = try_opt!(path.rewrite(context, width - ident_str.len() - 4, offset));
Some(if path.segments.last().unwrap().identifier == ident {
path_str
} else {
format!("{} as {}", path_str, ident)
format!("{} as {}", path_str, ident_str)
})
}
}
@ -74,10 +73,10 @@ pub fn rewrite_use_list(width: usize,
path: &ast::Path,
path_list: &[ast::PathListItem],
span: Span,
codemap: &CodeMap,
config: &Config)
context: &RewriteContext)
-> Option<String> {
let path_str = pprust::path_to_string(path);
// 1 = {}
let path_str = try_opt!(path.rewrite(context, width - 1, offset));
match path_list.len() {
0 => return None,
@ -106,10 +105,10 @@ pub fn rewrite_use_list(width: usize,
// available
// (loose 1 column (";"))
v_width: remaining_width,
ends_with_newline: true,
ends_with_newline: false,
};
let mut items = itemize_list(codemap,
let mut items = itemize_list(context.codemap,
vec![ListItem::from_str("")], /* Dummy value, explanation
* below */
path_list.iter(),
@ -125,7 +124,7 @@ pub fn rewrite_use_list(width: usize,
"self".to_owned()
}
},
span_after(span, "{", codemap),
span_after(span, "{", context.codemap),
span.hi);
// We prefixed the item list with a dummy value so that we can
@ -140,7 +139,7 @@ pub fn rewrite_use_list(width: usize,
1
};
if config.reorder_imports {
if context.config.reorder_imports {
items[1..].sort_by(|a, b| a.item.cmp(&b.item));
}

View file

@ -16,6 +16,8 @@ use utils::{format_mutability, format_visibility, make_indent, contains_skip, sp
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
use comment::FindUncommented;
use visitor::FmtVisitor;
use rewrite::Rewrite;
use config::Config;
use syntax::{ast, abi};
use syntax::codemap::{self, Span, BytePos};
@ -215,6 +217,7 @@ impl<'a> FmtVisitor<'a> {
// Where clause.
result.push_str(&self.rewrite_where_clause(where_clause,
self.config,
indent,
span.hi));
@ -281,7 +284,7 @@ impl<'a> FmtVisitor<'a> {
indent: arg_indent,
h_width: one_line_budget,
v_width: multi_line_budget,
ends_with_newline: true,
ends_with_newline: false,
};
write_list(&arg_items, &fmt)
@ -429,7 +432,7 @@ impl<'a> FmtVisitor<'a> {
indent: indent,
h_width: budget,
v_width: budget,
ends_with_newline: false,
ends_with_newline: true,
};
result.push_str(&write_list(&items, &fmt));
result.push(')');
@ -557,7 +560,7 @@ impl<'a> FmtVisitor<'a> {
indent: offset + self.config.tab_spaces,
h_width: self.config.max_width,
v_width: budget,
ends_with_newline: false,
ends_with_newline: true,
};
result.push_str(&write_list(&items, &fmt));
@ -608,6 +611,7 @@ impl<'a> FmtVisitor<'a> {
if generics.where_clause.predicates.len() > 0 || result.contains('\n') {
result.push_str(&self.rewrite_where_clause(&generics.where_clause,
self.config,
self.block_indent,
span.hi));
result.push_str(&make_indent(self.block_indent));
@ -664,8 +668,15 @@ impl<'a> FmtVisitor<'a> {
result.push('<');
// Strings for the generics.
let lt_strs = lifetimes.iter().map(|l| self.rewrite_lifetime_def(l));
let ty_strs = tys.iter().map(|ty| self.rewrite_ty_param(ty));
// 1 = <
let context = self.get_context();
// FIXME: don't unwrap
let lt_strs = lifetimes.iter().map(|lt| {
lt.rewrite(&context, budget, offset + 1).unwrap()
});
let ty_strs = tys.iter().map(|ty_param| {
ty_param.rewrite(&context, budget, offset + 1).unwrap()
});
// Extract comments between generics.
let lt_spans = lifetimes.iter().map(|l| {
@ -700,7 +711,7 @@ impl<'a> FmtVisitor<'a> {
indent: offset + 1,
h_width: budget,
v_width: budget,
ends_with_newline: true,
ends_with_newline: false,
};
result.push_str(&write_list(&items, &fmt));
@ -711,6 +722,7 @@ impl<'a> FmtVisitor<'a> {
fn rewrite_where_clause(&self,
where_clause: &ast::WhereClause,
config: &Config,
indent: usize,
span_end: BytePos)
-> String {
@ -720,9 +732,13 @@ impl<'a> FmtVisitor<'a> {
}
result.push('\n');
result.push_str(&make_indent(indent + 4));
result.push_str(&make_indent(indent + config.tab_spaces));
result.push_str("where ");
let context = self.get_context();
// 6 = "where ".len()
let offset = indent + config.tab_spaces + 6;
let budget = self.config.ideal_width + self.config.leeway - offset;
let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
let items = itemize_list(self.codemap,
Vec::new(),
@ -731,19 +747,21 @@ impl<'a> FmtVisitor<'a> {
"{",
|pred| span_for_where_pred(pred).lo,
|pred| span_for_where_pred(pred).hi,
|pred| self.rewrite_pred(pred),
// FIXME: we should handle failure better
// this will be taken care of when write_list
// takes Rewrite object: see issue #133
|pred| pred.rewrite(&context, budget, offset).unwrap(),
span_start,
span_end);
let budget = self.config.ideal_width + self.config.leeway - indent - 10;
let fmt = ListFormatting {
tactic: ListTactic::Vertical,
separator: ",",
trailing_separator: SeparatorTactic::Never,
indent: indent + 10,
indent: offset,
h_width: budget,
v_width: budget,
ends_with_newline: true,
ends_with_newline: false,
};
result.push_str(&write_list(&items, &fmt));

View file

@ -211,7 +211,7 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> St
let offset = formatting.indent + item_width + 1;
let comment = item.post_comment.as_ref().unwrap();
// Use block-style only for the last item or multiline comments.
let block_style = formatting.ends_with_newline && last ||
let block_style = !formatting.ends_with_newline && last ||
comment.trim().contains('\n') || comment.trim().len() > width;
let formatted_comment = rewrite_comment(comment, block_style, width, offset);

View file

@ -8,33 +8,311 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use visitor::FmtVisitor;
use std::fmt;
use syntax::ast;
use syntax::print::pprust;
use syntax::codemap::{self, Span, BytePos, CodeMap};
impl<'a> FmtVisitor<'a> {
pub fn rewrite_pred(&self, predicate: &ast::WherePredicate) -> String {
// TODO dead spans
use lists::{itemize_list, write_list, ListTactic, SeparatorTactic, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use utils::{extra_offset, span_after};
impl Rewrite for ast::Path {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
rewrite_path(context, None, self, width, offset)
}
}
// Does not wrap on simple segments.
pub fn rewrite_path(context: &RewriteContext,
qself: Option<&ast::QSelf>,
path: &ast::Path,
width: usize,
offset: usize)
-> Option<String> {
let skip_count = qself.map(|x| x.position).unwrap_or(0);
let mut result = if path.global {
"::".to_owned()
} else {
String::new()
};
let mut span_lo = path.span.lo;
if let Some(ref qself) = qself {
result.push('<');
result.push_str(&pprust::ty_to_string(&qself.ty));
result.push_str(" as ");
let extra_offset = extra_offset(&result, offset);
// 3 = ">::".len()
let budget = try_opt!(width.checked_sub(extra_offset)) - 3;
result = try_opt!(rewrite_path_segments(result,
path.segments.iter().take(skip_count),
span_lo,
path.span.hi,
context,
budget,
offset + extra_offset));
result.push_str(">::");
span_lo = qself.ty.span.hi + BytePos(1);
}
let extra_offset = extra_offset(&result, offset);
let budget = try_opt!(width.checked_sub(extra_offset));
rewrite_path_segments(result,
path.segments.iter().skip(skip_count),
span_lo,
path.span.hi,
context,
budget,
offset + extra_offset)
}
fn rewrite_path_segments<'a, I>(mut buffer: String,
iter: I,
mut span_lo: BytePos,
span_hi: BytePos,
context: &RewriteContext,
width: usize,
offset: usize)
-> Option<String>
where I: Iterator<Item = &'a ast::PathSegment>
{
let mut first = true;
for segment in iter {
let extra_offset = extra_offset(&buffer, offset);
let remaining_width = try_opt!(width.checked_sub(extra_offset));
let new_offset = offset + extra_offset;
let segment_string = try_opt!(rewrite_segment(segment,
&mut span_lo,
span_hi,
context,
remaining_width,
new_offset));
if first {
first = false;
} else {
buffer.push_str("::");
}
buffer.push_str(&segment_string);
}
Some(buffer)
}
enum SegmentParam<'a> {
LifeTime(&'a ast::Lifetime),
Type(&'a ast::Ty),
Binding(&'a ast::TypeBinding),
}
impl<'a> SegmentParam<'a> {
fn get_span(&self) -> Span {
match *self {
SegmentParam::LifeTime(ref lt) => lt.span,
SegmentParam::Type(ref ty) => ty.span,
SegmentParam::Binding(ref binding) => binding.span,
}
}
}
impl<'a> fmt::Display for SegmentParam<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SegmentParam::LifeTime(ref lt) => {
write!(f, "{}", pprust::lifetime_to_string(lt))
}
SegmentParam::Type(ref ty) => {
write!(f, "{}", pprust::ty_to_string(ty))
}
SegmentParam::Binding(ref binding) => {
write!(f, "{} = {}", binding.ident, pprust::ty_to_string(&*binding.ty))
}
}
}
}
// This is a dirty hack to determine if we're in an expression or not. Generic
// parameters are passed differently in expressions and items. We'd declare
// a struct with Foo<A, B>, but call its functions with Foo::<A, B>::f().
// We'd really rather not do this, but there doesn't seem to be an alternative
// at this point.
// FIXME: fails with spans containing comments with the characters < or :
fn get_path_separator(codemap: &CodeMap,
path_start: BytePos,
segment_start: BytePos)
-> &'static str {
let span = codemap::mk_sp(path_start, segment_start);
let snippet = codemap.span_to_snippet(span).unwrap();
for c in snippet.chars().rev() {
if c == ':' {
return "::"
} else if c.is_whitespace() || c == '<' {
continue;
} else {
return "";
}
}
unreachable!();
}
// Formats a path segment. There are some hacks involved to correctly determine
// the segment's associated span since it's not part of the AST.
//
// The span_lo is assumed to be greater than the end of any previous segment's
// parameters and lesser or equal than the start of current segment.
//
// span_hi is assumed equal to the end of the entire path.
//
// When the segment contains a positive number of parameters, we update span_lo
// so that invariants described above will hold for the next segment.
fn rewrite_segment(segment: &ast::PathSegment,
span_lo: &mut BytePos,
span_hi: BytePos,
context: &RewriteContext,
width: usize,
offset: usize)
-> Option<String> {
let ident_len = segment.identifier.to_string().len();
let width = try_opt!(width.checked_sub(ident_len));
let offset = offset + ident_len;
let params = match segment.parameters {
ast::PathParameters::AngleBracketedParameters(ref data) if data.lifetimes.len() > 0 ||
data.types.len() > 0 ||
data.bindings.len() > 0 => {
let param_list = data.lifetimes.iter()
.map(SegmentParam::LifeTime)
.chain(data.types.iter()
.map(|x| SegmentParam::Type(&*x)))
.chain(data.bindings.iter()
.map(|x| SegmentParam::Binding(&*x)))
.collect::<Vec<_>>();
let next_span_lo = param_list.last().unwrap().get_span().hi + BytePos(1);
let list_lo = span_after(codemap::mk_sp(*span_lo, span_hi), "<", context.codemap);
let separator = get_path_separator(context.codemap, *span_lo, list_lo);
let items = itemize_list(context.codemap,
Vec::new(),
param_list.into_iter(),
",",
">",
|param| param.get_span().lo,
|param| param.get_span().hi,
ToString::to_string,
list_lo,
span_hi);
// 1 for <
let extra_offset = 1 + separator.len();
// 1 for >
let list_width = try_opt!(width.checked_sub(extra_offset + 1));
let fmt = ListFormatting {
tactic: ListTactic::HorizontalVertical,
separator: ",",
trailing_separator: SeparatorTactic::Never,
indent: offset + extra_offset,
h_width: list_width,
v_width: list_width,
ends_with_newline: false,
};
// update pos
*span_lo = next_span_lo;
format!("{}<{}>", separator, write_list(&items, &fmt))
}
ast::PathParameters::ParenthesizedParameters(ref data) => {
let output = match data.output {
Some(ref ty) => format!(" -> {}", pprust::ty_to_string(&*ty)),
None => String::new()
};
let list_lo = span_after(codemap::mk_sp(*span_lo, span_hi), "(", context.codemap);
let items = itemize_list(context.codemap,
Vec::new(),
data.inputs.iter(),
",",
")",
|ty| ty.span.lo,
|ty| ty.span.hi,
|ty| pprust::ty_to_string(ty),
list_lo,
span_hi);
// 2 for ()
let budget = try_opt!(width.checked_sub(output.len() + 2));
let fmt = ListFormatting {
tactic: ListTactic::HorizontalVertical,
separator: ",",
trailing_separator: SeparatorTactic::Never,
// 1 for (
indent: offset + 1,
h_width: budget,
v_width: budget,
ends_with_newline: false,
};
// update pos
*span_lo = data.inputs.last().unwrap().span.hi + BytePos(1);
format!("({}){}", write_list(&items, &fmt), output)
}
_ => String::new()
};
Some(format!("{}{}", segment.identifier, params))
}
impl Rewrite for ast::WherePredicate {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
// TODO dead spans?
// TODO assumes we'll always fit on one line...
match predicate {
Some(match self {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bound_lifetimes,
ref bounded_ty,
ref bounds,
..}) => {
if bound_lifetimes.len() > 0 {
format!("for<{}> {}: {}",
bound_lifetimes.iter().map(|l| self.rewrite_lifetime_def(l))
.collect::<Vec<_>>().join(", "),
pprust::ty_to_string(bounded_ty),
bounds.iter().map(|b| self.rewrite_ty_bound(b))
.collect::<Vec<_>>().join(" + "))
let lifetime_str = bound_lifetimes.iter().map(|lt| {
lt.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(", ");
let type_str = pprust::ty_to_string(bounded_ty);
// 8 = "for<> : ".len()
let used_width = lifetime_str.len() + type_str.len() + 8;
let bounds_str = bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context,
width - used_width,
offset + used_width)
.unwrap()
}).collect::<Vec<_>>().join(" + ");
format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str)
} else {
format!("{}: {}",
pprust::ty_to_string(bounded_ty),
bounds.iter().map(|b| self.rewrite_ty_bound(b))
.collect::<Vec<_>>().join(" + "))
let type_str = pprust::ty_to_string(bounded_ty);
// 2 = ": ".len()
let used_width = type_str.len() + 2;
let bounds_str = bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context,
width - used_width,
offset + used_width)
.unwrap()
}).collect::<Vec<_>>().join(" + ");
format!("{}: {}", type_str, bounds_str)
}
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
@ -42,65 +320,91 @@ impl<'a> FmtVisitor<'a> {
..}) => {
format!("{}: {}",
pprust::lifetime_to_string(lifetime),
bounds.iter().map(|l| pprust::lifetime_to_string(l))
.collect::<Vec<_>>().join(" + "))
bounds.iter().map(pprust::lifetime_to_string)
.collect::<Vec<_>>().join(" + "))
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
format!("{} = {}", pprust::path_to_string(path), pprust::ty_to_string(ty))
let ty_str = pprust::ty_to_string(ty);
// 3 = " = ".len()
let used_width = 3 + ty_str.len();
let path_str = try_opt!(path.rewrite(context,
width - used_width,
offset + used_width));
format!("{} = {}", path_str, ty_str)
}
})
}
}
impl Rewrite for ast::LifetimeDef {
fn rewrite(&self, _: &RewriteContext, _: usize, _: usize) -> Option<String> {
if self.bounds.len() == 0 {
Some(pprust::lifetime_to_string(&self.lifetime))
} else {
Some(format!("{}: {}",
pprust::lifetime_to_string(&self.lifetime),
self.bounds.iter().map(pprust::lifetime_to_string)
.collect::<Vec<_>>().join(" + ")))
}
}
}
pub fn rewrite_lifetime_def(&self, lifetime: &ast::LifetimeDef) -> String {
if lifetime.bounds.len() == 0 {
return pprust::lifetime_to_string(&lifetime.lifetime);
}
format!("{}: {}",
pprust::lifetime_to_string(&lifetime.lifetime),
lifetime.bounds.iter().map(|l| pprust::lifetime_to_string(l))
.collect::<Vec<_>>().join(" + "))
}
pub fn rewrite_ty_bound(&self, bound: &ast::TyParamBound) -> String {
match *bound {
impl Rewrite for ast::TyParamBound {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
match *self {
ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
self.rewrite_poly_trait_ref(tref)
tref.rewrite(context, width, offset)
}
ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
format!("?{}", self.rewrite_poly_trait_ref(tref))
Some(format!("?{}", try_opt!(tref.rewrite(context, width - 1, offset + 1))))
}
ast::TyParamBound::RegionTyParamBound(ref l) => {
pprust::lifetime_to_string(l)
Some(pprust::lifetime_to_string(l))
}
}
}
}
pub fn rewrite_ty_param(&self, ty_param: &ast::TyParam) -> String {
// FIXME: this assumes everything will fit on one line
impl Rewrite for ast::TyParam {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
let mut result = String::with_capacity(128);
result.push_str(&ty_param.ident.to_string());
if ty_param.bounds.len() > 0 {
result.push_str(&self.ident.to_string());
if self.bounds.len() > 0 {
result.push_str(": ");
result.push_str(&ty_param.bounds.iter().map(|b| self.rewrite_ty_bound(b))
.collect::<Vec<_>>().join(" + "));
let bounds = self.bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(" + ");
result.push_str(&bounds);
}
if let Some(ref def) = ty_param.default {
if let Some(ref def) = self.default {
result.push_str(" = ");
result.push_str(&pprust::ty_to_string(&def));
}
result
Some(result)
}
}
fn rewrite_poly_trait_ref(&self, t: &ast::PolyTraitRef) -> String {
if t.bound_lifetimes.len() > 0 {
format!("for<{}> {}",
t.bound_lifetimes.iter().map(|l| self.rewrite_lifetime_def(l))
.collect::<Vec<_>>().join(", "),
pprust::path_to_string(&t.trait_ref.path))
// FIXME: this assumes everything will fit on one line
impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
if self.bound_lifetimes.len() > 0 {
let lifetime_str = self.bound_lifetimes.iter().map(|lt| {
lt.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(", ");
// 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6;
let max_path_width = try_opt!(width.checked_sub(extra_offset));
let path_str = try_opt!(self.trait_ref.path.rewrite(context,
max_path_width,
offset + extra_offset));
Some(format!("for<{}> {}", lifetime_str, path_str))
} else {
pprust::path_to_string(&t.trait_ref.path)
self.trait_ref.path.rewrite(context, width, offset)
}
}
}

View file

@ -15,6 +15,16 @@ use comment::FindUncommented;
use SKIP_ANNOTATION;
// Computes the length of a string's last line, minus offset.
#[inline]
pub fn extra_offset(text: &str, offset: usize) -> usize {
match text.rfind('\n') {
// 1 for newline character
Some(idx) => text.len() - idx - 1 - offset,
None => text.len()
}
}
#[inline]
pub fn span_after(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
let snippet = codemap.span_to_snippet(original).unwrap();

View file

@ -33,13 +33,9 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
self.codemap.lookup_char_pos(ex.span.lo),
self.codemap.lookup_char_pos(ex.span.hi));
self.format_missing(ex.span.lo);
let offset = self.buffer.cur_offset();
let context = RewriteContext {
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent,
};
let rewrite = ex.rewrite(&context, self.config.max_width - offset, offset);
let rewrite = ex.rewrite(&self.get_context(), self.config.max_width - offset, offset);
if let Some(new_str) = rewrite {
self.buffer.push_str(&new_str);
@ -372,4 +368,12 @@ impl<'a> FmtVisitor<'a> {
}
}
}
pub fn get_context(&self) -> RewriteContext {
RewriteContext {
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent,
}
}
}

View file

@ -9,3 +9,11 @@ y: World
) {
simple(/* does this preserve comments now? */ 42, NoWay)
}
fn generic<T>(arg: T) -> &SomeType
where T: Fn(// First arg
A,
// Second argument
B, C, D, /* pre comment */ E /* last comment */) -> &SomeType {
arg(a, b, c, d, e)
}

22
tests/source/paths.rs Normal file
View file

@ -0,0 +1,22 @@
fn main() {
// FIXME(#133): the list rewrite should fail and force a different format
let constellation_chan = Constellation::<layout::layout_task::LayoutTask, script::script_task::ScriptTask> ::start(
compositor_proxy,
resource_task,
image_cache_task,font_cache_task,
time_profiler_chan,
mem_profiler_chan,
devtools_chan,
storage_task,
supports_clipboard
);
Quux::<ParamOne, // Comment 1
ParamTwo, // Comment 2
>::some_func();
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::quux();
}
fn op(foo: Bar, key : &[u8], upd : Fn(Option<&memcache::Item> , Baz ) -> Result) -> MapResult {}

View file

@ -48,3 +48,8 @@ fn matcher() {
},
};
}
fn issue177() {
struct Foo<T> { memb: T }
let foo = Foo::<i64> { memb: 10 };
}

View file

@ -14,3 +14,16 @@ fn weird_comment(// /*/ double level */ comment
42,
NoWay)
}
fn generic<T>(arg: T) -> &SomeType
where T: Fn(// First arg
A,
// Second argument
B,
C,
D,
// pre comment
E /* last comment */) -> &SomeType
{
arg(a, b, c, d, e)
}

View file

@ -79,17 +79,3 @@ fn main() {
let _ = function(move || 5);
let _ = move || 42;
}
fn servo() {
let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
script::script_task::ScriptTask>::start(
compositor_proxy,
resource_task,
image_cache_task,
font_cache_task,
time_profiler_chan,
mem_profiler_chan,
devtools_chan,
storage_task,
supports_clipboard);
}

21
tests/target/paths.rs Normal file
View file

@ -0,0 +1,21 @@
fn main() {
// FIXME(#133): the list rewrite should fail and force a different format
let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
script::script_task::ScriptTask>::start(compositor_proxy,
resource_task,
image_cache_task,
font_cache_task,
time_profiler_chan,
mem_profiler_chan,
devtools_chan,
storage_task,
supports_clipboard);
Quux::<ParamOne /* Comment 1 */, ParamTwo /* Comment 2 */>::some_func();
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::quux();
}
fn op(foo: Bar, key: &[u8], upd: Fn(Option<&memcache::Item>, Baz) -> Result) -> MapResult {
}

View file

@ -64,3 +64,10 @@ fn matcher() {
},
};
}
fn issue177() {
struct Foo<T> {
memb: T,
}
let foo = Foo::<i64> { memb: 10 };
}