code-intelligence.com/cifuzz@v0.40.0/pkg/log/ptermwriter.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "io" 6 "sync" 7 8 "github.com/pkg/errors" 9 ) 10 11 var ActiveUpdatingPrinter updatingPrinter 12 13 type updatingPrinter interface { 14 Clear() 15 } 16 17 var writeLock sync.Mutex 18 19 type ptermWriter struct { 20 buf []byte 21 out io.Writer 22 } 23 24 // NewPTermWriter returns a writer which ensures that the output written 25 // by it doesn't mess with the output of an active pterm.SpinnerPrinter. 26 func NewPTermWriter(out io.Writer) *ptermWriter { 27 return &ptermWriter{out: out} 28 } 29 30 func (w *ptermWriter) Write(p []byte) (int, error) { 31 // To avoid races, only one write is executed at a time 32 writeLock.Lock() 33 defer writeLock.Unlock() 34 35 // To ensure that after the write, the spinner printer has a new 36 // line for itself, we only write the output if it ends with a 37 // newline. Else, we store it in a buffer which we write the next 38 // time Write() is called with something that ends with a newline. 39 lenOldBuf := len(w.buf) 40 w.buf = append(w.buf, p...) 41 if len(p) == 0 || p[len(p)-1] != '\n' { 42 return len(p), nil 43 } 44 45 // Clear the updating printer output if any. We don't use 46 // pterm.Fprint here, which also tries to clear spinner printer 47 // output, because that only works when the spinner printer and this 48 // function write to the same output stream, which is not always the 49 // case. 50 if ActiveUpdatingPrinter != nil { 51 ActiveUpdatingPrinter.Clear() 52 } 53 54 // Write the buffer 55 n, err := fmt.Fprint(w.out, string(w.buf)) 56 57 // Clear the buffer now that it was written 58 w.buf = []byte{} 59 60 // Return the number of bytes from p that were written. If 61 // fmt.Fprint printed all bytes from the buffer, this is n minus the 62 // length of the buffer before we appended p to it. 63 return n - lenOldBuf, errors.WithStack(err) 64 }