@@ -33,7 +33,7 @@ func (f Format) IsTable() bool {
3333 return strings .HasPrefix (string (f ), TableFormatKey )
3434}
3535
36- // IsJSON returns true if the format is the json format
36+ // IsJSON returns true if the format is the JSON format
3737func (f Format ) IsJSON () bool {
3838 return string (f ) == JSONFormatKey
3939}
@@ -43,6 +43,31 @@ func (f Format) Contains(sub string) bool {
4343 return strings .Contains (string (f ), sub )
4444}
4545
46+ // templateString pre-processes the format and returns it as a string
47+ // for templating.
48+ func (f Format ) templateString () string {
49+ out := string (f )
50+ switch out {
51+ case TableFormatKey :
52+ // A bare "--format table" should already be handled before we
53+ // hit this; a literal "table" here means a custom "table" format
54+ // without template.
55+ return ""
56+ case JSONFormatKey :
57+ // "--format json" only; not JSON formats ("--format '{{json .Field}}'").
58+ return JSONFormat
59+ }
60+
61+ // "--format 'table {{.Field}}\t{{.Field}}'" -> "{{.Field}}\t{{.Field}}"
62+ if after , isTable := strings .CutPrefix (out , TableFormatKey ); isTable {
63+ out = after
64+ }
65+
66+ out = strings .Trim (out , " " ) // trim spaces, but preserve other whitespace.
67+ out = strings .NewReplacer (`\t` , "\t " , `\n` , "\n " ).Replace (out )
68+ return out
69+ }
70+
4671// Context contains information required by the formatter to print the output as desired.
4772type Context struct {
4873 // Output is the output stream to which the formatted string is written.
@@ -53,49 +78,34 @@ type Context struct {
5378 Trunc bool
5479
5580 // internal element
56- finalFormat string
57- header any
58- buffer * bytes.Buffer
59- }
60-
61- func (c * Context ) preFormat () {
62- c .finalFormat = string (c .Format )
63- // TODO: handle this in the Format type
64- switch {
65- case c .Format .IsTable ():
66- c .finalFormat = c .finalFormat [len (TableFormatKey ):]
67- case c .Format .IsJSON ():
68- c .finalFormat = JSONFormat
69- }
70-
71- c .finalFormat = strings .Trim (c .finalFormat , " " )
72- r := strings .NewReplacer (`\t` , "\t " , `\n` , "\n " )
73- c .finalFormat = r .Replace (c .finalFormat )
81+ header any
82+ buffer * bytes.Buffer
7483}
7584
7685func (c * Context ) parseFormat () (* template.Template , error ) {
77- tmpl , err := templates .Parse (c .finalFormat )
86+ tmpl , err := templates .Parse (c .Format . templateString () )
7887 if err != nil {
7988 return nil , fmt .Errorf ("template parsing error: %w" , err )
8089 }
8190 return tmpl , nil
8291}
8392
8493func (c * Context ) postFormat (tmpl * template.Template , subContext SubContext ) {
85- if c .Output == nil {
86- c .Output = io .Discard
94+ out := c .Output
95+ if out == nil {
96+ out = io .Discard
8797 }
88- if c .Format .IsTable () {
89- t := tabwriter .NewWriter (c .Output , 10 , 1 , 3 , ' ' , 0 )
90- buffer := bytes .NewBufferString ("" )
91- tmpl .Funcs (templates .HeaderFunctions ).Execute (buffer , subContext .FullHeader ())
92- buffer .WriteTo (t )
93- t .Write ([]byte ("\n " ))
94- c .buffer .WriteTo (t )
95- t .Flush ()
96- } else {
97- c .buffer .WriteTo (c .Output )
98+ if ! c .Format .IsTable () {
99+ _ , _ = c .buffer .WriteTo (out )
100+ return
98101 }
102+
103+ // Write column-headers and rows to the tab-writer buffer, then flush the output.
104+ tw := tabwriter .NewWriter (out , 10 , 1 , 3 , ' ' , 0 )
105+ _ = tmpl .Funcs (templates .HeaderFunctions ).Execute (tw , subContext .FullHeader ())
106+ _ , _ = tw .Write ([]byte {'\n' })
107+ _ , _ = c .buffer .WriteTo (tw )
108+ _ = tw .Flush ()
99109}
100110
101111func (c * Context ) contextFormat (tmpl * template.Template , subContext SubContext ) error {
@@ -115,8 +125,6 @@ type SubFormat func(func(SubContext) error) error
115125// Write the template to the buffer using this Context
116126func (c * Context ) Write (sub SubContext , f SubFormat ) error {
117127 c .buffer = & bytes.Buffer {}
118- c .preFormat ()
119-
120128 tmpl , err := c .parseFormat ()
121129 if err != nil {
122130 return err
0 commit comments