summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs79
-rw-r--r--src/options.rs37
2 files changed, 107 insertions, 9 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e72800c0..431fea0e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,6 +26,7 @@ extern crate peeking_take_while;
extern crate regex;
#[macro_use]
extern crate lazy_static;
+extern crate which;
#[cfg(feature = "logging")]
#[macro_use]
@@ -455,6 +456,16 @@ impl Builder {
);
}
+ if !self.options.format_bindings {
+ output_vector.push("--format-bindings".into());
+ }
+
+ if let Some(path) = self.options.format_configuration_file.as_ref().and_then(
+ |f| f.to_str()) {
+ output_vector.push("--format-configuration-file".into());
+ output_vector.push(path.into());
+ }
+
output_vector
}
@@ -840,6 +851,19 @@ impl Builder {
self
}
+ /// Set whether rustfmt should format the generated bindings.
+ pub fn format_bindings(mut self, doit: bool) -> Self {
+ self.options.format_bindings = doit;
+ self
+ }
+
+ /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt
+ /// options are used.
+ pub fn format_configuration_file(mut self, path: Option<PathBuf>) -> Self {
+ self.options.format_configuration_file = path;
+ self
+ }
+
/// Generate the Rust bindings using the options built up thus far.
pub fn generate<'ctx>(mut self) -> Result<Bindings<'ctx>, ()> {
self.options.input_header = self.input_headers.pop();
@@ -1099,6 +1123,13 @@ pub struct BindgenOptions {
/// Features to enable, derived from `rust_target`
rust_features: RustFeatures,
+
+ /// Whether rustfmt should format the generated bindings.
+ pub format_bindings: bool,
+
+ /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
+ /// options are used.
+ pub format_configuration_file: Option<PathBuf>,
}
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -1183,6 +1214,8 @@ impl Default for BindgenOptions {
objc_extern_crate: false,
enable_mangling: true,
prepend_enum_name: true,
+ format_bindings: true,
+ format_configuration_file: None,
}
}
}
@@ -1334,14 +1367,19 @@ impl<'ctx> Bindings<'ctx> {
/// Write these bindings as source text to a file.
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
- let file = try!(
- OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(path)
- );
- self.write(Box::new(file))
+ {
+ let file = try!(
+ OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(path.as_ref())
+ );
+ self.write(Box::new(file))?;
+ }
+
+ self.format_generated_file(path.as_ref());
+ Ok(())
}
/// Write these bindings as source text to the given `Write`able.
@@ -1364,6 +1402,31 @@ impl<'ctx> Bindings<'ctx> {
try!(eof(&mut ps.s));
ps.s.out.flush()
}
+
+ /// Checks if format_bindings is set and runs rustfmt on the file
+ fn format_generated_file(&self, file: &Path) {
+ if !self.context.options().format_bindings {
+ return;
+ }
+
+ let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
+ rustfmt
+ } else {
+ error!("Could not find rustfmt in the global path.");
+ return;
+ };
+
+ let mut cmd = Command::new(rustfmt);
+
+ if let Some(path) = self.context.options().format_configuration_file.as_ref().and_then(
+ |f| f.to_str()) {
+ cmd.args(&["--config-path", path]);
+ }
+
+ if let Err(e) = cmd.arg(file).status() {
+ error!("Error executing rustfmt (exit code: {:?}).", e);
+ }
+ }
}
/// Determines whether the given cursor is in any of the files matched by the
diff --git a/src/options.rs b/src/options.rs
index 28faea99..074807c8 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -4,6 +4,7 @@ use clap::{App, Arg};
use std::fs::File;
use std::io::{self, Error, ErrorKind, Write, stderr};
use std::str::FromStr;
+use std::path::PathBuf;
/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
pub fn builder_from_flags<I>(
@@ -231,7 +232,20 @@ where
.help("Preprocess and dump the input header files to disk. \
Useful when debugging bindgen, using C-Reduce, or when \
filing issues. The resulting file will be named \
- something like `__bindgen.i` or `__bindgen.ii`.")
+ something like `__bindgen.i` or `__bindgen.ii`."),
+ Arg::with_name("format-bindings")
+ .long("format-bindings")
+ .help("Format the generated bindings with rustfmt. \
+ Rustfmt needs to be in the global PATH."),
+ Arg::with_name("format-configuration-file")
+ .long("format-configuration-file")
+ .help("The absolute path to the rustfmt configuration file. \
+ The configuration file will be used for formatting the bindings \
+ (when enabled by --format-bindings).")
+ .value_name("path")
+ .takes_value(true)
+ .multiple(false)
+ .number_of_values(1),
]) // .args()
.get_matches_from(args);
@@ -458,6 +472,27 @@ where
builder.dump_preprocessed_input()?;
}
+ if matches.is_present("format-bindings") {
+ builder = builder.format_bindings(true);
+ }
+
+ if let Some(path_str) = matches.value_of("format-configuration-file") {
+ let path = PathBuf::from(path_str);
+
+ if !path.is_absolute() {
+ return Err(Error::new(ErrorKind::Other,
+ "--format-configuration--file needs to be an absolute path!"));
+ }
+
+ if path.to_str().is_none() {
+ return Err(
+ Error::new(ErrorKind::Other,
+ "--format-configuration-file contains non-valid UTF8 characters."));
+ }
+
+ builder = builder.format_configuration_file(Some(path));
+ }
+
let verbose = matches.is_present("verbose");
Ok((builder, output, verbose))