rust/src/lib.rs

1044 lines
34 KiB
Rust
Raw Normal View History

// Copyright 2015-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(custom_attribute)]
#![feature(decl_macro)]
#![feature(match_default_bindings)]
#![feature(type_ascription)]
2015-04-13 20:00:46 -05:00
2017-11-06 06:44:59 -06:00
#[macro_use]
extern crate derive_new;
2017-08-08 10:16:35 -05:00
extern crate diff;
#[macro_use]
extern crate log;
2017-08-08 10:16:35 -05:00
extern crate regex;
extern crate rustc_errors as errors;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
2017-08-08 10:16:35 -05:00
extern crate syntax;
extern crate term;
extern crate toml;
2017-08-08 10:16:35 -05:00
extern crate unicode_segmentation;
2015-09-03 22:38:12 -05:00
use std::collections::HashMap;
use std::fmt;
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
use std::io::{self, stdout, BufRead, Write};
use std::iter::repeat;
use std::path::PathBuf;
2016-03-01 16:27:19 -06:00
use std::rc::Rc;
2017-11-17 07:21:46 -06:00
use std::time::Duration;
use errors::{DiagnosticBuilder, Handler};
use errors::emitter::{ColorConfig, EmitterWriter};
use syntax::ast;
2017-09-17 01:32:00 -05:00
use syntax::codemap::{CodeMap, FilePathMapping};
pub use syntax::codemap::FileName;
use syntax::parse::{self, ParseSess};
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
use regex::{Regex, RegexBuilder};
use checkstyle::{output_footer, output_header};
use comment::{CharClasses, FullCodeCharKind};
use issues::{BadIssueSeeker, Issue};
use shape::Indent;
use utils::use_colored_tty;
use visitor::{FmtVisitor, SnippetProvider};
2018-02-07 08:15:00 -06:00
pub use config::Config;
pub use config::summary::Summary;
2015-06-08 13:23:24 -05:00
#[macro_use]
mod utils;
2018-02-17 10:06:54 -06:00
2018-02-23 07:30:05 -06:00
mod attr;
mod chains;
mod checkstyle;
2017-11-12 20:26:33 -06:00
mod closures;
pub mod codemap;
mod comment;
pub mod config;
2015-04-21 04:01:19 -05:00
mod expr;
pub mod filemap;
2015-04-21 04:01:19 -05:00
mod imports;
mod issues;
mod items;
mod lists;
2015-09-14 15:53:30 -05:00
mod macros;
mod missed_spans;
pub mod modules;
2015-10-17 08:56:53 -05:00
mod patterns;
2018-02-17 10:06:54 -06:00
mod reorder;
mod rewrite;
pub mod rustfmt_diff;
mod shape;
mod spanned;
mod string;
mod types;
mod vertical;
pub mod visitor;
2018-02-22 18:07:35 -06:00
const STDIN: &str = "<stdin>";
2018-02-07 07:48:05 -06:00
// A map of the files of a crate, with their new content
pub type FileMap = Vec<FileRecord>;
pub type FileRecord = (FileName, String);
#[derive(Clone, Copy)]
pub enum ErrorKind {
// Line has exceeded character limit (found, maximum)
LineOverflow(usize, usize),
// Line ends in whitespace
TrailingWhitespace,
// TO-DO or FIX-ME item without an issue number
BadIssue(Issue),
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
// License check has failed
LicenseCheck,
// License template could not be parsed
ParsingLicense,
}
impl fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
2017-07-11 07:53:10 -05:00
ErrorKind::LineOverflow(found, maximum) => write!(
fmt,
"line exceeded maximum width (maximum: {}, found: {})",
2017-11-30 22:30:21 -06:00
maximum, found
2017-07-11 07:53:10 -05:00
),
ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
ErrorKind::LicenseCheck => write!(fmt, "license check failed"),
ErrorKind::ParsingLicense => write!(fmt, "parsing regex in license template failed"),
}
}
}
// Formatting errors that are identified *after* rustfmt has run.
pub struct FormattingError {
line: usize,
kind: ErrorKind,
is_comment: bool,
is_string: bool,
line_buffer: String,
}
impl FormattingError {
fn msg_prefix(&self) -> &str {
match self.kind {
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
ErrorKind::LineOverflow(..)
| ErrorKind::TrailingWhitespace
| ErrorKind::LicenseCheck
| ErrorKind::ParsingLicense => "error:",
ErrorKind::BadIssue(_) => "WARNING:",
}
}
fn msg_suffix(&self) -> &str {
if self.is_comment || self.is_string {
"set `error_on_unformatted = false` to suppress \
the warning against comments or string literals\n"
} else {
""
}
}
// (space, target)
pub fn format_len(&self) -> (usize, usize) {
match self.kind {
ErrorKind::LineOverflow(found, max) => (max, found - max),
ErrorKind::TrailingWhitespace => {
let trailing_ws_len = self.line_buffer
.chars()
.rev()
.take_while(|c| c.is_whitespace())
.count();
(self.line_buffer.len() - trailing_ws_len, trailing_ws_len)
}
_ => unreachable!(),
}
}
}
pub struct FormatReport {
// Maps stringified file paths to their associated formatting errors.
file_error_map: HashMap<FileName, Vec<FormattingError>>,
}
impl FormatReport {
fn new() -> FormatReport {
2017-07-03 04:54:26 -05:00
FormatReport {
file_error_map: HashMap::new(),
}
}
pub fn warning_count(&self) -> usize {
self.file_error_map
.iter()
.map(|(_, errors)| errors.len())
2018-01-25 23:53:28 -06:00
.sum()
}
pub fn has_warnings(&self) -> bool {
self.warning_count() > 0
}
pub fn print_warnings_fancy(
&self,
mut t: Box<term::Terminal<Output = io::Stderr>>,
) -> Result<(), term::Error> {
for (file, errors) in &self.file_error_map {
for error in errors {
let prefix_space_len = error.line.to_string().len();
let prefix_spaces: String = repeat(" ").take(1 + prefix_space_len).collect();
// First line: the overview of error
t.fg(term::color::RED)?;
t.attr(term::Attr::Bold)?;
write!(t, "{} ", error.msg_prefix())?;
t.reset()?;
t.attr(term::Attr::Bold)?;
write!(t, "{}\n", error.kind)?;
// Second line: file info
write!(t, "{}--> ", &prefix_spaces[1..])?;
t.reset()?;
write!(t, "{}:{}\n", file, error.line)?;
// Third to fifth lines: show the line which triggered error, if available.
if !error.line_buffer.is_empty() {
let (space_len, target_len) = error.format_len();
t.attr(term::Attr::Bold)?;
write!(t, "{}|\n{} | ", prefix_spaces, error.line)?;
t.reset()?;
write!(t, "{}\n", error.line_buffer)?;
t.attr(term::Attr::Bold)?;
write!(t, "{}| ", prefix_spaces)?;
t.fg(term::color::RED)?;
write!(t, "{}\n", target_str(space_len, target_len))?;
t.reset()?;
}
// The last line: show note if available.
let msg_suffix = error.msg_suffix();
if !msg_suffix.is_empty() {
t.attr(term::Attr::Bold)?;
write!(t, "{}= note: ", prefix_spaces)?;
t.reset()?;
write!(t, "{}\n", error.msg_suffix())?;
} else {
write!(t, "\n")?;
}
t.reset()?;
}
}
if !self.file_error_map.is_empty() {
t.attr(term::Attr::Bold)?;
write!(t, "warning: ")?;
t.reset()?;
write!(
t,
"rustfmt may have failed to format. See previous {} errors.\n\n",
self.warning_count(),
)?;
}
Ok(())
}
}
fn target_str(space_len: usize, target_len: usize) -> String {
let empty_line: String = repeat(" ").take(space_len).collect();
let overflowed: String = repeat("^").take(target_len).collect();
empty_line + &overflowed
}
impl fmt::Display for FormatReport {
// Prints all the formatting errors.
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
2015-09-04 16:39:33 -05:00
for (file, errors) in &self.file_error_map {
for error in errors {
let prefix_space_len = error.line.to_string().len();
let prefix_spaces: String = repeat(" ").take(1 + prefix_space_len).collect();
let error_line_buffer = if error.line_buffer.is_empty() {
String::from(" ")
} else {
let (space_len, target_len) = error.format_len();
format!(
"{}|\n{} | {}\n{}| {}",
prefix_spaces,
error.line,
error.line_buffer,
prefix_spaces,
target_str(space_len, target_len)
)
};
let error_info = format!("{} {}", error.msg_prefix(), error.kind);
let file_info = format!("{}--> {}:{}", &prefix_spaces[1..], file, error.line);
let msg_suffix = error.msg_suffix();
let note = if msg_suffix.is_empty() {
String::new()
} else {
format!("{}note= ", prefix_spaces)
};
write!(
fmt,
"{}\n{}\n{}\n{}{}\n",
error_info,
file_info,
error_line_buffer,
note,
error.msg_suffix()
)?;
}
}
if !self.file_error_map.is_empty() {
write!(
fmt,
"warning: rustfmt may have failed to format. See previous {} errors.\n",
self.warning_count(),
)?;
}
Ok(())
}
}
fn should_emit_verbose<F>(path: &FileName, config: &Config, f: F)
where
F: Fn(),
{
if config.verbose() && path.to_string() != STDIN {
f();
}
}
// Formatting which depends on the AST.
fn format_ast<F>(
krate: &ast::Crate,
2017-08-11 03:54:38 -05:00
parse_session: &mut ParseSess,
main_file: &FileName,
config: &Config,
mut after_file: F,
) -> Result<(FileMap, bool), io::Error>
where
F: FnMut(&FileName, &mut String, &[(usize, usize)]) -> Result<bool, io::Error>,
{
let mut result = FileMap::new();
// diff mode: check if any files are differing
let mut has_diff = false;
// We always skip children for the "Plain" write mode, since there is
// nothing to distinguish the nested module contents.
let skip_children = config.skip_children() || config.write_mode() == config::WriteMode::Plain;
2017-11-06 06:45:54 -06:00
for (path, module) in modules::list_files(krate, parse_session.codemap())? {
if skip_children && path != *main_file {
continue;
}
should_emit_verbose(&path, config, || println!("Formatting {}", path));
let filemap = parse_session
.codemap()
.lookup_char_pos(module.inner.lo())
.file;
let big_snippet = filemap.src.as_ref().unwrap();
let snippet_provider = SnippetProvider::new(filemap.start_pos, big_snippet);
let mut visitor = FmtVisitor::from_codemap(parse_session, config, &snippet_provider);
2017-08-29 22:00:10 -05:00
// Format inner attributes if available.
if !krate.attrs.is_empty() && path == *main_file {
visitor.skip_empty_lines(filemap.end_pos);
if visitor.visit_attrs(&krate.attrs, ast::AttrStyle::Inner) {
visitor.push_rewrite(module.inner, None);
} else {
visitor.format_separate_mod(module, &*filemap);
}
2017-08-29 22:00:10 -05:00
} else {
visitor.last_pos = filemap.start_pos;
visitor.skip_empty_lines(filemap.end_pos);
visitor.format_separate_mod(module, &*filemap);
};
2018-02-18 21:50:39 -06:00
debug_assert_eq!(
2017-12-08 01:59:04 -06:00
visitor.line_number,
::utils::count_newlines(&format!("{}", visitor.buffer))
);
let filename = path.clone();
has_diff |= match after_file(&filename, &mut visitor.buffer, &visitor.skipped_range) {
Ok(result) => result,
Err(e) => {
// Create a new error with path_str to help users see which files failed
let err_msg = format!("{}: {}", path, e);
return Err(io::Error::new(e.kind(), err_msg));
}
};
result.push((filename, visitor.buffer));
}
Ok((result, has_diff))
}
/// Returns true if the line with the given line number was skipped by `#[rustfmt_skip]`.
fn is_skipped_line(line_number: usize, skipped_range: &[(usize, usize)]) -> bool {
skipped_range
.iter()
.any(|&(lo, hi)| lo <= line_number && line_number <= hi)
}
fn should_report_error(
config: &Config,
char_kind: FullCodeCharKind,
is_string: bool,
error_kind: ErrorKind,
) -> bool {
let allow_error_report = if char_kind.is_comment() || is_string {
config.error_on_unformatted()
} else {
true
};
match error_kind {
ErrorKind::LineOverflow(..) => config.error_on_line_overflow() && allow_error_report,
ErrorKind::TrailingWhitespace => allow_error_report,
_ => true,
}
}
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
fn check_license(text: &str, license_template: &str) -> Result<bool, regex::Error> {
let mut template_re = String::from("^");
// the template is parsed as a series of pairs of capture groups of (1) lazy whatever, which
// will be matched literally, followed by (2) a {}-delimited block, which will be matched as a
// regex
let template_parser = RegexBuilder::new(r"(.*?)\{(.*?)\}")
.dot_matches_new_line(true)
.build()
.unwrap();
// keep track of the last matched offset and ultimately append the tail of the template (if any)
// after the last {} block
let mut last_matched_offset = 0;
for caps in template_parser.captures_iter(license_template) {
if let Some(mat) = caps.get(0) {
last_matched_offset = mat.end()
}
if let Some(mat) = caps.get(1) {
template_re.push_str(&regex::escape(mat.as_str()))
}
if let Some(mat) = caps.get(2) {
let mut re = mat.as_str();
if re.is_empty() {
re = ".*?";
}
template_re.push_str(re)
}
}
template_re.push_str(&regex::escape(&license_template[last_matched_offset..]));
let template_re = Regex::new(&template_re)?;
Ok(template_re.is_match(text))
}
2015-04-21 05:50:43 -05:00
// Formatting done on a char by char or line by line basis.
// FIXME(#20) other stuff for parity with make tidy
fn format_lines(
2017-12-10 02:40:51 -06:00
text: &mut String,
name: &FileName,
skipped_range: &[(usize, usize)],
config: &Config,
report: &mut FormatReport,
) {
let mut trims = vec![];
let mut last_wspace: Option<usize> = None;
let mut line_len = 0;
let mut cur_line = 1;
let mut newline_count = 0;
let mut errors = vec![];
let mut issue_seeker = BadIssueSeeker::new(config.report_todo(), config.report_fixme());
let mut line_buffer = String::with_capacity(config.max_width() * 2);
let mut is_string = false; // true if the current line contains a string literal.
let mut format_line = config.file_lines().contains_line(name, cur_line);
2018-02-18 21:50:39 -06:00
let allow_issue_seek = !issue_seeker.is_disabled();
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
// Check license.
if config.was_set().license_template() {
match check_license(text, &config.license_template()) {
Ok(check) => {
if !check {
errors.push(FormattingError {
line: cur_line,
kind: ErrorKind::LicenseCheck,
is_comment: false,
is_string: false,
line_buffer: String::new(),
});
}
}
Err(_) => {
errors.push(FormattingError {
line: cur_line,
kind: ErrorKind::ParsingLicense,
is_comment: false,
is_string: false,
line_buffer: String::new(),
});
}
}
}
// Iterate over the chars in the file map.
2017-12-10 20:50:11 -06:00
for (kind, (b, c)) in CharClasses::new(text.chars().enumerate()) {
if c == '\r' {
continue;
}
2018-02-18 21:50:39 -06:00
if allow_issue_seek && format_line {
// Add warnings for bad todos/ fixmes
if let Some(issue) = issue_seeker.inspect(c) {
2015-09-26 01:29:48 -05:00
errors.push(FormattingError {
line: cur_line,
kind: ErrorKind::BadIssue(issue),
is_comment: false,
is_string: false,
line_buffer: String::new(),
});
}
}
if c == '\n' {
if format_line {
// Check for (and record) trailing whitespace.
if let Some(..) = last_wspace {
if should_report_error(config, kind, is_string, ErrorKind::TrailingWhitespace) {
trims.push((cur_line, kind, line_buffer.clone()));
}
line_len -= 1;
}
// Check for any line width errors we couldn't correct.
let error_kind = ErrorKind::LineOverflow(line_len, config.max_width());
if line_len > config.max_width() && !is_skipped_line(cur_line, skipped_range)
&& should_report_error(config, kind, is_string, error_kind)
{
errors.push(FormattingError {
line: cur_line,
kind: error_kind,
is_comment: kind.is_comment(),
2018-01-21 22:05:18 -06:00
is_string,
line_buffer: line_buffer.clone(),
});
}
}
line_len = 0;
cur_line += 1;
format_line = config.file_lines().contains_line(name, cur_line);
newline_count += 1;
last_wspace = None;
line_buffer.clear();
is_string = false;
} else {
newline_count = 0;
line_len += if c == '\t' { config.tab_spaces() } else { 1 };
if c.is_whitespace() {
if last_wspace.is_none() {
last_wspace = Some(b);
}
} else {
last_wspace = None;
}
line_buffer.push(c);
if kind.is_string() {
is_string = true;
}
}
}
if newline_count > 1 {
2017-12-10 02:40:51 -06:00
debug!("track truncate: {} {}", text.len(), newline_count);
let line = text.len() - newline_count + 1;
text.truncate(line);
}
2015-04-23 01:02:55 -05:00
for &(l, kind, ref b) in &trims {
if !is_skipped_line(l, skipped_range) {
errors.push(FormattingError {
line: l,
kind: ErrorKind::TrailingWhitespace,
is_comment: kind.is_comment(),
is_string: kind.is_string(),
line_buffer: b.clone(),
});
}
2015-04-23 01:02:55 -05:00
}
report.file_error_map.insert(name.clone(), errors);
}
fn parse_input<'sess>(
input: Input,
parse_session: &'sess ParseSess,
config: &Config,
) -> Result<ast::Crate, Option<DiagnosticBuilder<'sess>>> {
let result = match input {
Input::File(file) => {
let mut parser = parse::new_parser_from_file(parse_session, &file);
parser.cfg_mods = false;
if config.skip_children() {
parser.recurse_into_file_modules = false;
}
parser.parse_crate_mod()
}
2016-04-11 11:49:56 -05:00
Input::Text(text) => {
let mut parser = parse::new_parser_from_source_str(
parse_session,
FileName::Custom("stdin".to_owned()),
text,
);
parser.cfg_mods = false;
if config.skip_children() {
parser.recurse_into_file_modules = false;
}
parser.parse_crate_mod()
2016-04-11 11:49:56 -05:00
}
};
2016-05-17 16:58:51 -05:00
match result {
Ok(c) => {
if parse_session.span_diagnostic.has_errors() {
// Bail out if the parser recovered from an error.
Err(None)
} else {
Ok(c)
}
}
Err(e) => Err(Some(e)),
}
}
/// Format the given snippet. The snippet is expected to be *complete* code.
/// When we cannot parse the given snippet, this function returns `None`.
pub fn format_snippet(snippet: &str, config: &Config) -> Option<String> {
let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
let input = Input::Text(snippet.into());
let mut config = config.clone();
config.set().write_mode(config::WriteMode::Plain);
2018-01-11 00:19:23 -06:00
config.set().hide_parse_errors(true);
match format_input(input, &config, Some(&mut out)) {
// `format_input()` returns an empty string on parsing error.
Ok(..) if out.is_empty() && !snippet.is_empty() => None,
Ok(..) => String::from_utf8(out).ok(),
Err(..) => None,
}
}
/// Format the given code block. Mainly targeted for code block in comment.
/// The code block may be incomplete (i.e. parser may be unable to parse it).
/// To avoid panic in parser, we wrap the code block with a dummy function.
/// The returned code block does *not* end with newline.
pub fn format_code_block(code_snippet: &str, config: &Config) -> Option<String> {
// Wrap the given code block with `fn main()` if it does not have one.
let fn_main_prefix = "fn main() {\n";
let snippet = fn_main_prefix.to_owned() + code_snippet + "\n}";
let mut result = String::with_capacity(snippet.len());
let mut is_first = true;
// Trim "fn main() {" on the first line and "}" on the last line,
// then unindent the whole code block.
let formatted = format_snippet(&snippet, config)?;
// 2 = "}\n"
let block_len = formatted.len().checked_sub(2).unwrap_or(0);
for line in formatted[fn_main_prefix.len()..block_len].lines() {
if !is_first {
result.push('\n');
} else {
is_first = false;
}
let trimmed_line = if line.len() > config.max_width() {
// If there are lines that are larger than max width, we cannot tell
// whether we have succeeded but have some comments or strings that
// are too long, or we have failed to format code block. We will be
// conservative and just return `None` in this case.
return None;
} else if line.len() > config.tab_spaces() {
// Make sure that the line has leading whitespaces.
let indent_str = Indent::from_width(config, config.tab_spaces()).to_string(config);
if line.starts_with(indent_str.as_ref()) {
let offset = if config.hard_tabs() {
1
} else {
config.tab_spaces()
};
&line[offset..]
} else {
line
}
} else {
line
};
result.push_str(trimmed_line);
}
Some(result)
}
pub fn format_input<T: Write>(
input: Input,
config: &Config,
mut out: Option<&mut T>,
) -> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> {
2017-08-29 08:16:04 -05:00
let mut summary = Summary::default();
if config.disable_all_formatting() {
// When the input is from stdin, echo back the input.
if let Input::Text(ref buf) = input {
if let Err(e) = io::stdout().write_all(buf.as_bytes()) {
return Err((e, summary));
}
}
return Ok((summary, FileMap::new(), FormatReport::new()));
}
let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
2016-03-01 16:27:19 -06:00
let tty_handler = if config.hide_parse_errors() {
let silent_emitter = Box::new(EmitterWriter::new(
Box::new(Vec::new()),
Some(codemap.clone()),
false,
2018-02-01 19:18:30 -06:00
false,
));
Handler::with_emitter(true, false, silent_emitter)
} else {
let supports_color = term::stderr().map_or(false, |term| term.supports_color());
let color_cfg = if supports_color {
ColorConfig::Auto
} else {
ColorConfig::Never
};
Handler::with_tty_emitter(color_cfg, true, false, Some(codemap.clone()))
};
2016-03-01 16:27:19 -06:00
let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
2016-04-11 11:49:56 -05:00
let main_file = match input {
Input::File(ref file) => FileName::Real(file.clone()),
Input::Text(..) => FileName::Custom("stdin".to_owned()),
2016-04-11 11:49:56 -05:00
};
let krate = match parse_input(input, &parse_session, config) {
2016-04-11 11:49:56 -05:00
Ok(krate) => krate,
Err(diagnostic) => {
if let Some(mut diagnostic) = diagnostic {
diagnostic.emit();
}
summary.add_parsing_error();
return Ok((summary, FileMap::new(), FormatReport::new()));
2016-04-11 11:49:56 -05:00
}
};
summary.mark_parse_time();
if parse_session.span_diagnostic.has_errors() {
summary.add_parsing_error();
}
// Suppress error output after parsing.
let silent_emitter = Box::new(EmitterWriter::new(
Box::new(Vec::new()),
Some(codemap.clone()),
2017-10-20 08:53:06 -05:00
false,
2018-02-01 19:18:30 -06:00
false,
));
2016-03-01 16:27:19 -06:00
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
let mut report = FormatReport::new();
let format_result = format_ast(
2017-05-31 22:08:09 -05:00
&krate,
&mut parse_session,
2017-05-31 22:08:09 -05:00
&main_file,
config,
|file_name, file, skipped_range| {
2017-05-31 22:08:09 -05:00
// For some reason, the codemap does not include terminating
// newlines so we must add one on for each file. This is sad.
filemap::append_newline(file);
format_lines(file, file_name, skipped_range, config, &mut report);
2017-05-31 22:08:09 -05:00
if let Some(ref mut out) = out {
return filemap::write_file(file, file_name, out, config);
}
Ok(false)
2017-06-03 08:50:44 -05:00
},
);
summary.mark_format_time();
should_emit_verbose(&main_file, config, || {
2017-11-17 07:21:46 -06:00
fn duration_to_f32(d: Duration) -> f32 {
d.as_secs() as f32 + d.subsec_nanos() as f32 / 1_000_000_000f32
}
println!(
2017-11-17 07:21:46 -06:00
"Spent {0:.3} secs in the parsing phase, and {1:.3} secs in the formatting phase",
duration_to_f32(summary.get_parse_time().unwrap()),
duration_to_f32(summary.get_format_time().unwrap()),
)
});
match format_result {
Ok((file_map, has_diff)) => {
if report.has_warnings() {
summary.add_formatting_error();
}
if has_diff {
summary.add_diff();
}
Ok((summary, file_map, report))
}
Err(e) => Err((e, summary)),
}
2016-04-02 13:56:37 -05:00
}
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
/// A single span of changed lines, with 0 or more removed lines
/// and a vector of 0 or more inserted lines.
#[derive(Debug, PartialEq, Eq)]
pub struct ModifiedChunk {
2018-02-12 17:07:46 -06:00
/// The first to be removed from the original text
pub line_number_orig: u32,
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
/// The number of lines which have been replaced
pub lines_removed: u32,
/// The new lines
pub lines: Vec<String>,
}
/// Set of changed sections of a file.
#[derive(Debug, PartialEq, Eq)]
pub struct ModifiedLines {
/// The set of changed chunks.
pub chunks: Vec<ModifiedChunk>,
}
2018-02-22 18:07:35 -06:00
/// The successful result of formatting via `get_modified_lines()`.
pub struct ModifiedLinesResult {
/// The high level summary details
pub summary: Summary,
/// The result Filemap
pub filemap: FileMap,
/// Map of formatting errors
pub report: FormatReport,
/// The sets of updated lines.
pub modified_lines: ModifiedLines,
}
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
/// Format a file and return a `ModifiedLines` data structure describing
/// the changed ranges of lines.
pub fn get_modified_lines(
input: Input,
config: &Config,
) -> Result<ModifiedLinesResult, (io::Error, Summary)> {
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
let mut data = Vec::new();
let mut config = config.clone();
config.set().write_mode(config::WriteMode::Modified);
let (summary, filemap, formatreport) = format_input(input, &config, Some(&mut data))?;
let mut lines = data.lines();
let mut chunks = Vec::new();
while let Some(Ok(header)) = lines.next() {
// Parse the header line
let values: Vec<_> = header
.split(' ')
.map(|s| s.parse::<u32>().unwrap())
.collect();
assert_eq!(values.len(), 3);
2018-02-12 17:07:46 -06:00
let line_number_orig = values[0];
let lines_removed = values[1];
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
let num_added = values[2];
let mut added_lines = Vec::new();
for _ in 0..num_added {
added_lines.push(lines.next().unwrap().unwrap());
}
chunks.push(ModifiedChunk {
2018-02-12 17:07:46 -06:00
line_number_orig,
lines_removed,
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
lines: added_lines,
});
}
Ok(ModifiedLinesResult {
summary: summary,
filemap: filemap,
report: formatreport,
2018-02-12 17:07:46 -06:00
modified_lines: ModifiedLines { chunks },
})
Add a new get_modified_lines() API to get only the new changed lines from rustfmting. Squashed commit of the following: commit e90f9da64bbdb640b8c9ee61c3ad395617d8b4da Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 20:10:16 2018 +0000 Fix tests after merging with master. commit c3af0042769fe459b0c9c94a0934605ea4b40e40 Merge: 03868583 e0e3e222 Author: Chris Emerson <github@mail.nosreme.org> Date: Sat Jan 20 17:45:05 2018 +0000 Merge remote-tracking branch 'origin/master' into HEAD commit 03868583f8555aae30bdfb5839a82afd3704f4cb Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:57:56 2017 +0000 Fix some warnings. commit 162b13463e44c782394d418db5ca5710931beb7a Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:48:02 2017 +0000 Remove unneeded import. commit 20cce3cbfd0f386d92b80bf4c7b83ab4d78a73e7 Merge: 81e98147 fa794f58 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:07:17 2017 +0000 Merge branch 'master' into difflines_mode commit 81e981472ceb3a0938d6f050edf8dcd5ebff8e33 Author: Chris Emerson <github@mail.nosreme.org> Date: Mon Nov 20 01:02:50 2017 +0000 Add a simple "modified lines" test. commit 018390ced3523ca9fdd5384a6c1004cdb99174a9 Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:06:21 2017 +0000 Update test output. commit 7909f4986ed21999aff7b3d075332e686ac464ff Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 23:03:22 2017 +0000 Rerun rustfmt. commit 6275f1a8da52db1df36c4b7432996cdbb94ca463 Merge: 7a66d286 175c0c6f Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:40:29 2017 +0000 Merge remote-tracking branch 'origin/master' into difflines_mode commit 7a66d2866432c430b046938bb37bf5efc03fa9da Author: Chris Emerson <github@mail.nosreme.org> Date: Thu Nov 2 21:36:40 2017 +0000 WIP: Add a separate API to get changed lines. Currently calls format_input() and adjusts the output. commit c8163a923c7d9ae42fd8078cd9b2b51c6f73e36e Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:53:33 2017 +0100 Remove "modified" from the documentation again. commit 94041fa115a6f428afe40e01d41bf2fe603f70bb Merge: acaa3c7c 2adf7eec Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 27 22:47:05 2017 +0100 Merge branch 'master' into difflines_mode commit acaa3c7ce446297cd3fe5c9610763629a2d8537c Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:34:14 2017 +0100 Update the Modified write mode to use `out` instead of just prinln!(). This means we can test it more easily, so do so. commit 9f1bbca1f3c12d933ea823918cc548e69b438b1e Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 23:11:55 2017 +0100 Add "Modified" to the various lists of modes. commit e12f023756cf3daf202dcaa02bd6492b0d2a0455 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:57:33 2017 +0100 Rerun cargo fmt. commit 0f8a43630fa1548e95dcb1c0933708f9c11ae135 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:46:26 2017 +0100 Add `line_number_orig` to instances of `Mismatch` in tests. commit d432a7061f74dbc159584f08470c64985a4b41d9 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:41:40 2017 +0100 Add a `line_number_orig` field to `Mismatch` to track the pre-format line number. Use that for the write-mode=modified output. commit bdb7d1d23f02f7b8f18e7073a65be88ff94cdbb3 Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 22:35:50 2017 +0100 First basic --write-mode=modified implementation. commit ea1433dae0c32879a31182c11be08b1bf53fbf31 Author: Chris Emerson <github@mail.nosreme.org> Date: Fri Oct 20 00:04:16 2017 +0100 WIP on new "modified" mode. commit 27ee9483cf937a11a0e115f54de0afcc3f9ceb44 Merge: e48dd81a 2a84352d Author: Chris Emerson <github@mail.nosreme.org> Date: Tue Oct 24 21:56:44 2017 +0100 Merge remote-tracking branch 'jc/diff_zero_context' into difflines_mode
2018-01-20 14:23:25 -06:00
}
2016-05-25 13:41:26 -05:00
#[derive(Debug)]
2016-04-02 13:56:37 -05:00
pub enum Input {
File(PathBuf),
Text(String),
}
pub fn run(input: Input, config: &Config) -> Summary {
2017-08-11 03:54:38 -05:00
let out = &mut stdout();
output_header(out, config.write_mode()).ok();
match format_input(input, config, Some(out)) {
Ok((summary, _, report)) => {
output_footer(out, config.write_mode()).ok();
if report.has_warnings() {
match term::stderr() {
Some(ref t)
if use_colored_tty(config.color()) && t.supports_color()
2017-11-09 14:23:12 -06:00
&& t.supports_attr(term::Attr::Bold) =>
{
match report.print_warnings_fancy(term::stderr().unwrap()) {
Ok(..) => (),
Err(..) => panic!("Unable to write to stderr: {}", report),
}
}
_ => msg!("{}", report),
}
}
summary
}
Err((msg, mut summary)) => {
msg!("Error writing files: {}", msg);
summary.add_operational_error();
summary
}
}
}
#[cfg(test)]
mod test {
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
use super::{check_license, format_code_block, format_snippet, Config};
#[test]
fn test_no_panic_on_format_snippet_and_format_code_block() {
// `format_snippet()` and `format_code_block()` should not panic
// even when we cannot parse the given snippet.
let snippet = "let";
assert!(format_snippet(snippet, &Config::default()).is_none());
assert!(format_code_block(snippet, &Config::default()).is_none());
}
fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
where
F: Fn(&str, &Config) -> Option<String>,
{
let output = formatter(input, &Config::default());
output.is_some() && output.unwrap() == expected
}
#[test]
fn test_format_snippet() {
let snippet = "fn main() { println!(\"hello, world\"); }";
let expected = "fn main() {\n \
println!(\"hello, world\");\n\
}\n";
assert!(test_format_inner(format_snippet, snippet, expected));
}
#[test]
fn test_format_code_block_fail() {
#[rustfmt_skip]
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
assert!(format_code_block(code_block, &Config::default()).is_none());
}
#[test]
fn test_format_code_block() {
// simple code block
let code_block = "let x=3;";
let expected = "let x = 3;";
assert!(test_format_inner(format_code_block, code_block, expected));
// more complex code block, taken from chains.rs.
let code_block =
"let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
(
chain_indent(context, shape.add_offset(parent_rewrite.len())),
context.config.indent_style() == IndentStyle::Visual || is_small_parent,
)
} else if is_block_expr(context, &parent, &parent_rewrite) {
match context.config.indent_style() {
// Try to put the first child on the same line with parent's last line
IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true),
// The parent is a block, so align the rest of the chain with the closing
// brace.
IndentStyle::Visual => (parent_shape, false),
}
} else {
(
chain_indent(context, shape.add_offset(parent_rewrite.len())),
false,
)
};
";
let expected =
"let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
(
chain_indent(context, shape.add_offset(parent_rewrite.len())),
context.config.indent_style() == IndentStyle::Visual || is_small_parent,
)
} else if is_block_expr(context, &parent, &parent_rewrite) {
match context.config.indent_style() {
// Try to put the first child on the same line with parent's last line
IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true),
// The parent is a block, so align the rest of the chain with the closing
// brace.
IndentStyle::Visual => (parent_shape, false),
}
} else {
(
chain_indent(context, shape.add_offset(parent_rewrite.len())),
false,
)
};";
assert!(test_format_inner(format_code_block, code_block, expected));
}
Attempt at checking for license (#209) I'm not quite sure how best to handle loading the license template from a path -- I mean obviously I know *how* to do it, but I'm not sure where to fit it in the codebase :) So this first attempt puts the license template directly into the config file. These are my misgivings about the license template config option as a path to a file (I'd love feedback if some of these are wrong or can be easily circumvented!): 1. I thought the obvious choice for the type of `license_template` in `create_config!` should be `PathBuf`, but `PathBuf` doesn't implement `FromStr` (yet? see https://github.com/rust-lang/rust/issues/44431), so it would have to be wrapped in a tuple struct, and I went down that road for a little while but then it seemed like too much ceremony for too little gain. 2. So a plain `String` then (which, mind you, also means the same `doc_hint()`, i.e. `<string>`, not `<path>` or something like that). The fact that it's a valid path will be checked once we try to read the file. 3. But where in the code should the license template be read? The obvious choice for me would be somewhere in `Config::from_toml()`, but since `Config` is defined via the `create_config!` macro, that would mean tight coupling between the macro invocation (which defines the configuration option `license_template`) and its definition (which would rely on the existence of that option to run the template loading code). 4. `license_template` could also be made a special option which is hardwired into the macro. This gets rid of the tight coupling, but special-casing one of the config options would make the code harder to navigate. 5. Instead, the macro could maybe be rewritten to allow for config options that load additional resources from files when the config is being parsed, but that's beyond my skill level I'm afraid (and probably overengineering the problem if it's only ever going to be used for this one option). 6. Finally, the file can be loaded at some later point in time, e.g. in `format_lines()`, right before `check_license()` is called. But to face a potential *IO* error at so late a stage, when the source files have already been parsed... I don't know, it doesn't feel right. BTW I don't like that I'm actually parsing the license template as late as inside `check_license()` either, but for much the same reasons, I don't know where else to put it. If the `Config` were hand-rolled instead of a macro, I'd just define a custom `license_template` option and load and parse the template in the `Config`'s init. But the way things are, I'm a bit at a loss. However, if someone more familiar with the project would kindly provide a few hints as to how the path approach can be done in a way that is as clean as possible in the context of the codebase, I'll be more than happy to implement it! :)
2018-02-16 16:21:57 -06:00
#[test]
fn test_check_license() {
assert!(check_license("literal matching", "literal matching").unwrap());
assert!(!check_license("literal no match", "literal matching").unwrap());
assert!(
check_license(
"Regex start and end: 2018",
r"{[Rr]egex} start {} end: {\d+}"
).unwrap()
);
assert!(!check_license(
"Regex start and end no match: 2018",
r"{[Rr]egex} start {} end: {\d+}"
).unwrap());
assert!(
check_license(
"Regex in the middle: 2018 (tm)",
r"Regex {} middle: {\d+} (tm)"
).unwrap()
);
assert!(!check_license(
"Regex in the middle no match: 2018 (tm)",
r"Regex {} middle: {\d+} (tm)"
).unwrap());
assert!(!check_license("default doesn't match\nacross lines", "default {} lines").unwrap());
assert!(check_license("", "this is not a valid {[regex}").is_err());
assert!(
check_license(
"can't parse nested delimiters with regex",
r"can't parse nested delimiters with regex{\.{3}}"
).is_err()
);
}
}