diff --git a/cmd/goast/cli.go b/cmd/goast/cli.go index 9919a9f..54dc402 100644 --- a/cmd/goast/cli.go +++ b/cmd/goast/cli.go @@ -271,8 +271,11 @@ func cmdEval() *cli.Command { switch f { case outputText: for _, fail := range failCases { - fmt.Fprintf(w, "[%s:%d] - %s\n", fail.Path, fail.Line, fail.Msg) + if err := outputFailAsText(w, fail); err != nil { + return err + } } + fmt.Fprintf(w, "\n\tDetected %d violations\n\n", len(failCases)) case outputJSON: diff --git a/cmd/goast/output.go b/cmd/goast/output.go new file mode 100644 index 0000000..16e7fb0 --- /dev/null +++ b/cmd/goast/output.go @@ -0,0 +1,70 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "unicode" + + "github.com/fatih/color" + "github.com/m-mizutani/goast" + "github.com/m-mizutani/goerr" +) + +func outputFailAsText(w io.Writer, fail *goast.Fail) error { + code, err := getLine(fail.Path, fail.Line) + if err != nil { + return err + } + + type fprintf func(w io.Writer, format string, a ...any) (n int, err error) + + underLine := make([]rune, len(code)) + for i, c := range code { + if i+1 < fail.Column { + switch { + case unicode.IsSpace(c): + underLine[i] = c + case i+1 < fail.Column: + underLine[i] = ' ' + } + } else { + underLine[i] = '~' + } + } + + var cFprintf fprintf = fmt.Fprintf + if w == os.Stdout { + cFprintf = color.New(color.FgRed).Fprintf + } + + fmt.Fprintf(w, "[%s:%d] - ", fail.Path, fail.Line) + cFprintf(w, "%s\n", fail.Msg) + fmt.Fprintf(w, "\n%s\n%s\n\n", code, string(underLine)) + + return nil +} + +func getLine(path string, line int) (string, error) { + fd, err := os.Open(path) + if err != nil { + return "", goerr.Wrap(err) + } + defer func() { + if err := fd.Close(); err != nil { + logger.Warn(err.Error()) + } + }() + + var idx int + scanner := bufio.NewScanner(fd) + for scanner.Scan() { + idx++ + if idx == line { + return scanner.Text(), nil + } + } + + return "", nil +} diff --git a/go.mod b/go.mod index c36df5d..c03348d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/m-mizutani/goast go 1.18 require ( + github.com/fatih/color v1.13.0 github.com/m-mizutani/goerr v0.1.7 github.com/m-mizutani/opac v0.1.2-0.20220911011947-30fd33506a09 github.com/m-mizutani/zlog v0.3.2 diff --git a/go.sum b/go.sum index 5c6a50b..6e72219 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/Lu github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -58,8 +60,11 @@ github.com/m-mizutani/opac v0.1.2-0.20220911011947-30fd33506a09 h1:LXIbVjhcYSJP0 github.com/m-mizutani/opac v0.1.2-0.20220911011947-30fd33506a09/go.mod h1:XLr1rba7h2qEUmOpVb1DKwOV1w3UvZP4q/zJWKtO1z0= github.com/m-mizutani/zlog v0.3.2 h1:gdtvmISolbikEt+9ZfP/WGOlzePQOYUWFisI+ZolUtQ= github.com/m-mizutani/zlog v0.3.2/go.mod h1:GxFJcc4bguQJIHXYOOBF16Of2+SIrPGlZ5JkdOECzyE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= @@ -102,6 +107,9 @@ github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=