// Formatting top-level items - functions, structs, enums, traits, impls.
use {ReturnIndent, BraceStyle};
-use utils::make_indent;
+use utils::{format_visibility, make_indent};
use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};
use visitor::FmtVisitor;
use syntax::{ast, abi};
explicit_self: Option<&ast::ExplicitSelf>,
generics: &ast::Generics,
unsafety: &ast::Unsafety,
+ constness: &ast::Constness,
abi: &abi::Abi,
vis: ast::Visibility,
span_end: BytePos)
explicit_self,
generics,
unsafety,
+ constness,
abi,
vis,
span_end,
Some(&sig.explicit_self),
&sig.generics,
&sig.unsafety,
+ &sig.constness,
&sig.abi,
ast::Visibility::Inherited,
span_end,
explicit_self: Option<&ast::ExplicitSelf>,
generics: &ast::Generics,
unsafety: &ast::Unsafety,
+ constness: &ast::Constness,
abi: &abi::Abi,
vis: ast::Visibility,
span_end: BytePos,
let mut result = String::with_capacity(1024);
// Vis unsafety abi.
- if vis == ast::Visibility::Public {
- result.push_str("pub ");
- }
+ result.push_str(format_visibility(vis));
+
if let &ast::Unsafety::Unsafe = unsafety {
result.push_str("unsafe ");
}
+ if let &ast::Constness::Const = constness {
+ result.push_str("const ");
+ }
if *abi != abi::Rust {
result.push_str("extern ");
result.push_str(&abi.to_string());
let ret_str = self.rewrite_return(&fd.output);
// Args.
- let (one_line_budget, multi_line_budget, arg_indent) =
- self.compute_budgets_for_args(&mut result, indent, ret_str.len(), newline_brace);
+ let (one_line_budget, multi_line_budget, mut arg_indent) =
+ self.compute_budgets_for_args(&result, indent, ret_str.len(), newline_brace);
debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {}",
one_line_budget, multi_line_budget, arg_indent);
- result.push('(');
+ // Check if vertical layout was forced by compute_budget_for_args.
+ if one_line_budget <= 0 {
+ if config!(fn_args_paren_newline) {
+ result.push('\n');
+ result.push_str(&make_indent(arg_indent));
+ arg_indent = arg_indent + 1; // extra space for `(`
+ result.push('(');
+ } else {
+ result.push_str("(\n");
+ result.push_str(&make_indent(arg_indent));
+ }
+ } else {
+ result.push('(');
+ }
+
result.push_str(&self.rewrite_args(&fd.inputs,
explicit_self,
one_line_budget,
}
fn compute_budgets_for_args(&self,
- result: &mut String,
+ result: &str,
indent: usize,
ret_str_len: usize,
newline_brace: bool)
// Didn't work. we must force vertical layout and put args on a newline.
if let None = budgets {
- result.push('\n');
- result.push_str(&make_indent(indent + 4));
- // 6 = new indent + `()`
- let used_space = indent + 6;
+ let new_indent = indent + config!(tab_spaces);
+ let used_space = new_indent + 2; // account for `(` and `)`
let max_space = config!(ideal_width) + config!(leeway);
if used_space > max_space {
// Whoops! bankrupt.
// TODO take evasive action, perhaps kill the indent or something.
} else {
- // 5 = new indent + `(`
- budgets = Some((0, max_space - used_space, indent + 5));
+ budgets = Some((0, max_space - used_space, new_indent));
}
}
}
}
+ pub fn visit_enum(&mut self,
+ ident: ast::Ident,
+ vis: ast::Visibility,
+ enum_def: &ast::EnumDef,
+ generics: &ast::Generics,
+ span: Span)
+ {
+ let header_str = self.format_header("enum", ident, vis);
+ self.changes.push_str_span(span, &header_str);
+
+ let enum_snippet = self.snippet(span);
+ // FIXME this will give incorrect results if there is a { in a comment.
+ let body_start = span.lo + BytePos(enum_snippet.find('{').unwrap() as u32 + 1);
+ let generics_str = self.format_generics(generics, body_start);
+ self.changes.push_str_span(span, &generics_str);
+
+ self.last_pos = body_start;
+ self.block_indent += config!(tab_spaces);
+ for (i, f) in enum_def.variants.iter().enumerate() {
+ let next_span_start: BytePos = if i == enum_def.variants.len() - 1 {
+ span.hi
+ } else {
+ enum_def.variants[i + 1].span.lo
+ };
+
+ self.visit_variant(f, i == enum_def.variants.len() - 1, next_span_start);
+ }
+ self.block_indent -= config!(tab_spaces);
+
+ self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32));
+ self.changes.push_str_span(span, "}");
+ }
+
+ // Variant of an enum
+ fn visit_variant(&mut self,
+ field: &ast::Variant,
+ last_field: bool,
+ next_span_start: BytePos)
+ {
+ if self.visit_attrs(&field.node.attrs) {
+ return;
+ }
+
+ if let ast::VariantKind::TupleVariantKind(ref types) = field.node.kind {
+ self.format_missing_with_indent(field.span.lo);
+
+ let vis = format_visibility(field.node.vis);
+ self.changes.push_str_span(field.span, vis);
+ let name = field.node.name.to_string();
+ self.changes.push_str_span(field.span, &name);
+
+ let mut result = String::new();
+
+ if types.len() > 0 {
+ let comments = self.make_comments_for_list(Vec::new(),
+ types.iter().map(|arg| arg.ty.span),
+ ",",
+ ")",
+ |span| span.lo,
+ |span| span.hi,
+ next_span_start);
+
+ let type_strings: Vec<_> = types.iter()
+ .map(|arg| pprust::ty_to_string(&arg.ty))
+ .zip(comments.into_iter())
+ .collect();
+
+ result.push('(');
+
+ let indent = self.block_indent
+ + vis.len()
+ + field.node.name.to_string().len()
+ + 1; // 1 = (
+
+ let comma_cost = if config!(enum_trailing_comma) { 1 } else { 0 };
+ let budget = config!(ideal_width) - indent - comma_cost - 1; // 1 = )
+
+ let fmt = ListFormatting {
+ tactic: ListTactic::HorizontalVertical,
+ separator: ",",
+ trailing_separator: SeparatorTactic::Never,
+ indent: indent,
+ h_width: budget,
+ v_width: budget,
+ };
+ result.push_str(&write_list(&type_strings, &fmt));
+ result.push(')');
+ }
+
+ if let Some(ref expr) = field.node.disr_expr {
+ result.push_str(" = ");
+ let expr_snippet = self.snippet(expr.span);
+ result.push_str(&expr_snippet);
+
+ // Make sure we do not exceed column limit
+ // 4 = " = ,"
+ assert!(config!(max_width) >= vis.len() + name.len() + expr_snippet.len() + 4,
+ "Enum variant exceeded column limit");
+ }
+
+ self.changes.push_str_span(field.span, &result);
+
+ if !last_field || config!(enum_trailing_comma) {
+ self.changes.push_str_span(field.span, ",");
+ }
+ }
+
+ // TODO: deal with struct-like variants
+
+ self.last_pos = field.span.hi + BytePos(1);
+ }
+
pub fn visit_struct(&mut self,
ident: ast::Ident,
vis: ast::Visibility,
generics: &ast::Generics,
span: Span)
{
- let header_str = self.struct_header(ident, vis);
+ let header_str = self.format_header("struct", ident, vis);
self.changes.push_str_span(span, &header_str);
if struct_def.fields.len() == 0 {
return;
}
- let mut generics_buf = String::new();
- let generics_str = self.rewrite_generics(generics, self.block_indent, struct_def.fields[0].span.lo);
- generics_buf.push_str(&generics_str);
-
- if generics.where_clause.predicates.len() > 0 {
- generics_buf.push_str(&self.rewrite_where_clause(&generics.where_clause,
- self.block_indent,
- struct_def.fields[0].span.lo));
- generics_buf.push_str(&make_indent(self.block_indent));
- generics_buf.push_str("\n{");
-
- } else {
- generics_buf.push_str(" {");
- }
- self.changes.push_str_span(span, &generics_buf);
+ let generics_str = self.format_generics(generics, struct_def.fields[0].span.lo);
+ self.changes.push_str_span(span, &generics_str);
let struct_snippet = self.snippet(span);
- // FIXME this will give incorrect results if there is a { in a commet.
+ // FIXME this will give incorrect results if there is a { in a comment.
self.last_pos = span.lo + BytePos(struct_snippet.find('{').unwrap() as u32 + 1);
self.block_indent += config!(tab_spaces);
self.changes.push_str_span(span, "}");
}
- fn struct_header(&self,
+ fn format_header(&self,
+ item_name: &str,
ident: ast::Ident,
vis: ast::Visibility)
-> String
{
- let vis = if vis == ast::Visibility::Public {
- "pub "
+ format!("{}{} {}", format_visibility(vis), item_name, &token::get_ident(ident))
+ }
+
+ fn format_generics(&self,
+ generics: &ast::Generics,
+ span_end: BytePos)
+ -> String
+ {
+ let mut result = self.rewrite_generics(generics, self.block_indent, span_end);
+
+ if generics.where_clause.predicates.len() > 0 {
+ result.push_str(&self.rewrite_where_clause(&generics.where_clause,
+ self.block_indent,
+ span_end));
+ result.push_str(&make_indent(self.block_indent));
+ result.push_str("\n{");
+
} else {
- ""
- };
+ result.push_str(" {");
+ }
- format!("{}struct {}", vis, &token::get_ident(ident))
+ result
}
// Field of a struct
};
let vis = match field.node.kind {
ast::StructFieldKind::NamedField(_, vis) |
- ast::StructFieldKind::UnnamedField(vis) => if vis == ast::Visibility::Public {
- "pub "
- } else {
- ""
- }
+ ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis)
};
let typ = pprust::ty_to_string(&field.node.ty);