From 3198ecda1822d7f5c1c583b9dce57b502dd383aa Mon Sep 17 00:00:00 2001 From: Fred Israel Date: Fri, 12 Jul 2024 10:37:30 -0300 Subject: [PATCH] adding colored char diff --- go.mod | 12 +++++- go.sum | 35 ++++++++++++++++- vimv.go | 115 +++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 131 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 51eeda8..7d8f483 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,14 @@ go 1.22.3 require github.com/jwalton/go-supportscolor v1.2.0 require ( - golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 + github.com/fatih/color v1.17.0 +) + +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect ) diff --git a/go.sum b/go.sum index 4289711..7466461 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,38 @@ +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/jwalton/go-supportscolor v1.2.0 h1:g6Ha4u7Vm3LIsQ5wmeBpS4gazu0UP1DRDE8y6bre4H8= github.com/jwalton/go-supportscolor v1.2.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/vimv.go b/vimv.go index 24aecbf..b75c38a 100644 --- a/vimv.go +++ b/vimv.go @@ -6,13 +6,15 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "strings" + "github.com/andreyvit/diff" + "github.com/fatih/color" "github.com/jwalton/go-supportscolor" ) -var color = supportscolor.Stdout().SupportsColor var cleanup_afterwards = true func main() { @@ -23,6 +25,8 @@ func main() { flag.Parse() files := flag.Args() + color.NoColor = !supportscolor.Stdout().SupportsColor + files = removeEmptyLines(files) validateInput(files) tmpfolder, filelist := getTmpFile(files) @@ -59,17 +63,9 @@ func main() { errors := rename(to_rename) // Finalizing - if color { - fmt.Printf("\033[1;32mRenamed %d files successfully.\033[0m\n", len(to_rename)-len(errors)) - } else { - fmt.Printf("Renamed %d files successfully.\n", len(to_rename)-len(errors)) - } + color.Green("Renamed %d files successfully.", len(to_rename)-len(errors)) if errors != nil { - if color { - fmt.Printf("\033[1;31mError renaming %d files.\033[0m\n", len(errors)) - } else { - fmt.Printf("Error renaming %d files.\n", len(errors)) - } + color.Red("Error renaming %d files.", len(errors)) } } @@ -79,26 +75,34 @@ type FilePair struct { } func report(to_rename []FilePair) { - if color { - fmt.Printf("\033[1;34mTotal files to be renamed: %d\033[0m\n", len(to_rename)) - } else { - fmt.Printf("Total files to be renamed: %d\n", len(to_rename)) + color.Cyan("Total files to be renamed: %d", len(to_rename)) + if len(to_rename) == 0 { + return } for _, fp := range to_rename { - if color { - fmt.Printf("\033[1;34m%s\033[0m -> \033[1;33m%s\033[0m\n", fp.from, fp.to) - } else { - fmt.Printf("%s -> %s\n", fp.from, fp.to) - } + fmt.Printf("%s -> %s\n", color.CyanString(fp.from), color.YellowString(fp.to)) } - if len(to_rename) == 0 { - return + for { + user_input := prompt_user() + if user_input == "yes" { + return + } + if user_input == "no" { + fmt.Println("Operation aborted by user.") + cleanup_afterwards = false + panic(Exit{1}) + } + if user_input == "diff" { + show_diff(to_rename) + } } +} +func prompt_user() string { // Confirm - fmt.Print("Press '(y)' to continue, 'n' to abort: ") + fmt.Print("Press '(y)' to continue, 'd' to show name diff, 'n' to abort:") var response string _, err := fmt.Scanln(&response) if err != nil { @@ -107,10 +111,67 @@ func report(to_rename []FilePair) { panic(Exit{1}) } } - if strings.ToLower(response) != "y" && response != "" { - fmt.Println("Operation aborted by user.") - cleanup_afterwards = false - panic(Exit{1}) + if strings.ToLower(response) == "y" || response == "" { + return "yes" + } + if strings.ToLower(response) == "d" { + return "diff" + } + // else + return "no" +} + +func show_diff(pairs []FilePair) { + type Segment struct { + text string + type_ string + } + // Create a list of ordered Segments. Types are +(added) ~(deleted) or =(common) + for _, fp := range pairs { + the_diff := diff.CharacterDiff(fp.from, fp.to) + var segments []Segment + re := regexp.MustCompile(`\(?(\+\+|~~)\)?`) + delimiters := re.FindAllStringIndex(the_diff, -1) + idx := 0 + inside_delimiter := false + for _, delimiter := range delimiters { + var type_ string + if inside_delimiter { + type_ = string(the_diff[delimiter[0]+1]) // +1 to avoid brackets + } else { + type_ = "=" + } + segments = append(segments, Segment{the_diff[idx:delimiter[0]], type_}) + idx = delimiter[1] + inside_delimiter = !inside_delimiter + } + segments = append(segments, Segment{the_diff[idx:], "="}) + + // Print orig + fmt.Print(color.CyanString("From: ")) + for _, seg := range segments { + switch seg.type_ { + case "+": + // noop + case "~": + fmt.Print(color.RedString(seg.text)) + default: + fmt.Print(color.WhiteString(seg.text)) + } + } + fmt.Println() + fmt.Print(color.YellowString("To: ")) + for _, seg := range segments { + switch seg.type_ { + case "+": + fmt.Print(color.GreenString(seg.text)) + case "~": + // noop + default: + fmt.Print(color.WhiteString(seg.text)) + } + } + fmt.Println() } }