github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/printers/text.go (about)

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