github.com/blugnu/test-report@v0.1.3/writer.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  )
     8  
     9  // IndentWriter is a wrapper around an io.Writer that will consistently indent
    10  // output and providing methods to simplify the writing of text output
    11  // containing indented sections and the handling of errors.
    12  //
    13  // The IndentWriter is not thread-safe and should not be used concurrently.
    14  //
    15  // If the underlying writer returns an error, the error is stored in the
    16  // IndentWriter and no further output is written by any IndentWriter methods.
    17  type IndentWriter struct {
    18  	output   io.Writer // the underlying writer
    19  	indent   string    // the current indent string
    20  	indented bool      // indicates if the indent has been written on the current line
    21  	error              // any error that occurred during writing
    22  }
    23  
    24  // writeIndent writes the current indent string to the output writer (if not
    25  // already written and not in an error state) and clears the indented flag.
    26  func (w *IndentWriter) writeIndent() {
    27  	if w.indented || w.error != nil {
    28  		return
    29  	}
    30  	_, w.error = io.WriteString(w.output, w.indent)
    31  	w.indented = w.error == nil
    32  }
    33  
    34  // WriteIndented calls the specified function with the indent string increased
    35  // by two spaces. The indent is restored to its original value after the
    36  // function returns.
    37  func (w *IndentWriter) WriteIndented(fn func()) {
    38  	og := w.indent
    39  	defer func() { w.indent = og }()
    40  
    41  	w.indent += "  "
    42  	fn()
    43  }
    44  
    45  // Write writes the specified arguments to the output writer. If the writer is
    46  // in an error state, no output is written.
    47  //
    48  // One or more arguments may be provided. If more than one argument is provided,
    49  // the first argument is treated as a string to be used as a format string with
    50  // the remaining arguments supplied as values.
    51  //
    52  // If not yet written, the current indent string is written to the output
    53  // writer before the specified arguments.
    54  //
    55  // No newline is appended to the output.
    56  func (w *IndentWriter) Write(s string, args ...any) {
    57  	if w.error != nil {
    58  		return
    59  	}
    60  
    61  	if len(args) > 0 {
    62  		s = fmt.Sprintf(s, args...)
    63  	}
    64  	w.writeIndent()
    65  	_, w.error = io.WriteString(w.output, s)
    66  }
    67  
    68  // WriteLn writes the specified arguments with a newline appended.
    69  // Different numbers of arguments are treated differently:
    70  //
    71  //	no arguments          only a newline is written.
    72  //
    73  //	one argument          the argument is written and a new-line appended.
    74  //
    75  //	multiple arguments    the first argument must be a string
    76  //	                      to be used as a format string with the
    77  //	                      remaining arguments supplied as values.
    78  //
    79  // If the writer is in an error state, no output is written.
    80  //
    81  // If not yet written, the current indent string is written to the output
    82  // writer before the specified arguments.
    83  func (w *IndentWriter) WriteLn(args ...any) {
    84  	defer func() { w.indented = false }()
    85  	var (
    86  		s string
    87  		a []any
    88  	)
    89  	switch len(args) {
    90  	case 0:
    91  		w.Write("\n")
    92  		return
    93  
    94  	case 1:
    95  		s = fmt.Sprintf("%s", args[0])
    96  
    97  	default:
    98  		s = args[0].(string)
    99  		a = args[1:]
   100  	}
   101  
   102  	if len(a) > 0 {
   103  		s = fmt.Sprintf(s, a...)
   104  	}
   105  
   106  	lines := strings.Split(s, "\n")
   107  	for _, line := range lines {
   108  		w.writeIndent()
   109  		if len(line) > 0 {
   110  			w.Write(line)
   111  		}
   112  		w.Write("\n")
   113  	}
   114  }
   115  
   116  // WriteXMLElement writes an XML element with optional attributes. The content
   117  // is written by calling the specified function with the indent increased by
   118  // two spaces. The element is closed with the appropriate end tag.
   119  func (w *IndentWriter) WriteXMLElement(fn func(), el string, attrs ...string) {
   120  	w.Write("<%s", el)
   121  	for _, attr := range attrs {
   122  		w.Write(" ")
   123  		w.Write(attr)
   124  	}
   125  	w.WriteLn(">")
   126  	w.WriteIndented(fn)
   127  	w.WriteLn("</%s>", el)
   128  }