diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 79 | ||||
-rw-r--r-- | src/options.rs | 37 |
2 files changed, 107 insertions, 9 deletions
@@ -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)) |