11use anyhow:: Result ;
22use heck:: { ToLowerCamelCase as _, ToSnakeCase as _, ToUpperCamelCase as _} ;
3+ use std:: borrow:: Cow ;
34use std:: collections:: { BTreeMap , BTreeSet , HashMap , HashSet , hash_map} ;
5+ use std:: fmt;
46use std:: fmt:: Write as _;
7+ use std:: io:: { self , Write as _} ;
58use std:: iter;
69use std:: mem;
10+ use std:: process:: Command ;
11+ use std:: str:: FromStr ;
12+ use std:: thread;
713use wit_bindgen_core:: abi:: {
814 self , AbiVariant , Bindgen , Bitcast , FlatTypes , Instruction , LiftLower , WasmType ,
915} ;
@@ -27,9 +33,55 @@ const EXPORT_RETURN_AREA: &str = "exportReturnArea";
2733const SYNC_EXPORT_PINNER : & str = "syncExportPinner" ;
2834const PINNER : & str = "pinner" ;
2935
36+ #[ derive( Default , Debug , Copy , Clone ) ]
37+ pub enum Format {
38+ #[ default]
39+ True ,
40+ False ,
41+ }
42+
43+ impl fmt:: Display for Format {
44+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
45+ write ! (
46+ f,
47+ "{}" ,
48+ match self {
49+ Self :: True => "true" ,
50+ Self :: False => "false" ,
51+ }
52+ )
53+ }
54+ }
55+
56+ impl FromStr for Format {
57+ type Err = String ;
58+
59+ fn from_str ( s : & str ) -> Result < Format , String > {
60+ match s {
61+ "true" => Ok ( Format :: True ) ,
62+ "false" => Ok ( Format :: False ) ,
63+ _ => Err ( format ! ( "expected `true` or `false`; got `{s}`" ) ) ,
64+ }
65+ }
66+ }
67+
3068#[ derive( Default , Debug , Clone ) ]
3169#[ cfg_attr( feature = "clap" , derive( clap:: Parser ) ) ]
3270pub struct Opts {
71+ /// Whether or not `gofmt` should be used (if present) to format generated
72+ /// code.
73+ #[ cfg_attr(
74+ feature = "clap" ,
75+ arg(
76+ long,
77+ default_value = "true" ,
78+ default_missing_value = "true" ,
79+ num_args = 0 ..=1 ,
80+ require_equals = true ,
81+ )
82+ ) ]
83+ pub format : Format ,
84+
3385 #[ cfg_attr( feature = "clap" , clap( flatten) ) ]
3486 pub async_ : AsyncFilterSet ,
3587
@@ -717,8 +769,10 @@ impl WorldGenerator for Go {
717769
718770 files. push (
719771 "wit_bindings.go" ,
720- format ! (
721- r#"package main
772+ & maybe_gofmt (
773+ self . opts . format ,
774+ format ! (
775+ r#"package main
722776
723777import (
724778 "runtime"
@@ -734,8 +788,9 @@ var {SYNC_EXPORT_PINNER} = runtime.Pinner{{}}
734788// Unused, but present to make the compiler happy
735789func main() {{}}
736790"#
737- )
738- . as_bytes ( ) ,
791+ )
792+ . as_bytes ( ) ,
793+ ) ,
739794 ) ;
740795 files. push ( "go.mod" , b"module wit_component\n \n go 1.25" ) ;
741796 files. push (
@@ -750,16 +805,19 @@ func main() {{}}
750805
751806 files. push (
752807 & format ! ( "{prefix}{name}/wit_bindings.go" ) ,
753- format ! (
754- "package {prefix}{name}
808+ & maybe_gofmt (
809+ self . opts . format ,
810+ format ! (
811+ "package {prefix}{name}
755812
756813import (
757814 {imports}
758815)
759816
760817{code}"
761- )
762- . as_bytes ( ) ,
818+ )
819+ . as_bytes ( ) ,
820+ ) ,
763821 ) ;
764822 }
765823 }
@@ -788,13 +846,16 @@ import (
788846
789847 files. push (
790848 "wit_types/wit_tuples.go" ,
791- format ! (
792- r#"package wit_types
849+ & maybe_gofmt (
850+ self . opts . format ,
851+ format ! (
852+ r#"package wit_types
793853
794854{tuples}
795855"#
796- )
797- . as_bytes ( ) ,
856+ )
857+ . as_bytes ( ) ,
858+ ) ,
798859 ) ;
799860 }
800861
@@ -2948,3 +3009,23 @@ fn func_declaration(resolve: &Resolve, func: &Function) -> (String, bool) {
29483009 }
29493010 }
29503011}
3012+
3013+ fn maybe_gofmt < ' a > ( format : Format , code : & ' a [ u8 ] ) -> Cow < ' a , [ u8 ] > {
3014+ return thread:: scope ( |s| {
3015+ if let Format :: True = format
3016+ && let Ok ( ( reader, mut writer) ) = io:: pipe ( )
3017+ {
3018+ s. spawn ( move || {
3019+ _ = writer. write_all ( & code) ;
3020+ } ) ;
3021+
3022+ if let Ok ( output) = Command :: new ( "gofmt" ) . stdin ( reader) . output ( )
3023+ && output. status . success ( )
3024+ {
3025+ return Cow :: Owned ( output. stdout ) ;
3026+ }
3027+ }
3028+
3029+ Cow :: Borrowed ( code)
3030+ } ) ;
3031+ }
0 commit comments