@@ -19,15 +19,15 @@ var (
1919 // set (regardless of its value). This is a global option and affects all
2020 // colors. For more control over each color block use the methods
2121 // DisableColor() individually.
22- NoColor = noColorIsSet () || os .Getenv ("TERM" ) == "dumb" ||
23- (! isatty .IsTerminal (os .Stdout .Fd ()) && ! isatty .IsCygwinTerminal (os .Stdout .Fd ()))
22+ NoColor = noColorIsSet () || os .Getenv ("TERM" ) == "dumb" || ! stdoutIsTerminal ()
2423
2524 // Output defines the standard output of the print functions. By default,
26- // os.Stdout is used.
27- Output = colorable . NewColorableStdout ()
25+ // stdOut() is used.
26+ Output = stdOut ()
2827
29- // Error defines a color supporting writer for os.Stderr.
30- Error = colorable .NewColorableStderr ()
28+ // Error defines the standard error of the print functions. By default,
29+ // stdErr() is used.
30+ Error = stdErr ()
3131
3232 // colorsCache is used to reduce the count of created Color objects and
3333 // allows to reuse already created objects with required Attribute.
@@ -40,6 +40,33 @@ func noColorIsSet() bool {
4040 return os .Getenv ("NO_COLOR" ) != ""
4141}
4242
43+ // stdoutIsTerminal returns true if os.Stdout is a terminal.
44+ // Returns false if os.Stdout is nil (e.g., when running as a Windows service).
45+ func stdoutIsTerminal () bool {
46+ if os .Stdout == nil {
47+ return false
48+ }
49+ return isatty .IsTerminal (os .Stdout .Fd ()) || isatty .IsCygwinTerminal (os .Stdout .Fd ())
50+ }
51+
52+ // stdOut returns a writer for color output.
53+ // Returns io.Discard if os.Stdout is nil (e.g., when running as a Windows service).
54+ func stdOut () io.Writer {
55+ if os .Stdout == nil {
56+ return io .Discard
57+ }
58+ return colorable .NewColorableStdout ()
59+ }
60+
61+ // stdErr returns a writer for color error output.
62+ // Returns io.Discard if os.Stderr is nil (e.g., when running as a Windows service).
63+ func stdErr () io.Writer {
64+ if os .Stderr == nil {
65+ return io .Discard
66+ }
67+ return colorable .NewColorableStderr ()
68+ }
69+
4370// Color defines a custom color object which is defined by SGR parameters.
4471type Color struct {
4572 params []Attribute
@@ -220,22 +247,30 @@ func (c *Color) unset() {
220247// a low-level function, and users should use the higher-level functions, such
221248// as color.Fprint, color.Print, etc.
222249func (c * Color ) SetWriter (w io.Writer ) * Color {
250+ _ , _ = c .setWriter (w )
251+ return c
252+ }
253+
254+ func (c * Color ) setWriter (w io.Writer ) (int , error ) {
223255 if c .isNoColorSet () {
224- return c
256+ return 0 , nil
225257 }
226258
227- fmt .Fprint (w , c .format ())
228- return c
259+ return fmt .Fprint (w , c .format ())
229260}
230261
231262// UnsetWriter resets all escape attributes and clears the output with the give
232263// io.Writer. Usually should be called after SetWriter().
233264func (c * Color ) UnsetWriter (w io.Writer ) {
265+ _ , _ = c .unsetWriter (w )
266+ }
267+
268+ func (c * Color ) unsetWriter (w io.Writer ) (int , error ) {
234269 if c .isNoColorSet () {
235- return
270+ return 0 , nil
236271 }
237272
238- fmt .Fprintf (w , "%s[%dm" , escape , Reset )
273+ return fmt .Fprintf (w , "%s[%dm" , escape , Reset )
239274}
240275
241276// Add is used to chain SGR parameters. Use as many as parameters to combine
@@ -251,10 +286,20 @@ func (c *Color) Add(value ...Attribute) *Color {
251286// On Windows, users should wrap w with colorable.NewColorable() if w is of
252287// type *os.File.
253288func (c * Color ) Fprint (w io.Writer , a ... interface {}) (n int , err error ) {
254- c .SetWriter (w )
255- defer c .UnsetWriter (w )
289+ n , err = c .setWriter (w )
290+ if err != nil {
291+ return n , err
292+ }
256293
257- return fmt .Fprint (w , a ... )
294+ nn , err := fmt .Fprint (w , a ... )
295+ n += nn
296+ if err != nil {
297+ return
298+ }
299+
300+ nn , err = c .unsetWriter (w )
301+ n += nn
302+ return n , err
258303}
259304
260305// Print formats using the default formats for its operands and writes to
@@ -274,10 +319,20 @@ func (c *Color) Print(a ...interface{}) (n int, err error) {
274319// On Windows, users should wrap w with colorable.NewColorable() if w is of
275320// type *os.File.
276321func (c * Color ) Fprintf (w io.Writer , format string , a ... interface {}) (n int , err error ) {
277- c .SetWriter (w )
278- defer c .UnsetWriter (w )
322+ n , err = c .setWriter (w )
323+ if err != nil {
324+ return n , err
325+ }
326+
327+ nn , err := fmt .Fprintf (w , format , a ... )
328+ n += nn
329+ if err != nil {
330+ return
331+ }
279332
280- return fmt .Fprintf (w , format , a ... )
333+ nn , err = c .unsetWriter (w )
334+ n += nn
335+ return n , err
281336}
282337
283338// Printf formats according to a format specifier and writes to standard output.
0 commit comments