github.com/daixiang0/gci@v0.13.0/pkg/analyzer/diff.go (about) 1 package analyzer 2 3 import ( 4 "bytes" 5 "go/token" 6 "regexp" 7 "strconv" 8 "strings" 9 10 "github.com/pmezard/go-difflib/difflib" 11 "golang.org/x/tools/go/analysis" 12 ) 13 14 var hunkRE = regexp.MustCompile(`@@ -(\d+),(\d+) \+\d+,\d+ @@`) 15 16 func GetSuggestedFix(file *token.File, a, b []byte) (*analysis.SuggestedFix, error) { 17 d := difflib.UnifiedDiff{ 18 A: difflib.SplitLines(string(a)), 19 B: difflib.SplitLines(string(b)), 20 Context: 1, 21 } 22 diff, err := difflib.GetUnifiedDiffString(d) 23 if err != nil { 24 return nil, err 25 } 26 if diff == "" { 27 return nil, nil 28 } 29 var ( 30 fix analysis.SuggestedFix 31 found = false 32 edit analysis.TextEdit 33 buf bytes.Buffer 34 ) 35 for _, line := range strings.Split(diff, "\n") { 36 if hunk := hunkRE.FindStringSubmatch(line); len(hunk) > 0 { 37 if found { 38 edit.NewText = buf.Bytes() 39 buf = bytes.Buffer{} 40 fix.TextEdits = append(fix.TextEdits, edit) 41 edit = analysis.TextEdit{} 42 } 43 found = true 44 start, err := strconv.Atoi(hunk[1]) 45 if err != nil { 46 return nil, err 47 } 48 lines, err := strconv.Atoi(hunk[2]) 49 if err != nil { 50 return nil, err 51 } 52 edit.Pos = file.LineStart(start) 53 end := start + lines 54 if end > file.LineCount() { 55 edit.End = token.Pos(file.Size()) 56 } else { 57 edit.End = file.LineStart(end) 58 } 59 continue 60 } 61 // skip any lines until first hunk found 62 if !found { 63 continue 64 } 65 if line == "" { 66 continue 67 } 68 switch line[0] { 69 case '+': 70 buf.WriteString(line[1:]) 71 buf.WriteRune('\n') 72 case '-': 73 // just skip 74 case ' ': 75 buf.WriteString(line[1:]) 76 buf.WriteRune('\n') 77 } 78 } 79 edit.NewText = buf.Bytes() 80 fix.TextEdits = append(fix.TextEdits, edit) 81 82 return &fix, nil 83 }