Work across multiple files

This commit is contained in:
Nick Cameron 2015-04-14 21:52:12 +12:00
parent 8f5b899c85
commit 0a67babb95
2 changed files with 100 additions and 49 deletions

View File

@ -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<String, StringBuffer>,
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)

View File

@ -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()
}
}