commit
b37e78974c
3 changed files with 169 additions and 4 deletions
|
|
@ -9,6 +9,10 @@ readme = "README.md"
|
|||
license = "Apache-2.0/MIT"
|
||||
include = ["src/*.rs", "Cargo.toml"]
|
||||
|
||||
[features]
|
||||
default = ["cargo-fmt"]
|
||||
cargo-fmt = []
|
||||
|
||||
[dependencies]
|
||||
toml = "0.1.20"
|
||||
rustc-serialize = "0.3.14"
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -21,14 +21,21 @@ or if you're using [`multirust`](https://github.com/brson/multirust)
|
|||
multirust run nightly cargo install --git https://github.com/rust-lang-nursery/rustfmt
|
||||
```
|
||||
|
||||
Usually cargo-fmt, which enables usage of Cargo subcommand `cargo fmt`, is
|
||||
installed alongside rustfmt. To only install rustfmt run
|
||||
|
||||
```
|
||||
cargo install --no-default-features --git https://github.com/rust-lang-nursery/rustfmt
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
You can run Rustfmt by just typing `rustfmt filename` if you used `Cargo
|
||||
You can run Rustfmt by just typing `rustfmt filename` if you used `cargo
|
||||
install`. This runs rustfmt on the given file, if the file includes out of line
|
||||
modules, then we reformat those too. So to run on a whole module or crate, you
|
||||
just need to run on the root file (usually mod.rs or lib.rs). Rustfmt can also
|
||||
read data from stdin.
|
||||
read data from stdin. Alternatively, you can use `cargo fmt` to format all
|
||||
binary and library targets of your crate.
|
||||
|
||||
You'll probably want to specify the write mode. Currently, there are modes for
|
||||
replace, overwrite, display, and coverage. The replace mode is the default
|
||||
|
|
@ -42,6 +49,7 @@ screen, for example.
|
|||
|
||||
You can run `rustfmt --help` for more information.
|
||||
|
||||
`cargo fmt` uses `--write-mode=overwrite` by default.
|
||||
|
||||
## Running Rustfmt from your editor
|
||||
|
||||
|
|
@ -59,8 +67,8 @@ First make sure you've got Rust **1.4.0** or greater available, then:
|
|||
|
||||
`cargo test` to run all tests.
|
||||
|
||||
To run rustfmt after this, use `cargo run -- filename`. See the notes above on
|
||||
running rustfmt.
|
||||
To run rustfmt after this, use `cargo run --bin rustfmt -- filename`. See the
|
||||
notes above on running rustfmt.
|
||||
|
||||
|
||||
## What style does Rustfmt use?
|
||||
|
|
|
|||
153
src/bin/cargo-fmt.rs
Normal file
153
src/bin/cargo-fmt.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)
|
||||
|
||||
#![cfg(not(test))]
|
||||
#![cfg(feature="cargo-fmt")]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::env;
|
||||
use std::str;
|
||||
|
||||
use getopts::Options;
|
||||
use rustc_serialize::json::Json;
|
||||
|
||||
fn main() {
|
||||
let mut opts = getopts::Options::new();
|
||||
opts.optflag("h", "help", "show this message");
|
||||
|
||||
let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
print_usage(&opts, &e.to_string());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("h") {
|
||||
print_usage(&opts, "");
|
||||
} else {
|
||||
format_crate(&opts);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_usage(opts: &Options, reason: &str) {
|
||||
let msg = format!("{}\nusage: cargo fmt [options]", reason);
|
||||
println!("{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
|
||||
Arguments after `--` are passes to rustfmt.",
|
||||
opts.usage(&msg));
|
||||
}
|
||||
|
||||
fn format_crate(opts: &Options) {
|
||||
let targets = match get_targets() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
print_usage(opts, &e.to_string());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Currently only bin and lib files get formatted
|
||||
let files: Vec<_> = targets.into_iter()
|
||||
.filter(|t| t.kind.is_lib() | t.kind.is_bin())
|
||||
.map(|t| t.path)
|
||||
.collect();
|
||||
|
||||
format_files(&files, &get_fmt_args()).unwrap_or_else(|e| print_usage(opts, &e.to_string()));
|
||||
}
|
||||
|
||||
fn get_fmt_args() -> Vec<String> {
|
||||
let mut args = vec!["--write-mode=overwrite".to_string()];
|
||||
// All arguments after -- are passed to rustfmt
|
||||
args.extend(env::args().skip_while(|a| a != "--").skip(1));
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TargetKind {
|
||||
Lib, // dylib, staticlib, lib
|
||||
Bin, // bin
|
||||
Other, // test, plugin,...
|
||||
}
|
||||
|
||||
impl TargetKind {
|
||||
fn is_lib(&self) -> bool {
|
||||
match self {
|
||||
&TargetKind::Lib => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_bin(&self) -> bool {
|
||||
match self {
|
||||
&TargetKind::Bin => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Target {
|
||||
path: PathBuf,
|
||||
kind: TargetKind,
|
||||
}
|
||||
|
||||
// Returns a vector of all compile targets of a crate
|
||||
fn get_targets() -> Result<Vec<Target>, std::io::Error> {
|
||||
let mut targets: Vec<Target> = vec![];
|
||||
let output = try!(Command::new("cargo").arg("read-manifest").output());
|
||||
if output.status.success() {
|
||||
// None of the unwraps should fail if output of `cargo read-manifest` is correct
|
||||
let data = &String::from_utf8(output.stdout).unwrap();
|
||||
let json = Json::from_str(data).unwrap();
|
||||
let jtargets = json.find("targets").unwrap().as_array().unwrap();
|
||||
for jtarget in jtargets {
|
||||
targets.push(target_from_json(jtarget));
|
||||
}
|
||||
|
||||
Ok(targets)
|
||||
} else {
|
||||
// This happens when cargo-fmt is not used inside a crate
|
||||
Err(std::io::Error::new(std::io::ErrorKind::NotFound,
|
||||
str::from_utf8(&output.stderr).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
fn target_from_json(jtarget: &Json) -> Target {
|
||||
let jtarget = jtarget.as_object().unwrap();
|
||||
let path = PathBuf::from(jtarget.get("src_path").unwrap().as_string().unwrap());
|
||||
let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
|
||||
let kind = match kinds[0].as_string().unwrap() {
|
||||
"bin" => TargetKind::Bin,
|
||||
"lib" | "dylib" | "staticlib" => TargetKind::Lib,
|
||||
_ => TargetKind::Other,
|
||||
};
|
||||
|
||||
Target {
|
||||
path: path,
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_files(files: &Vec<PathBuf>, fmt_args: &Vec<String>) -> Result<(), std::io::Error> {
|
||||
let mut command = try!(Command::new("rustfmt")
|
||||
.args(files)
|
||||
.args(fmt_args)
|
||||
.spawn());
|
||||
try!(command.wait());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue