github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/line-length-limit.go (about) 1 package rule 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "go/token" 8 "strings" 9 "unicode/utf8" 10 11 "github.com/songshiyun/revive/lint" 12 ) 13 14 // LineLengthLimitRule lints given else constructs. 15 type LineLengthLimitRule struct { 16 max int 17 } 18 19 // Apply applies the rule to given file. 20 func (r *LineLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { 21 if r.max == 0 { 22 checkNumberOfArguments(1, arguments, r.Name()) 23 24 max, ok := arguments[0].(int64) // Alt. non panicking version 25 if !ok || max < 0 { 26 panic(`invalid value passed as argument number to the "line-length-limit" rule`) 27 } 28 29 r.max = int(max) 30 } 31 32 var failures []lint.Failure 33 checker := lintLineLengthNum{ 34 max: r.max, 35 file: file, 36 onFailure: func(failure lint.Failure) { 37 failures = append(failures, failure) 38 }, 39 } 40 41 checker.check() 42 43 return failures 44 } 45 46 // Name returns the rule name. 47 func (r *LineLengthLimitRule) Name() string { 48 return "line-length-limit" 49 } 50 51 type lintLineLengthNum struct { 52 max int 53 file *lint.File 54 onFailure func(lint.Failure) 55 } 56 57 func (r lintLineLengthNum) check() { 58 f := bytes.NewReader(r.file.Content()) 59 spaces := strings.Repeat(" ", 4) // tab width = 4 60 l := 1 61 s := bufio.NewScanner(f) 62 for s.Scan() { 63 t := s.Text() 64 t = strings.ReplaceAll(t, "\t", spaces) 65 c := utf8.RuneCountInString(t) 66 if c > r.max { 67 r.onFailure(lint.Failure{ 68 Category: "code-style", 69 Position: lint.FailurePosition{ 70 // Offset not set; it is non-trivial, and doesn't appear to be needed. 71 Start: token.Position{ 72 Filename: r.file.Name, 73 Line: l, 74 Column: 0, 75 }, 76 End: token.Position{ 77 Filename: r.file.Name, 78 Line: l, 79 Column: c, 80 }, 81 }, 82 Confidence: 1, 83 Failure: fmt.Sprintf("line is %d characters, out of limit %d", c, r.max), 84 }) 85 } 86 l++ 87 } 88 }