2 use std::io::{self, Write};
5 use syntax::source_map::SourceMap;
7 use crate::checkstyle::output_checkstyle_file;
8 use crate::config::{Config, EmitMode, FileName, Verbosity};
9 use crate::rustfmt_diff::{make_diff, print_diff, ModifiedLines};
12 use crate::formatting::FileRecord;
14 // Append a newline to the end of each file.
15 pub(crate) fn append_newline(s: &mut String) {
20 pub(crate) fn write_all_files<T>(
21 source_file: &[FileRecord],
24 ) -> Result<(), io::Error>
28 if config.emit_mode() == EmitMode::Checkstyle {
29 write!(out, "{}", crate::checkstyle::header())?;
31 for &(ref filename, ref text) in source_file {
32 write_file(None, filename, text, out, config)?;
34 if config.emit_mode() == EmitMode::Checkstyle {
35 write!(out, "{}", crate::checkstyle::footer())?;
41 pub(crate) fn write_file<T>(
42 source_map: Option<&SourceMap>,
47 ) -> Result<bool, io::Error>
51 fn ensure_real_path(filename: &FileName) -> &Path {
53 FileName::Real(ref path) => path,
54 _ => panic!("cannot format `{}` and emit to files", filename),
58 impl From<&FileName> for syntax_pos::FileName {
59 fn from(filename: &FileName) -> syntax_pos::FileName {
61 FileName::Real(path) => syntax_pos::FileName::Real(path.to_owned()),
62 FileName::Stdin => syntax_pos::FileName::Custom("stdin".to_owned()),
67 // If parse session is around (cfg(not(test))) then try getting source from
68 // there instead of hitting the file system. This also supports getting
69 // original text for `FileName::Stdin`.
70 let original_text = source_map
71 .and_then(|x| x.get_source_file(&filename.into()))
72 .and_then(|x| x.src.as_ref().map(ToString::to_string));
73 let original_text = match original_text {
75 None => fs::read_to_string(ensure_real_path(filename))?,
78 match config.emit_mode() {
79 EmitMode::Files if config.make_backup() => {
80 let filename = ensure_real_path(filename);
81 if original_text != formatted_text {
82 // Do a little dance to make writing safer - write to a temp file
83 // rename the original to a .bk, then rename the temp file to the
85 let tmp_name = filename.with_extension("tmp");
86 let bk_name = filename.with_extension("bk");
88 fs::write(&tmp_name, formatted_text)?;
89 fs::rename(filename, bk_name)?;
90 fs::rename(tmp_name, filename)?;
94 // Write text directly over original file if there is a diff.
95 let filename = ensure_real_path(filename);
97 if original_text != formatted_text {
98 fs::write(filename, formatted_text)?;
101 EmitMode::Stdout | EmitMode::Coverage => {
102 if config.verbose() != Verbosity::Quiet {
103 println!("{}:\n", filename);
105 write!(out, "{}", formatted_text)?;
107 EmitMode::ModifiedLines => {
108 let mismatch = make_diff(&original_text, formatted_text, 0);
109 let has_diff = !mismatch.is_empty();
110 write!(out, "{}", ModifiedLines::from(mismatch))?;
113 EmitMode::Checkstyle => {
114 let filename = ensure_real_path(filename);
116 let diff = make_diff(&original_text, formatted_text, 3);
117 output_checkstyle_file(out, filename, diff)?;
120 let mismatch = make_diff(&original_text, formatted_text, 3);
121 let has_diff = !mismatch.is_empty();
124 |line_num| format!("Diff in {} at line {}:", filename, line_num),
131 // when we are not in diff mode, don't indicate differing files