Skip to content

Commit 0ec1533

Browse files
authored
Merge pull request #2779 from thibaultdelor/stableApi
Improve end lines handling
2 parents 46d145b + 6b00b8b commit 0ec1533

File tree

3 files changed

+78
-115
lines changed

3 files changed

+78
-115
lines changed

src/filemap.rs

Lines changed: 36 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010

1111
// TODO: add tests
1212

13-
use std::fs::{self, File};
14-
use std::io::{self, BufWriter, Read, Write};
15-
use std::path::Path;
13+
use std::fs;
14+
use std::io::{self, Write};
1615

1716
use checkstyle::output_checkstyle_file;
18-
use config::{Config, EmitMode, FileName, NewlineStyle, Verbosity};
19-
use rustfmt_diff::{make_diff, output_modified, print_diff, Mismatch};
17+
use config::{Config, EmitMode, FileName, Verbosity};
18+
use rustfmt_diff::{make_diff, output_modified, print_diff};
2019

2120
#[cfg(test)]
2221
use FileRecord;
@@ -48,72 +47,15 @@ where
4847
Ok(())
4948
}
5049

51-
// Prints all newlines either as `\n` or as `\r\n`.
52-
pub fn write_system_newlines<T>(writer: T, text: &str, config: &Config) -> Result<(), io::Error>
53-
where
54-
T: Write,
55-
{
56-
// Buffer output, since we're writing a since char at a time.
57-
let mut writer = BufWriter::new(writer);
58-
59-
let style = if config.newline_style() == NewlineStyle::Native {
60-
if cfg!(windows) {
61-
NewlineStyle::Windows
62-
} else {
63-
NewlineStyle::Unix
64-
}
65-
} else {
66-
config.newline_style()
67-
};
68-
69-
match style {
70-
NewlineStyle::Unix => write!(writer, "{}", text),
71-
NewlineStyle::Windows => {
72-
for c in text.chars() {
73-
match c {
74-
'\n' => write!(writer, "\r\n")?,
75-
'\r' => continue,
76-
c => write!(writer, "{}", c)?,
77-
}
78-
}
79-
Ok(())
80-
}
81-
NewlineStyle::Native => unreachable!(),
82-
}
83-
}
84-
8550
pub fn write_file<T>(
86-
text: &str,
51+
formatted_text: &str,
8752
filename: &FileName,
8853
out: &mut T,
8954
config: &Config,
9055
) -> Result<bool, io::Error>
9156
where
9257
T: Write,
9358
{
94-
fn source_and_formatted_text(
95-
text: &str,
96-
filename: &Path,
97-
config: &Config,
98-
) -> Result<(String, String), io::Error> {
99-
let mut f = File::open(filename)?;
100-
let mut ori_text = String::new();
101-
f.read_to_string(&mut ori_text)?;
102-
let mut v = Vec::new();
103-
write_system_newlines(&mut v, text, config)?;
104-
let fmt_text = String::from_utf8(v).unwrap();
105-
Ok((ori_text, fmt_text))
106-
}
107-
108-
fn create_diff(
109-
filename: &Path,
110-
text: &str,
111-
config: &Config,
112-
) -> Result<Vec<Mismatch>, io::Error> {
113-
let (ori, fmt) = source_and_formatted_text(text, filename, config)?;
114-
Ok(make_diff(&ori, &fmt, 3))
115-
}
116-
11759
let filename_to_path = || match *filename {
11860
FileName::Real(ref path) => path,
11961
_ => panic!("cannot format `{}` and emit to files", filename),
@@ -122,65 +64,58 @@ where
12264
match config.emit_mode() {
12365
EmitMode::Files if config.make_backup() => {
12466
let filename = filename_to_path();
125-
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
126-
if fmt != ori {
127-
// Do a little dance to make writing safer - write to a temp file
128-
// rename the original to a .bk, then rename the temp file to the
129-
// original.
130-
let tmp_name = filename.with_extension("tmp");
131-
let bk_name = filename.with_extension("bk");
132-
{
133-
// Write text to temp file
134-
let tmp_file = File::create(&tmp_name)?;
135-
write_system_newlines(tmp_file, text, config)?;
136-
}
137-
138-
fs::rename(filename, bk_name)?;
139-
fs::rename(tmp_name, filename)?;
140-
}
67+
let ori = fs::read_to_string(filename)?;
68+
if ori != formatted_text {
69+
// Do a little dance to make writing safer - write to a temp file
70+
// rename the original to a .bk, then rename the temp file to the
71+
// original.
72+
let tmp_name = filename.with_extension("tmp");
73+
let bk_name = filename.with_extension("bk");
74+
75+
fs::write(&tmp_name, formatted_text)?;
76+
fs::rename(filename, bk_name)?;
77+
fs::rename(tmp_name, filename)?;
14178
}
14279
}
14380
EmitMode::Files => {
14481
// Write text directly over original file if there is a diff.
14582
let filename = filename_to_path();
146-
let (source, formatted) = source_and_formatted_text(text, filename, config)?;
147-
if source != formatted {
148-
let file = File::create(filename)?;
149-
write_system_newlines(file, text, config)?;
83+
let ori = fs::read_to_string(filename)?;
84+
if ori != formatted_text {
85+
fs::write(filename, formatted_text)?;
15086
}
15187
}
15288
EmitMode::Stdout | EmitMode::Coverage => {
15389
if config.verbose() != Verbosity::Quiet {
15490
println!("{}:\n", filename);
15591
}
156-
write_system_newlines(out, text, config)?;
92+
write!(out, "{}", formatted_text)?;
15793
}
15894
EmitMode::ModifiedLines => {
15995
let filename = filename_to_path();
160-
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
161-
let mismatch = make_diff(&ori, &fmt, 0);
162-
let has_diff = !mismatch.is_empty();
163-
output_modified(out, mismatch);
164-
return Ok(has_diff);
165-
}
96+
let ori = fs::read_to_string(filename)?;
97+
let mismatch = make_diff(&ori, formatted_text, 0);
98+
let has_diff = !mismatch.is_empty();
99+
output_modified(out, mismatch);
100+
return Ok(has_diff);
166101
}
167102
EmitMode::Checkstyle => {
168103
let filename = filename_to_path();
169-
let diff = create_diff(filename, text, config)?;
104+
let ori = fs::read_to_string(filename)?;
105+
let diff = make_diff(&ori, formatted_text, 3);
170106
output_checkstyle_file(out, filename, diff)?;
171107
}
172108
EmitMode::Diff => {
173109
let filename = filename_to_path();
174-
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
175-
let mismatch = make_diff(&ori, &fmt, 3);
176-
let has_diff = !mismatch.is_empty();
177-
print_diff(
178-
mismatch,
179-
|line_num| format!("Diff in {} at line {}:", filename.display(), line_num),
180-
config,
181-
);
182-
return Ok(has_diff);
183-
}
110+
let ori = fs::read_to_string(filename)?;
111+
let mismatch = make_diff(&ori, formatted_text, 3);
112+
let has_diff = !mismatch.is_empty();
113+
print_diff(
114+
mismatch,
115+
|line_num| format!("Diff in {} at line {}:", filename.display(), line_num),
116+
config,
117+
);
118+
return Ok(has_diff);
184119
}
185120
}
186121

src/lib.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ use visitor::{FmtVisitor, SnippetProvider};
6060
pub use checkstyle::{footer as checkstyle_footer, header as checkstyle_header};
6161
pub use config::summary::Summary;
6262
pub use config::{
63-
load_config, CliOptions, Color, Config, EmitMode, FileLines, FileName, Range, Verbosity,
63+
load_config, CliOptions, Color, Config, EmitMode, FileLines, FileName, NewlineStyle, Range,
64+
Verbosity,
6465
};
6566

6667
#[macro_use]
@@ -132,6 +133,9 @@ pub enum ErrorKind {
132133
/// An io error during reading or writing.
133134
#[fail(display = "io error: {}", _0)]
134135
IoError(io::Error),
136+
/// Parse error occured when parsing the Input.
137+
#[fail(display = "parse error")]
138+
ParseError,
135139
/// The user mandated a version and the current version of Rustfmt does not
136140
/// satisfy that requirement.
137141
#[fail(display = "Version mismatch")]
@@ -172,9 +176,10 @@ impl FormattingError {
172176
}
173177
fn msg_prefix(&self) -> &str {
174178
match self.kind {
175-
ErrorKind::LineOverflow(..) | ErrorKind::TrailingWhitespace | ErrorKind::IoError(_) => {
176-
"internal error:"
177-
}
179+
ErrorKind::LineOverflow(..)
180+
| ErrorKind::TrailingWhitespace
181+
| ErrorKind::IoError(_)
182+
| ErrorKind::ParseError => "internal error:",
178183
ErrorKind::LicenseCheck | ErrorKind::BadAttr | ErrorKind::VersionMismatch => "error:",
179184
ErrorKind::BadIssue(_) | ErrorKind::DeprecatedAttr => "warning:",
180185
}
@@ -832,7 +837,7 @@ fn format_input_inner<T: Write>(
832837
ParseError::Recovered => {}
833838
}
834839
summary.add_parsing_error();
835-
return Ok((summary, FileMap::new(), FormatReport::new()));
840+
return Err((ErrorKind::ParseError, summary));
836841
}
837842
};
838843

@@ -861,6 +866,7 @@ fn format_input_inner<T: Write>(
861866
filemap::append_newline(file);
862867

863868
format_lines(file, file_name, skipped_range, config, report);
869+
replace_with_system_newlines(file, config);
864870

865871
if let Some(ref mut out) = out {
866872
return filemap::write_file(file, file_name, out, config);
@@ -913,6 +919,34 @@ fn format_input_inner<T: Write>(
913919
}
914920
}
915921

922+
pub fn replace_with_system_newlines(text: &mut String, config: &Config) -> () {
923+
let style = if config.newline_style() == NewlineStyle::Native {
924+
if cfg!(windows) {
925+
NewlineStyle::Windows
926+
} else {
927+
NewlineStyle::Unix
928+
}
929+
} else {
930+
config.newline_style()
931+
};
932+
933+
match style {
934+
NewlineStyle::Unix => return,
935+
NewlineStyle::Windows => {
936+
let mut transformed = String::with_capacity(text.capacity());
937+
for c in text.chars() {
938+
match c {
939+
'\n' => transformed.push_str("\r\n"),
940+
'\r' => continue,
941+
c => transformed.push(c),
942+
}
943+
}
944+
*text = transformed;
945+
}
946+
NewlineStyle::Native => unreachable!(),
947+
}
948+
}
949+
916950
/// A single span of changed lines, with 0 or more removed lines
917951
/// and a vector of 0 or more inserted lines.
918952
#[derive(Debug, PartialEq, Eq)]

src/test/mod.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::str::Chars;
2222

2323
use config::summary::Summary;
2424
use config::{Color, Config, ReportTactic};
25-
use filemap::write_system_newlines;
2625
use rustfmt_diff::*;
2726
use *;
2827

@@ -401,14 +400,9 @@ fn idempotent_check(
401400
}
402401

403402
let mut write_result = HashMap::new();
404-
for &(ref filename, ref text) in &file_map {
405-
let mut v = Vec::new();
406-
// Won't panic, as we're not doing any IO.
407-
write_system_newlines(&mut v, text, &config).unwrap();
408-
// Won't panic, we are writing correct utf8.
409-
let one_result = String::from_utf8(v).unwrap();
410-
if let FileName::Real(ref filename) = *filename {
411-
write_result.insert(filename.to_owned(), one_result);
403+
for (filename, text) in file_map {
404+
if let FileName::Real(ref filename) = filename {
405+
write_result.insert(filename.to_owned(), text);
412406
}
413407
}
414408

0 commit comments

Comments
 (0)