about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2015-05-25 11:03:26 +1200
committerNick Cameron <ncameron@mozilla.com>2015-05-25 17:07:55 +1200
commite7adf64155abb3bdc2dcb6bb52ee24ed87206eff (patch)
tree6a908b645ba344ff537671e3235db6cf733e2bc2 /src
parentc3856880f6c40649d3bb9a330c65de79db6c56a4 (diff)
Format structs
Diffstat (limited to 'src')
-rw-r--r--src/bin/rustfmt.rs4
-rw-r--r--src/config.rs1
-rw-r--r--src/items.rs (renamed from src/functions.rs)126
-rw-r--r--src/lib.rs2
-rw-r--r--src/visitor.rs11
5 files changed, 136 insertions, 8 deletions
diff --git a/src/bin/rustfmt.rs b/src/bin/rustfmt.rs
index 5a12dbd639b..3b87ac7eb03 100644
--- a/src/bin/rustfmt.rs
+++ b/src/bin/rustfmt.rs
@@ -24,8 +24,8 @@ fn main() {
     let mut def_config = String::new();
     def_config_file.read_to_string(&mut def_config).unwrap();
 
-    //run(args, WriteMode::Display, &def_config);
-    run(args, WriteMode::Overwrite, &def_config);
+    run(args, WriteMode::Display, &def_config);
+    //run(args, WriteMode::Overwrite, &def_config);
 
     std::env::set_exit_status(0);
 
diff --git a/src/config.rs b/src/config.rs
index d1045293ee3..080926b03a2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -23,7 +23,6 @@ pub struct Config {
 
 impl Config {
     fn from_toml(toml: &str) -> Config {
-        println!("About to parse: {}", toml);
         let parsed = toml.parse().unwrap();
         toml::decode(parsed).unwrap()
     }
diff --git a/src/functions.rs b/src/items.rs
index 2ca5423f0c8..a2027d89b88 100644
--- a/src/functions.rs
+++ b/src/items.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Formatting top-level items - functions, structs, enums, traits, impls.
+
 use {ReturnIndent, BraceStyle};
 use utils::make_indent;
 use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};
@@ -123,7 +125,7 @@ impl<'a> FmtVisitor<'a> {
         let generics_indent = indent + result.len();
         result.push_str(&self.rewrite_generics(generics,
                                                generics_indent,
-                                               span_for_return(&fd.output)));
+                                               span_for_return(&fd.output).lo));
 
         let ret_str = self.rewrite_return(&fd.output);
 
@@ -388,7 +390,125 @@ impl<'a> FmtVisitor<'a> {
         }
     }
 
-    fn rewrite_generics(&self, generics: &ast::Generics, indent: usize, ret_span: Span) -> String {
+    pub fn visit_struct(&mut self,
+                        ident: ast::Ident,
+                        vis: ast::Visibility,
+                        struct_def: &ast::StructDef,
+                        generics: &ast::Generics,
+                        span: Span)
+    {
+        let header_str = self.struct_header(ident, vis);
+        self.changes.push_str_span(span, &header_str);
+
+        if struct_def.fields.len() == 0 {
+            assert!(generics.where_clause.predicates.len() == 0,
+                    "No-field struct with where clause?");
+            assert!(generics.lifetimes.len() == 0, "No-field struct with generics?");
+            assert!(generics.ty_params.len() == 0, "No-field struct with generics?");
+
+            self.changes.push_str_span(span, ";");
+            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 struct_snippet = self.snippet(span);
+        // FIXME this will give incorrect results if there is a { in a commet.
+        self.last_pos = span.lo + BytePos(struct_snippet.find('{').unwrap() as u32 + 1);
+
+        self.block_indent += config!(tab_spaces);
+        for f in &struct_def.fields {
+            self.visit_field(f, span.lo, &struct_snippet);
+        }
+        self.block_indent -= config!(tab_spaces);
+
+        self.format_missing_with_indent(span.lo + BytePos(struct_snippet.rfind('}').unwrap() as u32));
+        self.changes.push_str_span(span, "}");
+    }
+
+    fn struct_header(&self,
+                     ident: ast::Ident,
+                     vis: ast::Visibility)
+        -> String
+    {
+        let vis = if vis == ast::Visibility::Public {
+            "pub "
+        } else {
+            ""
+        };
+
+        format!("{}struct {}", vis, &token::get_ident(ident))
+    }
+
+    // Field of a struct
+    fn visit_field(&mut self,
+                   field: &ast::StructField,
+                   // These two args are for missing spans hacks.
+                   struct_start: BytePos,
+                   struct_snippet: &str)
+    {
+        if self.visit_attrs(&field.node.attrs) {
+            return;
+        }
+        self.format_missing_with_indent(field.span.lo);
+
+        let name = match field.node.kind {
+            ast::StructFieldKind::NamedField(ident, _) => Some(token::get_ident(ident)),
+            ast::StructFieldKind::UnnamedField(_) => None,
+        };
+        let vis = match field.node.kind {
+            ast::StructFieldKind::NamedField(_, vis) |
+            ast::StructFieldKind::UnnamedField(vis) => if vis == ast::Visibility::Public {
+                "pub "
+            } else {
+                ""
+            }
+        };
+        let typ = pprust::ty_to_string(&field.node.ty);
+
+        let field_str = match name {
+            Some(name) => {
+                let budget = config!(ideal_width) - self.block_indent;
+                if self.block_indent + vis.len() + name.len() + typ.len() + 3 > budget {
+                    format!("{}{}:\n{}{},",
+                            vis,
+                            name,
+                            &make_indent(self.block_indent + config!(tab_spaces)),
+                            typ)
+                } else {
+                    format!("{}{}: {},", vis, name, typ)
+                }
+            }
+            None => format!("{}{},", vis, typ),
+        };
+        self.changes.push_str_span(field.span, &field_str);
+
+        // This hack makes sure we only add comments etc. after the comma, and
+        // makes sure we don't repeat any commas.
+        let hi = field.span.hi;
+        // FIXME a comma in a comment will break this hack.
+        let comma_pos = match struct_snippet[(hi.0 - struct_start.0) as usize..].find(',') {
+            Some(i) => i,
+            None => 0,
+        };
+        self.last_pos = hi + BytePos(comma_pos as u32 + 1);
+    }
+
+    fn rewrite_generics(&self, generics: &ast::Generics, indent: usize, span_end: BytePos) -> String {
         // FIXME convert bounds to where clauses where they get too big or if
         // there is a where clause at all.
         let mut result = String::new();
@@ -422,7 +542,7 @@ impl<'a> FmtVisitor<'a> {
                                                    ">",
                                                    |sp| sp.lo,
                                                    |sp| sp.hi,
-                                                   ret_span.lo);
+                                                   span_end);
 
         // If there are // comments, keep them multi-line.
         let mut list_tactic = ListTactic::HorizontalVertical;
diff --git a/src/lib.rs b/src/lib.rs
index 386c39ad472..1a690b4945a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,7 +50,7 @@ use visitor::FmtVisitor;
 mod config;
 mod changes;
 mod visitor;
-mod functions;
+mod items;
 mod missed_spans;
 mod lists;
 mod utils;
diff --git a/src/visitor.rs b/src/visitor.rs
index 2aac931c4e6..256c1e6e132 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -180,6 +180,15 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
                 self.changes.push_str_span(item.span, &new_str);
                 self.last_pos = item.span.hi;
             }
+            ast::Item_::ItemStruct(ref def, ref generics) => {
+                self.format_missing_with_indent(item.span.lo);
+                self.visit_struct(item.ident,
+                                  item.vis,
+                                  def,
+                                  generics,
+                                  item.span);
+                self.last_pos = item.span.hi;
+            }
             _ => {
                 visit::walk_item(self, item);
             }
@@ -252,7 +261,7 @@ impl<'a> FmtVisitor<'a> {
     }
 
     // Returns true if we should skip the following item.
-    fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
+    pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
         if attrs.len() == 0 {
             return false;
         }