uncrust/uncrust.go
2024-12-08 22:51:59 +01:00

116 lines
2.2 KiB
Go

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
for p := range before {
for i := range edits[idx:] {
if edits[i].Start == p {
edits[i].Start = rcount
}
if edits[i].End == p {
edits[i].End = rcount
idx++
}
}
rcount++
if idx == len(edits) {
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()
}