diff --git a/src/changes.rs b/src/changes.rs index 752ae942f1f..068b6b7736c 100644 --- a/src/changes.rs +++ b/src/changes.rs @@ -15,7 +15,7 @@ use strings::string_buffer::StringBuffer; use std::collections::HashMap; -use syntax::codemap::{CodeMap, Span}; +use syntax::codemap::{CodeMap, Span,BytePos}; use std::fmt; // This is basically a wrapper around a bunch of Ropes which makes it convenient @@ -23,6 +23,7 @@ use std::fmt; pub struct ChangeSet<'a> { file_map: HashMap, codemap: &'a CodeMap, + file_spans: Vec<(u32, u32)>, } impl<'a> ChangeSet<'a> { @@ -31,6 +32,7 @@ impl<'a> ChangeSet<'a> { let mut result = ChangeSet { file_map: HashMap::new(), codemap: codemap, + file_spans: Vec::with_capacity(codemap.files.borrow().len()), }; for f in codemap.files.borrow().iter() { @@ -39,11 +41,49 @@ impl<'a> ChangeSet<'a> { // power of two. TODO check that or do it here. result.file_map.insert(f.name.clone(), StringBuffer::with_capacity(f.src.as_ref().unwrap().len())); + + result.file_spans.push((f.start_pos.0, f.end_pos.0)); } + result.file_spans.sort(); + result } + pub fn filespans_for_span(&self, start: BytePos, end: BytePos) -> Vec<(u32, u32)> { + assert!(start.0 <= end.0); + + if self.file_spans.len() == 0 { + return Vec::new(); + } + + let mut idx = match self.file_spans.binary_search(&(start.0, ::std::u32::MAX)) { + Ok(i) => i, + Err(0) => 0, + Err(i) => i - 1, + }; + + let mut result = Vec::new(); + let mut start = start.0; + loop { + let cur_file = &self.file_spans[idx]; + idx += 1; + + if idx >= self.file_spans.len() || start >= end.0 { + if start < end.0 { + result.push((start, end.0)); + } + return result; + } + + let end = ::std::cmp::min(cur_file.1 - 1, end.0); + if start < end { + result.push((start, end)); + } + start = self.file_spans[idx].0; + } + } + pub fn push_str(&mut self, file_name: &str, text: &str) { let buf = self.file_map.get_mut(&*file_name).unwrap(); buf.push_str(text) diff --git a/src/mod.rs b/src/mod.rs index a124eb9e2b4..65951638c1c 100644 --- a/src/mod.rs +++ b/src/mod.rs @@ -22,8 +22,8 @@ // TODO priorities // Fix fns and methods properly - need visibility in visit // Writing output -// Working on multiple files, inclding empty ones // Smoke testing till we can use it +// end of multi-line string has wspace #[macro_use] extern crate log; @@ -123,10 +123,9 @@ struct FmtVisitor<'a> { impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { fn visit_expr(&mut self, ex: &'v ast::Expr) { - // TODO uncomment - // debug!("visit_expr: {:?} {:?}", - // self.codemap.lookup_char_pos(ex.span.lo), - // self.codemap.lookup_char_pos(ex.span.hi)); + debug!("visit_expr: {:?} {:?}", + 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.changes.cur_offset_span(ex.span); let new_str = self.rewrite_expr(ex, MAX_WIDTH - offset, offset); @@ -135,10 +134,9 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { } fn visit_block(&mut self, b: &'v ast::Block) { - // TODO uncomment - // debug!("visit_block: {:?} {:?}", - // self.codemap.lookup_char_pos(b.span.lo), - // self.codemap.lookup_char_pos(b.span.hi)); + debug!("visit_block: {:?} {:?}", + self.codemap.lookup_char_pos(b.span.lo), + self.codemap.lookup_char_pos(b.span.hi)); self.format_missing(b.span.lo); self.changes.push_str_span(b.span, "{"); @@ -241,6 +239,15 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { fn visit_mac(&mut self, mac: &'v ast::Mac) { visit::walk_mac(self, mac) } + + fn visit_mod(&mut self, m: &'v ast::Mod, s: Span, _: ast::NodeId) { + // Only visit inline mods here. + if self.codemap.lookup_char_pos(s.lo).file.name != + self.codemap.lookup_char_pos(m.inner.lo).file.name { + return; + } + visit::walk_mod(self, m); + } } fn make_indent(width: usize) -> String { @@ -413,63 +420,67 @@ impl<'a> FmtVisitor<'a> { process_last_snippet: F) { let start = self.last_pos; - // TODO uncomment - // debug!("format_missing_inner: {:?} to {:?}", - // self.codemap.lookup_char_pos(start), - // self.codemap.lookup_char_pos(end)); - - // TODO(#11) gets tricky if we're missing more than one file - // assert!(self.codemap.lookup_char_pos(start).file.name == self.codemap.lookup_char_pos(end).file.name, - // "not implemented: unformated span across files: {} and {}", - // self.codemap.lookup_char_pos(start).file.name, - // self.codemap.lookup_char_pos(end).file.name); - // assert!(start <= end, - // "Request to format inverted span: {:?} to {:?}", - // self.codemap.lookup_char_pos(start), - // self.codemap.lookup_char_pos(end)); + debug!("format_missing_inner: {:?} to {:?}", + self.codemap.lookup_char_pos(start), + self.codemap.lookup_char_pos(end)); if start == end { return; } + assert!(start < end, + "Request to format inverted span: {:?} to {:?}", + self.codemap.lookup_char_pos(start), + self.codemap.lookup_char_pos(end)); + + self.last_pos = end; - let span = codemap::mk_sp(start, end); - let snippet = self.snippet(span); + let spans = self.changes.filespans_for_span(start, end); + for (i, &(start, end)) in spans.iter().enumerate() { + let span = codemap::mk_sp(BytePos(start), BytePos(end)); + let snippet = self.snippet(span); - // Trim whitespace from the right hand side of each line. - // Annoyingly, the library functions for splitting by lines etc. are not - // quite right, so we must do it ourselves. - let mut line_start = 0; - let mut last_wspace = None; - for (i, c) in snippet.char_indices() { - if c == '\n' { - if let Some(lw) = last_wspace { - self.changes.push_str_span(span, &snippet[line_start..lw]); - self.changes.push_str_span(span, "\n"); - } else { - self.changes.push_str_span(span, &snippet[line_start..i+1]); - } - - line_start = i + 1; - last_wspace = None; - } else { - if c.is_whitespace() { - if last_wspace.is_none() { - last_wspace = Some(i); + // Trim whitespace from the right hand side of each line. + // Annoyingly, the library functions for splitting by lines etc. are not + // quite right, so we must do it ourselves. + let mut line_start = 0; + let mut last_wspace = None; + for (i, c) in snippet.char_indices() { + if c == '\n' { + if let Some(lw) = last_wspace { + self.changes.push_str_span(span, &snippet[line_start..lw]); + self.changes.push_str_span(span, "\n"); + } else { + self.changes.push_str_span(span, &snippet[line_start..i+1]); } - } else { + + line_start = i + 1; last_wspace = None; + } else { + if c.is_whitespace() { + if last_wspace.is_none() { + last_wspace = Some(i); + } + } else { + last_wspace = None; + } } } + if i == spans.len() - 1 { + process_last_snippet(self, &snippet[line_start..], span, &snippet); + } else { + self.changes.push_str_span(span, &snippet[line_start..]); + } } - process_last_snippet(self, &snippet[line_start..], span, &snippet); } fn snippet(&self, span: Span) -> String { match self.codemap.span_to_snippet(span) { Ok(s) => s, Err(_) => { - println!("Couldn't make snippet for span {:?}", span); + println!("Couldn't make snippet for span {:?}->{:?}", + self.codemap.lookup_char_pos(span.lo), + self.codemap.lookup_char_pos(span.hi)); "".to_string() } }