package main import ( "bufio" "fmt" "io" "sort" "git.xdrm.io/go/cliverage/coverage" ) func bold(str string) string { return fmt.Sprintf("\x1b[1m%s\x1b[0m", str) } func success(str string) string { return fmt.Sprintf("\x1b[38;2;26;221;120m%s\x1b[0m", str) } func warning(str string) string { return fmt.Sprintf("\x1b[38;2;221;26;120m%s\x1b[0m", str) } func printCoverage(r io.Reader, w io.Writer, chunks []coverage.Coverage) error { reader := bufio.NewReader(r) linen := uint64(0) eof := false coverPrefix := "\x1b[38;2;26;221;120m" coverSuffix := "\x1b[0m" // coverPrefix := "<<<" // coverSuffix := ">>>" for true { linen++ if eof { break } line, err := reader.ReadString('\n') if err == io.EOF { if len(line) < 1 { break } else { eof = true } } else if err != nil { return err } // check if we got a chunk start concerned := make([]coverage.Coverage, 0) for _, c := range chunks { if c.StartLine == linen || c.EndLine == linen { concerned = append(concerned, c) } } // sort by max column before sort.Slice(concerned, sortChunksByColumn(concerned, linen)) // if no coverage, write directly if len(concerned) < 1 { _, err := w.Write([]byte(fmt.Sprintf("%d\t| %s", linen, line))) if err != nil { return err } continue } // position each column with its prefix/suffix for _, chunk := range concerned { isStart := chunk.StartLine == linen isEnd := chunk.EndLine == linen if isStart && isEnd { firstColumn := chunk.StartColumn prefix := coverPrefix lastColumn := chunk.EndColumn suffix := coverSuffix if chunk.EndColumn > chunk.StartColumn { firstColumn = chunk.EndColumn prefix = coverSuffix lastColumn = chunk.StartColumn suffix = coverPrefix } line = line[0:firstColumn-1] + prefix + line[firstColumn-1:] if firstColumn != lastColumn { line = line[0:lastColumn-1] + suffix + line[lastColumn-1:] } continue } if isEnd { line = line[0:chunk.EndColumn-1] + coverSuffix + line[chunk.EndColumn-1:] } else if isStart { line = line[0:chunk.StartColumn-1] + coverPrefix + line[chunk.StartColumn-1:] continue } } _, err = w.Write([]byte(fmt.Sprintf("%d\t| %s", linen, line))) if err != nil { return err } } return nil } func sortChunksByColumn(chunks []coverage.Coverage, lineNumber uint64) func(i, j int) bool { return func(i, j int) bool { // if start is concerned iConcernedColumn := chunks[i].StartColumn if chunks[i].EndLine == lineNumber { iConcernedColumn = chunks[i].EndColumn if chunks[i].StartLine == lineNumber && chunks[i].StartColumn > iConcernedColumn { iConcernedColumn = chunks[i].StartColumn } } jConcernedColumn := chunks[j].StartColumn if chunks[j].EndLine == lineNumber { jConcernedColumn = chunks[j].EndColumn if chunks[j].StartLine == lineNumber && chunks[j].StartColumn > jConcernedColumn { jConcernedColumn = chunks[j].StartColumn } } if iConcernedColumn == jConcernedColumn { // return the closing chunk before if chunks[i].StartLine == lineNumber && chunks[j].EndLine == lineNumber { return true } if chunks[i].EndLine == lineNumber && chunks[j].StartLine == lineNumber { return false } } return iConcernedColumn >= jConcernedColumn } }