1// Package printer implements printing of avo files in various formats. 2package printer 3 4import ( 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/mmcloughlin/avo/internal/stack" 11 "github.com/mmcloughlin/avo/ir" 12) 13 14// Printer can produce output for an avo File. 15type Printer interface { 16 Print(*ir.File) ([]byte, error) 17} 18 19// Builder can construct a printer. 20type Builder func(Config) Printer 21 22// Config represents general printing configuration. 23type Config struct { 24 // Command-line arguments passed to the generator. If provided, this will be 25 // included in a code generation warning. 26 Argv []string 27 28 // Name of the code generator. 29 Name string 30 31 // Name of Go package the generated code will belong to. 32 Pkg string 33} 34 35// NewDefaultConfig produces a config with Name "avo". 36// The package name is guessed from the current directory. 37func NewDefaultConfig() Config { 38 return Config{ 39 Name: "avo", 40 Pkg: pkg(), 41 } 42} 43 44// NewArgvConfig constructs a Config from os.Args. 45// The package name is guessed from the current directory. 46func NewArgvConfig() Config { 47 return Config{ 48 Argv: os.Args, 49 Pkg: pkg(), 50 } 51} 52 53// NewGoRunConfig produces a Config for a generator that's expected to be 54// executed via "go run ...". 55func NewGoRunConfig() Config { 56 path := mainfile() 57 if path == "" { 58 return NewDefaultConfig() 59 } 60 argv := []string{"go", "run", filepath.Base(path)} 61 if len(os.Args) > 1 { 62 argv = append(argv, os.Args[1:]...) 63 } 64 return Config{ 65 Argv: argv, 66 Pkg: pkg(), 67 } 68} 69 70// GeneratedBy returns a description of the code generator. 71func (c Config) GeneratedBy() string { 72 if c.Argv == nil { 73 return c.Name 74 } 75 return fmt.Sprintf("command: %s", strings.Join(c.Argv, " ")) 76} 77 78// GeneratedWarning returns text for a code generation warning. Conforms to https://golang.org/s/generatedcode. 79func (c Config) GeneratedWarning() string { 80 return fmt.Sprintf("Code generated by %s. DO NOT EDIT.", c.GeneratedBy()) 81} 82 83// mainfile attempts to determine the file path of the main function by 84// inspecting the stack. Returns empty string on failure. 85func mainfile() string { 86 if m := stack.Main(); m != nil { 87 return m.File 88 } 89 return "" 90} 91 92// pkg guesses the name of the package from the working directory. 93func pkg() string { 94 if cwd, err := os.Getwd(); err == nil { 95 return filepath.Base(cwd) 96 } 97 return "" 98} 99