1
Fork 0

Add failure mode to write_list

This commit is contained in:
Marcus Klaas 2015-09-04 18:09:05 +02:00
parent 2a61a989d5
commit d05a41c773
12 changed files with 294 additions and 212 deletions

View file

@ -8,11 +8,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::cmp::Ordering;
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};
use string::{StringFormat, rewrite_string}; use string::{StringFormat, rewrite_string};
use StructLitStyle; use StructLitStyle;
use utils::{span_after, make_indent, extra_offset, first_line_width, last_line_width}; use utils::{span_after, make_indent, extra_offset, first_line_width, last_line_width, wrap_str};
use visitor::FmtVisitor; use visitor::FmtVisitor;
use config::BlockIndentStyle; use config::BlockIndentStyle;
use comment::{FindUncommented, rewrite_comment, contains_comment}; use comment::{FindUncommented, rewrite_comment, contains_comment};
@ -134,37 +136,9 @@ impl Rewrite for ast::Expr {
ast::Expr_::ExprClosure(capture, ref fn_decl, ref body) => { ast::Expr_::ExprClosure(capture, ref fn_decl, ref body) => {
rewrite_closure(capture, fn_decl, body, self.span, context, width, offset) rewrite_closure(capture, fn_decl, body, self.span, context, width, offset)
} }
_ => {
// We do not format these expressions yet, but they should still // We do not format these expressions yet, but they should still
// satisfy our width restrictions. // satisfy our width restrictions.
let snippet = context.snippet(self.span); _ => wrap_str(context.snippet(self.span), context.config.max_width, width, offset),
{
let mut lines = snippet.lines();
// The caller of this function has already placed `offset`
// characters on the first line.
let first_line_max_len = try_opt!(context.config.max_width.checked_sub(offset));
if lines.next().unwrap().len() > first_line_max_len {
return None;
}
// The other lines must fit within the maximum width.
if lines.find(|line| line.len() > context.config.max_width).is_some() {
return None;
}
// `width` is the maximum length of the last line, excluding
// indentation.
// A special check for the last line, since the caller may
// place trailing characters on this line.
if snippet.lines().rev().next().unwrap().len() > offset + width {
return None;
}
}
Some(snippet)
}
} }
} }
} }
@ -202,7 +176,8 @@ fn rewrite_closure(capture: ast::CaptureClause,
body.span.lo); body.span.lo);
let fmt = ListFormatting::for_fn(argument_budget, argument_offset); let fmt = ListFormatting::for_fn(argument_budget, argument_offset);
let prefix = format!("{}|{}|", mover, write_list(&arg_items.collect::<Vec<_>>(), &fmt)); let list_str = try_opt!(write_list(&arg_items.collect::<Vec<_>>(), &fmt));
let prefix = format!("{}|{}|", mover, list_str);
let closure_indent = closure_indent(context, offset); let closure_indent = closure_indent(context, offset);
// Try to format closure body as a single line expression without braces. // Try to format closure body as a single line expression without braces.
@ -869,19 +844,58 @@ fn rewrite_call(context: &RewriteContext,
-> Option<String> { -> Option<String> {
debug!("rewrite_call, width: {}, offset: {}", width, offset); debug!("rewrite_call, width: {}, offset: {}", width, offset);
// FIXME using byte lens instead of char lens (and probably all over the place too)
// 2 is for parens // 2 is for parens
let max_callee_width = try_opt!(width.checked_sub(2)); let mut hi = try_opt!(width.checked_sub(2)) * 2;
let callee_str = try_opt!(callee.rewrite(context, max_callee_width, offset)); let mut lo = 0;
debug!("rewrite_call, callee_str: `{}`", callee_str); let mut tries = 0;
if args.is_empty() { // Binary search for the best split between callee and arguments.
return Some(format!("{}()", callee_str)); loop {
let middle = (lo + hi) / 2;
match rewrite_call_inner(context, callee, middle, args, span, width, offset) {
_ if tries > 10 => return None,
Ok(result) => return Some(result),
Err(Ordering::Less) => {
lo = middle;
tries += 1;
} }
Err(Ordering::Greater) => {
hi = middle;
tries += 1;
}
_ => unreachable!(),
}
}
}
fn rewrite_call_inner(context: &RewriteContext,
callee: &ast::Expr,
max_callee_width: usize,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
-> Result<String, Ordering> {
// FIXME using byte lens instead of char lens (and probably all over the place too)
let callee_str = match callee.rewrite(context, max_callee_width, offset) {
Some(string) => {
if !string.contains('\n') && string.len() > max_callee_width {
panic!("{:?} {}", string, max_callee_width);
} else {
string
}
}
None => return Err(Ordering::Less),
};
debug!("rewrite_call, callee_str: `{}`", callee_str);
let extra_offset = extra_offset(&callee_str, offset); let extra_offset = extra_offset(&callee_str, offset);
// 2 is for parens. // 2 is for parens.
let remaining_width = try_opt!(width.checked_sub(extra_offset + 2)); let remaining_width = match width.checked_sub(extra_offset + 2) {
Some(str) => str,
None => return Err(Ordering::Greater),
};
let offset = offset + extra_offset + 1; let offset = offset + extra_offset + 1;
let inner_indent = expr_indent(context, offset); let inner_indent = expr_indent(context, offset);
let inner_context = context.overflow_context(inner_indent - context.block_indent); let inner_context = context.overflow_context(inner_indent - context.block_indent);
@ -900,8 +914,12 @@ fn rewrite_call(context: &RewriteContext,
span.hi); span.hi);
let fmt = ListFormatting::for_fn(remaining_width, offset); let fmt = ListFormatting::for_fn(remaining_width, offset);
let list_str = match write_list(&items.collect::<Vec<_>>(), &fmt) {
Some(str) => str,
None => return Err(Ordering::Greater),
};
Some(format!("{}({})", callee_str, write_list(&items.collect::<Vec<_>>(), &fmt))) Ok(format!("{}({})", callee_str, list_str))
} }
macro_rules! block_indent_helper { macro_rules! block_indent_helper {
@ -1024,7 +1042,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
v_width: v_budget, v_width: v_budget,
ends_with_newline: false, ends_with_newline: false,
}; };
let fields_str = write_list(&items.collect::<Vec<_>>(), &fmt); let fields_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
match context.config.struct_lit_style { match context.config.struct_lit_style {
StructLitStyle::Block if fields_str.contains('\n') => { StructLitStyle::Block if fields_str.contains('\n') => {
@ -1046,7 +1064,8 @@ fn rewrite_field(context: &RewriteContext,
-> Option<String> { -> Option<String> {
let name = &field.ident.node.to_string(); let name = &field.ident.node.to_string();
let overhead = name.len() + 2; let overhead = name.len() + 2;
let expr = field.expr.rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead); let expr =
field.expr.rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead);
expr.map(|s| format!("{}: {}", name, s)) expr.map(|s| format!("{}: {}", name, s))
} }
@ -1080,8 +1099,9 @@ fn rewrite_tuple_lit(context: &RewriteContext,
let budget = try_opt!(width.checked_sub(2)); let budget = try_opt!(width.checked_sub(2));
let fmt = ListFormatting::for_fn(budget, indent); let fmt = ListFormatting::for_fn(budget, indent);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
Some(format!("({})", write_list(&items.collect::<Vec<_>>(), &fmt))) Some(format!("({})", list_str))
} }
fn rewrite_binary_op(context: &RewriteContext, fn rewrite_binary_op(context: &RewriteContext,
@ -1206,12 +1226,13 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
let new_offset = offset + context.config.tab_spaces; let new_offset = offset + context.config.tab_spaces;
result.push_str(&format!("\n{}", make_indent(new_offset))); result.push_str(&format!("\n{}", make_indent(new_offset)));
// FIXME: we probably should related max_width to width instead of config.max_width
// where is the 1 coming from anyway?
let max_width = try_opt!(context.config.max_width.checked_sub(new_offset + 1)); let max_width = try_opt!(context.config.max_width.checked_sub(new_offset + 1));
let rhs = try_opt!(ex.rewrite(&context.overflow_context(context.config.tab_spaces), let overflow_context = context.overflow_context(context.config.tab_spaces);
max_width, let rhs = ex.rewrite(&overflow_context, max_width, new_offset);
new_offset));
result.push_str(&rhs); result.push_str(&&try_opt!(rhs));
} }
} }

View file

@ -22,13 +22,11 @@ impl Rewrite for ast::ViewPath {
// Returns an empty string when the ViewPath is empty (like foo::bar::{}) // Returns an empty string when the ViewPath is empty (like foo::bar::{})
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> { fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
match self.node { match self.node {
ast::ViewPath_::ViewPathList(_, ref path_list) if path_list.is_empty() => {
Some(String::new())
}
ast::ViewPath_::ViewPathList(ref path, ref path_list) => { ast::ViewPath_::ViewPathList(ref path, ref path_list) => {
Some(rewrite_use_list(width, rewrite_use_list(width, offset, path, path_list, self.span, context)
offset,
path,
path_list,
self.span,
context).unwrap_or("".to_owned()))
} }
ast::ViewPath_::ViewPathGlob(_) => { ast::ViewPath_::ViewPathGlob(_) => {
// FIXME convert to list? // FIXME convert to list?
@ -67,8 +65,8 @@ fn rewrite_single_use_list(path_str: String, vpi: ast::PathListItem) -> String {
} }
} }
// Basically just pretty prints a multi-item import. // Pretty prints a multi-item import.
// Returns None when the import can be removed. // Assumes that path_list.len() > 0.
pub fn rewrite_use_list(width: usize, pub fn rewrite_use_list(width: usize,
offset: usize, offset: usize,
path: &ast::Path, path: &ast::Path,
@ -80,7 +78,7 @@ pub fn rewrite_use_list(width: usize,
let path_str = try_opt!(path.rewrite(context, width - 1, offset)); let path_str = try_opt!(path.rewrite(context, width - 1, offset));
match path_list.len() { match path_list.len() {
0 => return None, 0 => unreachable!(),
1 => return Some(rewrite_single_use_list(path_str, path_list[0])), 1 => return Some(rewrite_single_use_list(path_str, path_list[0])),
_ => (), _ => (),
} }
@ -149,12 +147,12 @@ pub fn rewrite_use_list(width: usize,
items[1..].sort_by(|a, b| a.item.cmp(&b.item)); items[1..].sort_by(|a, b| a.item.cmp(&b.item));
} }
let list = write_list(&items[first_index..], &fmt); let list_str = try_opt!(write_list(&items[first_index..], &fmt));
Some(if path_str.is_empty() { Some(if path_str.is_empty() {
format!("{{{}}}", list) format!("{{{}}}", list_str)
} else { } else {
format!("{}::{{{}}}", path_str, list) format!("{}::{{{}}}", path_str, list_str)
}) })
} }

View file

@ -99,10 +99,10 @@ impl<'a> FmtVisitor<'a> {
abi: &abi::Abi, abi: &abi::Abi,
vis: ast::Visibility, vis: ast::Visibility,
span: Span) span: Span)
-> String { -> Option<String> {
let mut newline_brace = self.newline_for_brace(&generics.where_clause); let mut newline_brace = self.newline_for_brace(&generics.where_clause);
let mut result = self.rewrite_fn_base(indent, let mut result = try_opt!(self.rewrite_fn_base(indent,
ident, ident,
fd, fd,
explicit_self, explicit_self,
@ -112,7 +112,7 @@ impl<'a> FmtVisitor<'a> {
abi, abi,
vis, vis,
span, span,
newline_brace); newline_brace));
if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') { if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
newline_brace = false; newline_brace = false;
@ -130,7 +130,7 @@ impl<'a> FmtVisitor<'a> {
result.push(' '); result.push(' ');
} }
result Some(result)
} }
pub fn rewrite_required_fn(&mut self, pub fn rewrite_required_fn(&mut self,
@ -138,11 +138,11 @@ impl<'a> FmtVisitor<'a> {
ident: ast::Ident, ident: ast::Ident,
sig: &ast::MethodSig, sig: &ast::MethodSig,
span: Span) span: Span)
-> String { -> Option<String> {
// Drop semicolon or it will be interpreted as comment // Drop semicolon or it will be interpreted as comment
let span = codemap::mk_sp(span.lo, span.hi - BytePos(1)); let span = codemap::mk_sp(span.lo, span.hi - BytePos(1));
let mut result = self.rewrite_fn_base(indent, let mut result = try_opt!(self.rewrite_fn_base(indent,
ident, ident,
&sig.decl, &sig.decl,
Some(&sig.explicit_self), Some(&sig.explicit_self),
@ -152,12 +152,12 @@ impl<'a> FmtVisitor<'a> {
&sig.abi, &sig.abi,
ast::Visibility::Inherited, ast::Visibility::Inherited,
span, span,
false); false));
// Re-attach semicolon // Re-attach semicolon
result.push(';'); result.push(';');
result Some(result)
} }
fn rewrite_fn_base(&mut self, fn rewrite_fn_base(&mut self,
@ -172,7 +172,7 @@ impl<'a> FmtVisitor<'a> {
vis: ast::Visibility, vis: ast::Visibility,
span: Span, span: Span,
newline_brace: bool) newline_brace: bool)
-> String { -> Option<String> {
// FIXME we'll lose any comments in between parts of the function decl, but anyone // FIXME we'll lose any comments in between parts of the function decl, but anyone
// who comments there probably deserves what they get. // who comments there probably deserves what they get.
@ -200,11 +200,12 @@ impl<'a> FmtVisitor<'a> {
// Generics. // Generics.
let generics_indent = indent + result.len(); let generics_indent = indent + result.len();
result.push_str(&self.rewrite_generics(generics, let generics_span = codemap::mk_sp(span.lo, span_for_return(&fd.output).lo);
let generics_str = try_opt!(self.rewrite_generics(generics,
indent, indent,
generics_indent, generics_indent,
codemap::mk_sp(span.lo, generics_span));
span_for_return(&fd.output).lo))); result.push_str(&generics_str);
let ret_str = self.rewrite_return(&fd.output, indent); let ret_str = self.rewrite_return(&fd.output, indent);
@ -243,13 +244,14 @@ impl<'a> FmtVisitor<'a> {
"(", "(",
self.codemap), self.codemap),
span_for_return(&fd.output).lo); span_for_return(&fd.output).lo);
result.push_str(&self.rewrite_args(&fd.inputs, let arg_str = try_opt!(self.rewrite_args(&fd.inputs,
explicit_self, explicit_self,
one_line_budget, one_line_budget,
multi_line_budget, multi_line_budget,
indent, indent,
arg_indent, arg_indent,
args_span)); args_span));
result.push_str(&arg_str);
if self.config.fn_args_layout == StructLitStyle::Block { if self.config.fn_args_layout == StructLitStyle::Block {
result.push('\n'); result.push('\n');
} }
@ -307,13 +309,14 @@ impl<'a> FmtVisitor<'a> {
}; };
// Where clause. // Where clause.
result.push_str(&self.rewrite_where_clause(where_clause, let where_clause_str = try_opt!(self.rewrite_where_clause(where_clause,
self.config, self.config,
indent, indent,
where_density, where_density,
span.hi)); span.hi));
result.push_str(&where_clause_str);
result Some(result)
} }
fn rewrite_args(&self, fn rewrite_args(&self,
@ -324,7 +327,7 @@ impl<'a> FmtVisitor<'a> {
indent: usize, indent: usize,
arg_indent: usize, arg_indent: usize,
span: Span) span: Span)
-> String { -> Option<String> {
let mut arg_item_strs: Vec<_> = args.iter().map(rewrite_fn_input).collect(); let mut arg_item_strs: Vec<_> = args.iter().map(rewrite_fn_input).collect();
// Account for sugary self. // Account for sugary self.
// FIXME: the comment for the self argument is dropped. This is blocked // FIXME: the comment for the self argument is dropped. This is blocked
@ -461,8 +464,8 @@ impl<'a> FmtVisitor<'a> {
" {", " {",
self.block_indent, self.block_indent,
self.block_indent + self.config.tab_spaces, self.block_indent + self.config.tab_spaces,
codemap::mk_sp(span.lo, codemap::mk_sp(span.lo, body_start))
body_start)); .unwrap();
self.buffer.push_str(&generics_str); self.buffer.push_str(&generics_str);
self.last_pos = body_start; self.last_pos = body_start;
@ -534,7 +537,12 @@ impl<'a> FmtVisitor<'a> {
v_width: budget, v_width: budget,
ends_with_newline: true, ends_with_newline: true,
}; };
result.push_str(&write_list(&items.collect::<Vec<_>>(), &fmt)); let list_str = match write_list(&items.collect::<Vec<_>>(), &fmt) {
Some(list_str) => list_str,
None => return,
};
result.push_str(&list_str);
result.push(')'); result.push(')');
} }
@ -554,13 +562,18 @@ impl<'a> FmtVisitor<'a> {
} }
ast::VariantKind::StructVariantKind(ref struct_def) => { ast::VariantKind::StructVariantKind(ref struct_def) => {
// TODO Should limit the width, as we have a trailing comma // TODO Should limit the width, as we have a trailing comma
self.format_struct("", let struct_rewrite = self.format_struct("",
field.node.name, field.node.name,
field.node.vis, field.node.vis,
struct_def, struct_def,
None, None,
field.span, field.span,
self.block_indent) self.block_indent);
match struct_rewrite {
Some(struct_str) => struct_str,
None => return,
}
} }
}; };
self.buffer.push_str(&result); self.buffer.push_str(&result);
@ -580,7 +593,7 @@ impl<'a> FmtVisitor<'a> {
generics: Option<&ast::Generics>, generics: Option<&ast::Generics>,
span: Span, span: Span,
offset: usize) offset: usize)
-> String { -> Option<String> {
let mut result = String::with_capacity(1024); let mut result = String::with_capacity(1024);
let header_str = self.format_header(item_name, ident, vis); let header_str = self.format_header(item_name, ident, vis);
@ -588,7 +601,7 @@ impl<'a> FmtVisitor<'a> {
if struct_def.fields.is_empty() { if struct_def.fields.is_empty() {
result.push(';'); result.push(';');
return result; return Some(result);
} }
let is_tuple = match struct_def.fields[0].node.kind { let is_tuple = match struct_def.fields[0].node.kind {
@ -603,12 +616,14 @@ impl<'a> FmtVisitor<'a> {
}; };
let generics_str = match generics { let generics_str = match generics {
Some(g) => self.format_generics(g, Some(g) => {
try_opt!(self.format_generics(g,
opener, opener,
offset, offset,
offset + header_str.len(), offset + header_str.len(),
codemap::mk_sp(span.lo, codemap::mk_sp(span.lo,
struct_def.fields[0].span.lo)), struct_def.fields[0].span.lo)))
}
None => opener.to_owned(), None => opener.to_owned(),
}; };
result.push_str(&generics_str); result.push_str(&generics_str);
@ -658,8 +673,9 @@ impl<'a> FmtVisitor<'a> {
v_width: budget, v_width: budget,
ends_with_newline: true, ends_with_newline: true,
}; };
let list_str = write_list(&items.collect::<Vec<_>>(), &fmt).unwrap();
result.push_str(&write_list(&items.collect::<Vec<_>>(), &fmt)); result.push_str(&list_str);
if break_line { if break_line {
result.push('\n'); result.push('\n');
@ -672,7 +688,7 @@ impl<'a> FmtVisitor<'a> {
result.push(';'); result.push(';');
} }
result Some(result)
} }
pub fn visit_struct(&mut self, pub fn visit_struct(&mut self,
@ -688,7 +704,9 @@ impl<'a> FmtVisitor<'a> {
struct_def, struct_def,
Some(generics), Some(generics),
span, span,
indent); indent)
.unwrap();
self.buffer.push_str(&result); self.buffer.push_str(&result);
self.last_pos = span.hi; self.last_pos = span.hi;
} }
@ -703,15 +721,16 @@ impl<'a> FmtVisitor<'a> {
offset: usize, offset: usize,
generics_offset: usize, generics_offset: usize,
span: Span) span: Span)
-> String { -> Option<String> {
let mut result = self.rewrite_generics(generics, offset, generics_offset, span); let mut result = try_opt!(self.rewrite_generics(generics, offset, generics_offset, span));
if !generics.where_clause.predicates.is_empty() || result.contains('\n') { if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
result.push_str(&self.rewrite_where_clause(&generics.where_clause, let where_clause_str = try_opt!(self.rewrite_where_clause(&generics.where_clause,
self.config, self.config,
self.block_indent, self.block_indent,
Density::Tall, Density::Tall,
span.hi)); span.hi));
result.push_str(&where_clause_str);
result.push_str(&make_indent(self.block_indent)); result.push_str(&make_indent(self.block_indent));
result.push('\n'); result.push('\n');
result.push_str(opener.trim()); result.push_str(opener.trim());
@ -719,7 +738,7 @@ impl<'a> FmtVisitor<'a> {
result.push_str(opener); result.push_str(opener);
} }
result Some(result)
} }
// Field of a struct // Field of a struct
@ -761,13 +780,13 @@ impl<'a> FmtVisitor<'a> {
offset: usize, offset: usize,
generics_offset: usize, generics_offset: usize,
span: Span) span: Span)
-> String { -> Option<String> {
// FIXME convert bounds to where clauses where they get too big or if // FIXME convert bounds to where clauses where they get too big or if
// there is a where clause at all. // there is a where clause at all.
let lifetimes: &[_] = &generics.lifetimes; let lifetimes: &[_] = &generics.lifetimes;
let tys: &[_] = &generics.ty_params; let tys: &[_] = &generics.ty_params;
if lifetimes.is_empty() && tys.is_empty() { if lifetimes.is_empty() && tys.is_empty() {
return String::new(); return Some(String::new());
} }
let offset = match self.config.generics_indent { let offset = match self.config.generics_indent {
@ -816,8 +835,9 @@ impl<'a> FmtVisitor<'a> {
} }
let fmt = ListFormatting::for_fn(h_budget, offset); let fmt = ListFormatting::for_fn(h_budget, offset);
let list_str = try_opt!(write_list(&items, &fmt));
format!("<{}>", write_list(&items, &fmt)) Some(format!("<{}>", list_str))
} }
fn rewrite_where_clause(&self, fn rewrite_where_clause(&self,
@ -826,9 +846,9 @@ impl<'a> FmtVisitor<'a> {
indent: usize, indent: usize,
density: Density, density: Density,
span_end: BytePos) span_end: BytePos)
-> String { -> Option<String> {
if where_clause.predicates.is_empty() { if where_clause.predicates.is_empty() {
return String::new(); return Some(String::new());
} }
let extra_indent = match self.config.where_indent { let extra_indent = match self.config.where_indent {
@ -870,16 +890,16 @@ impl<'a> FmtVisitor<'a> {
v_width: budget, v_width: budget,
ends_with_newline: true, ends_with_newline: true,
}; };
let preds_str = write_list(&items.collect::<Vec<_>>(), &fmt); let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
// 9 = " where ".len() + " {".len() // 9 = " where ".len() + " {".len()
if density == Density::Tall || preds_str.contains('\n') || if density == Density::Tall || preds_str.contains('\n') ||
indent + 9 + preds_str.len() > self.config.max_width { indent + 9 + preds_str.len() > self.config.max_width {
format!("\n{}where {}", Some(format!("\n{}where {}",
make_indent(indent + extra_indent), make_indent(indent + extra_indent),
preds_str) preds_str))
} else { } else {
format!(" where {}", preds_str) Some(format!(" where {}", preds_str))
} }
} }

View file

@ -13,7 +13,7 @@ use std::iter::Peekable;
use syntax::codemap::{self, CodeMap, BytePos}; use syntax::codemap::{self, CodeMap, BytePos};
use utils::{round_up_to_power_of_two, make_indent}; use utils::{round_up_to_power_of_two, make_indent, wrap_str};
use comment::{FindUncommented, rewrite_comment, find_comment_end}; use comment::{FindUncommented, rewrite_comment, find_comment_end};
#[derive(Eq, PartialEq, Debug, Copy, Clone)] #[derive(Eq, PartialEq, Debug, Copy, Clone)]
@ -95,9 +95,9 @@ impl ListItem {
// Format a list of commented items into a string. // Format a list of commented items into a string.
// FIXME: this has grown into a monstrosity // FIXME: this has grown into a monstrosity
// TODO: add unit tests // TODO: add unit tests
pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> String { pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> Option<String> {
if items.is_empty() { if items.is_empty() {
return String::new(); return Some(String::new());
} }
let mut tactic = formatting.tactic; let mut tactic = formatting.tactic;
@ -204,7 +204,9 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> St
} }
} }
result.push_str(&item.item); // FIXME: no magic numbers!
let item_str = wrap_str(&item.item[..], 100, formatting.v_width, formatting.indent);
result.push_str(&&try_opt!(item_str));
// Post-comments // Post-comments
if tactic != ListTactic::Vertical && item.post_comment.is_some() { if tactic != ListTactic::Vertical && item.post_comment.is_some() {
@ -240,7 +242,7 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> St
} }
} }
result Some(result)
} }
pub struct ListItems<'a, I, F1, F2, F3> pub struct ListItems<'a, I, F1, F2, F3>

View file

@ -87,6 +87,12 @@ fn rewrite_path_segments<'a, I>(mut buffer: String,
let mut first = true; let mut first = true;
for segment in iter { for segment in iter {
if first {
first = false;
} else {
buffer.push_str("::");
}
let extra_offset = extra_offset(&buffer, offset); let extra_offset = extra_offset(&buffer, offset);
let remaining_width = try_opt!(width.checked_sub(extra_offset)); let remaining_width = try_opt!(width.checked_sub(extra_offset));
let new_offset = offset + extra_offset; let new_offset = offset + extra_offset;
@ -97,12 +103,6 @@ fn rewrite_path_segments<'a, I>(mut buffer: String,
remaining_width, remaining_width,
new_offset)); new_offset));
if first {
first = false;
} else {
buffer.push_str("::");
}
buffer.push_str(&segment_string); buffer.push_str(&segment_string);
} }
@ -218,18 +218,20 @@ fn rewrite_segment(segment: &ast::PathSegment,
">", ">",
|param| param.get_span().lo, |param| param.get_span().lo,
|param| param.get_span().hi, |param| param.get_span().hi,
// FIXME: need better params
|seg| { |seg| {
seg.rewrite(context, list_width, offset + extra_offset).unwrap() seg.rewrite(context, 1000, offset + extra_offset).unwrap()
}, },
list_lo, list_lo,
span_hi); span_hi);
let fmt = ListFormatting::for_fn(list_width, offset + extra_offset); let fmt = ListFormatting::for_fn(list_width, offset + extra_offset);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
// update pos // update pos
*span_lo = next_span_lo; *span_lo = next_span_lo;
format!("{}<{}>", separator, write_list(&items.collect::<Vec<_>>(), &fmt)) format!("{}<{}>", separator, list_str)
} }
ast::PathParameters::ParenthesizedParameters(ref data) => { ast::PathParameters::ParenthesizedParameters(ref data) => {
let output = match data.output { let output = match data.output {
@ -252,11 +254,12 @@ fn rewrite_segment(segment: &ast::PathSegment,
// 1 for ( // 1 for (
let fmt = ListFormatting::for_fn(budget, offset + 1); let fmt = ListFormatting::for_fn(budget, offset + 1);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
// update pos // update pos
*span_lo = data.span.hi + BytePos(1); *span_lo = data.span.hi + BytePos(1);
format!("({}){}", write_list(&items.collect::<Vec<_>>(), &fmt), output) format!("({}){}", list_str, output)
} }
_ => String::new(), _ => String::new(),
}; };
@ -354,7 +357,8 @@ impl Rewrite for ast::TyParamBound {
impl Rewrite for ast::TyParamBounds { impl Rewrite for ast::TyParamBounds {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> { fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
let strs: Vec<_> = self.iter().map(|b| b.rewrite(context, width, offset).unwrap()).collect(); let strs: Vec<_> =
self.iter().map(|b| b.rewrite(context, width, offset).unwrap()).collect();
Some(strs.join(" + ")) Some(strs.join(" + "))
} }
} }

View file

@ -164,6 +164,38 @@ macro_rules! try_opt {
}) })
} }
pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usize) -> Option<S> {
let snippet = s.as_ref();
if !snippet.contains('\n') && snippet.len() > width {
return None;
} else {
let mut lines = snippet.lines();
// The caller of this function has already placed `offset`
// characters on the first line.
let first_line_max_len = try_opt!(max_width.checked_sub(offset));
if lines.next().unwrap().len() > first_line_max_len {
return None;
}
// The other lines must fit within the maximum width.
if lines.find(|line| line.len() > max_width).is_some() {
return None;
}
// `width` is the maximum length of the last line, excluding
// indentation.
// A special check for the last line, since the caller may
// place trailing characters on this line.
if snippet.lines().rev().next().unwrap().len() > offset + width {
return None;
}
}
Some(s)
}
#[test] #[test]
fn power_rounding() { fn power_rounding() {
assert_eq!(0, round_up_to_power_of_two(0)); assert_eq!(0, round_up_to_power_of_two(0));

View file

@ -87,7 +87,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
// Check if this block has braces. // Check if this block has braces.
let snippet = self.snippet(b.span); let snippet = self.snippet(b.span);
let has_braces = snippet.chars().next().unwrap() == '{' || &snippet[..6] == "unsafe"; let has_braces = &snippet[..1] == "{" || &snippet[..6] == "unsafe";
let brace_compensation = if has_braces { let brace_compensation = if has_braces {
BytePos(1) BytePos(1)
} else { } else {
@ -125,18 +125,15 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
b: &'v ast::Block, b: &'v ast::Block,
s: Span, s: Span,
_: ast::NodeId) { _: ast::NodeId) {
self.format_missing_with_indent(s.lo);
self.last_pos = s.lo;
let indent = self.block_indent; let indent = self.block_indent;
match fk { let rewrite = match fk {
visit::FnKind::ItemFn(ident, visit::FnKind::ItemFn(ident,
ref generics, ref generics,
ref unsafety, ref unsafety,
ref constness, ref constness,
ref abi, ref abi,
vis) => { vis) => {
let new_fn = self.rewrite_fn(indent, self.rewrite_fn(indent,
ident, ident,
fd, fd,
None, None,
@ -145,11 +142,10 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
constness, constness,
abi, abi,
vis, vis,
codemap::mk_sp(s.lo, b.span.lo)); codemap::mk_sp(s.lo, b.span.lo))
self.buffer.push_str(&new_fn);
} }
visit::FnKind::Method(ident, ref sig, vis) => { visit::FnKind::Method(ident, ref sig, vis) => {
let new_fn = self.rewrite_fn(indent, self.rewrite_fn(indent,
ident, ident,
fd, fd,
Some(&sig.explicit_self), Some(&sig.explicit_self),
@ -158,10 +154,16 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
&sig.constness, &sig.constness,
&sig.abi, &sig.abi,
vis.unwrap_or(ast::Visibility::Inherited), vis.unwrap_or(ast::Visibility::Inherited),
codemap::mk_sp(s.lo, b.span.lo)); codemap::mk_sp(s.lo, b.span.lo))
self.buffer.push_str(&new_fn);
} }
visit::FnKind::Closure => {} visit::FnKind::Closure => None,
};
if let Some(fn_str) = rewrite {
self.format_missing_with_indent(s.lo);
self.buffer.push_str(&fn_str);
} else {
self.format_missing(b.span.lo);
} }
self.last_pos = b.span.lo; self.last_pos = b.span.lo;
@ -239,9 +241,12 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
sig, sig,
ti.span); ti.span);
self.buffer.push_str(&new_fn);
if let Some(fn_str) = new_fn {
self.buffer.push_str(&fn_str);
self.last_pos = ti.span.hi; self.last_pos = ti.span.hi;
} }
}
// TODO format trait types // TODO format trait types
visit::walk_trait_item(self, ti) visit::walk_trait_item(self, ti)

View file

@ -2,8 +2,8 @@
// Long import. // Long import.
use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use exceedingly::looooooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA, use exceedingly::looooooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA, ItemB};
ItemB}; use exceedingly::loooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA, ItemB};
use list::{ use list::{
// Some item // Some item

View file

@ -1,6 +1,5 @@
fn main() { 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( let constellation_chan = Constellation::<layout::layout_task::LayoutTask, script::script_task::ScriptTask> ::start(
compositor_proxy, compositor_proxy,
resource_task, resource_task,

View file

@ -2,7 +2,8 @@
// Long import. // Long import.
use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use exceedingly::looooooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA, use exceedingly::looooooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA, ItemB};
use exceedingly::loooooooooooooooooooooooooooooooooooooooooooooooooooooooong::import::path::{ItemA,
ItemB}; ItemB};
use list::{// Some item use list::{// Some item

View file

@ -1,7 +1,7 @@
fn main() { fn main() {
// FIXME(#133): the list rewrite should fail and force a different format let constellation_chan =
let constellation_chan = Constellation::<layout::layout_task::LayoutTask, Constellation::<layout::layout_task::LayoutTask,
script::script_task::ScriptTask>::start(compositor_proxy, script::script_task::ScriptTask>::start(compositor_proxy,
resource_task, resource_task,
image_cache_task, image_cache_task,

View file

@ -4,7 +4,7 @@ fn foo() {
let a = (a, a, a, a, a); let a = (a, a, a, a, a);
let aaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaa, aaaaaaaaaaaaaa); let aaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaa, aaaaaaaaaaaaaa);
let aaaaaaaaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, let aaaaaaaaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaa,
aaaa); aaaa);
let a = (a,); let a = (a,);