diff options
Diffstat (limited to 'uncrust.go')
-rw-r--r-- | uncrust.go | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/uncrust.go b/uncrust.go new file mode 100644 index 0000000..a8a362e --- /dev/null +++ b/uncrust.go @@ -0,0 +1,118 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "log" + "os" + "os/exec" + "strconv" + "strings" + + "9fans.net/go/acme" + "github.com/akedrou/textdiff" +) + +var ( + fl_lang = flag.String("l", "C", "Language") + fl_verbose = flag.Bool("v", false, "Verbosity on") +) + +func main() { + samfile := os.Getenv("samfile") + id := os.Getenv("winid") + if "" == id { + log.Fatalf("no $winid set, not running in acme?") + } + + wid, e := strconv.Atoi(id) + if e != nil { + log.Fatalf("couldn't parse $winid: %s\n", e) + } + + win, e := acme.Open(wid, nil) + if e != nil { + log.Fatalf("couldn't open acme window id %d: %s\n", wid, e) + } + + body, e := win.ReadAll("body") + if e != nil { + log.Fatalf("couldn't read body of window id %d: %s\n", wid, e) + } + + args := []string{"-l", *fl_lang} + stderr := &bytes.Buffer{} + stdout := &bytes.Buffer{} + + cmd := exec.Command("uncrustify", args...) + cmd.Stdin = bytes.NewBuffer(body) + cmd.Stdout = stdout + cmd.Stderr = stderr + + if e = cmd.Run(); e != nil { + if _, ok := e.(*exec.ExitError); ok { + str := stderr.String() + if len(samfile) != 0 { + str = strings.ReplaceAll(str, "stdin, open_line is ", samfile+":") + } + log.Fatal("error: " + str) + } + log.Fatalf("error: %s\n", e) + return + } + + after := stdout.String() + before := string(body) + edits := textdiff.Strings(before, after) + textdiff.SortEdits(edits) + + // We have to calculate the rune position from the byte position. + rcount := 0 + idx := 0 + cont := false + for p := range before { + cont = false + for i := range edits[idx:] { + cont = true + if edits[i].Start == p { + edits[i].Start = rcount + } + if edits[i].End == p { + edits[i].End = rcount + idx++ + } + } + rcount++ + if !cont { + break + } + } + + if len(edits) > 0 { + win.Write("ctl", []byte("mark")) + win.Write("ctl", []byte("nomark")) + if *fl_verbose { + log.Printf("Applying %d diffs:\n%s\n", len(edits), pretty(edits, samfile)) + } + } + + for i := len(edits) - 1; i >= 0; i-- { + edit := edits[i] + + addr := fmt.Sprintf("#%d,#%d", edit.Start, edit.End) + e = win.Addr(addr) + if e != nil { + log.Fatalf("error writing to acme/%d/addr: %s\n", wid, e) + } + win.Write("data", []byte(edit.New)) + } +} + +func pretty(e []textdiff.Edit, p string) string { + b := &bytes.Buffer{} + for _, e := range e { + fmt.Fprintf(b, "%s:#%d,#%d\n", p, e.Start, e.End) + } + return b.String() +} |