github.com/nozzle/golangci-lint@v1.49.0-nz3/pkg/printers/text.go (about)

     1  package printers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  
     9  	"github.com/fatih/color"
    10  
    11  	"github.com/golangci/golangci-lint/pkg/logutils"
    12  	"github.com/golangci/golangci-lint/pkg/result"
    13  )
    14  
    15  type Text struct {
    16  	printIssuedLine bool
    17  	useColors       bool
    18  	printLinterName bool
    19  
    20  	log logutils.Log
    21  	w   io.Writer
    22  }
    23  
    24  func NewText(printIssuedLine, useColors, printLinterName bool, log logutils.Log, w io.Writer) *Text {
    25  	return &Text{
    26  		printIssuedLine: printIssuedLine,
    27  		useColors:       useColors,
    28  		printLinterName: printLinterName,
    29  		log:             log,
    30  		w:               w,
    31  	}
    32  }
    33  
    34  func (p Text) SprintfColored(ca color.Attribute, format string, args ...interface{}) string {
    35  	if !p.useColors {
    36  		return fmt.Sprintf(format, args...)
    37  	}
    38  
    39  	c := color.New(ca)
    40  	return c.Sprintf(format, args...)
    41  }
    42  
    43  func (p *Text) Print(ctx context.Context, issues []result.Issue) error {
    44  	for i := range issues {
    45  		p.printIssue(&issues[i])
    46  
    47  		if !p.printIssuedLine {
    48  			continue
    49  		}
    50  
    51  		p.printSourceCode(&issues[i])
    52  		p.printUnderLinePointer(&issues[i])
    53  	}
    54  
    55  	return nil
    56  }
    57  
    58  func (p Text) printIssue(i *result.Issue) {
    59  	text := p.SprintfColored(color.FgRed, "%s", strings.TrimSpace(i.Text))
    60  	if p.printLinterName {
    61  		text += fmt.Sprintf(" (%s)", i.FromLinter)
    62  	}
    63  	pos := p.SprintfColored(color.Bold, "%s:%d", i.FilePath(), i.Line())
    64  	if i.Pos.Column != 0 {
    65  		pos += fmt.Sprintf(":%d", i.Pos.Column)
    66  	}
    67  	fmt.Fprintf(p.w, "%s: %s\n", pos, text)
    68  }
    69  
    70  func (p Text) printSourceCode(i *result.Issue) {
    71  	for _, line := range i.SourceLines {
    72  		fmt.Fprintln(p.w, line)
    73  	}
    74  }
    75  
    76  func (p Text) printUnderLinePointer(i *result.Issue) {
    77  	// if column == 0 it means column is unknown (e.g. for gosec)
    78  	if len(i.SourceLines) != 1 || i.Pos.Column == 0 {
    79  		return
    80  	}
    81  
    82  	col0 := i.Pos.Column - 1
    83  	line := i.SourceLines[0]
    84  	prefixRunes := make([]rune, 0, len(line))
    85  	for j := 0; j < len(line) && j < col0; j++ {
    86  		if line[j] == '\t' {
    87  			prefixRunes = append(prefixRunes, '\t')
    88  		} else {
    89  			prefixRunes = append(prefixRunes, ' ')
    90  		}
    91  	}
    92  
    93  	fmt.Fprintf(p.w, "%s%s\n", string(prefixRunes), p.SprintfColored(color.FgYellow, "^"))
    94  }