uncrust/uncrust.go

135 lines
2.9 KiB
Go
Raw Permalink Normal View History

2024-12-08 22:41:16 +01:00
package main
import (
"bytes"
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
2024-12-08 22:41:16 +01:00
"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")
pos_rx = regexp.MustCompile(`.* orig line is ([\d]+), orig col is ([\d]+)`)
2024-12-11 19:40:08 +01:00
lin_rx = regexp.MustCompile(`.* orig line is ([\d]+)`)
grb_rx = regexp.MustCompile(`stdin:([\d]+) Garbage in col ([\d]+)`)
2024-12-08 22:41:16 +01:00
)
func main() {
2024-12-08 23:12:11 +01:00
flag.Parse()
2024-12-08 22:41:16 +01:00
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)
}
2025-01-17 17:56:22 +01:00
args := []string{"--replace", "--no-backup", "-l", *fl_lang}
2024-12-08 22:41:16 +01:00
stderr := &bytes.Buffer{}
stdout := &bytes.Buffer{}
cmd := exec.Command("uncrustify", args...)
cmd.Stdin = bytes.NewBuffer(body)
cmd.Stdout = stdout
cmd.Stderr = stderr
2024-12-08 23:40:09 +01:00
samfile = filepath.Base(samfile)
2024-12-08 22:41:16 +01:00
if e = cmd.Run(); e != nil {
if _, ok := e.(*exec.ExitError); ok {
str := stderr.String()
str += "\n" + stdout.String()
2024-12-08 22:41:16 +01:00
if len(samfile) != 0 {
str = strings.ReplaceAll(str, "stdin, open_line is ", samfile+":")
str = pos_rx.ReplaceAllString(str, fmt.Sprintf("%s:$1:#$2", samfile))
2024-12-11 19:40:08 +01:00
str = lin_rx.ReplaceAllString(str, fmt.Sprintf("%s:$1", samfile))
str = grb_rx.ReplaceAllString(str, fmt.Sprintf("%s:$1:#$2", samfile))
2024-12-08 22:41:16 +01:00
}
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
2025-01-10 12:17:06 +01:00
sidx, eidx := 0, 0
2024-12-08 22:41:16 +01:00
for p := range before {
2025-01-10 12:17:06 +01:00
for i := range edits[sidx:] {
if edits[sidx+i].Start == p {
edits[sidx+i].Start = rcount
sidx += i
break
2024-12-08 22:41:16 +01:00
}
2025-01-10 12:17:06 +01:00
}
for i := range edits[eidx:] {
if edits[i+eidx].End == p {
edits[i+eidx].End = rcount
eidx += i
break
2024-12-08 22:41:16 +01:00
}
}
rcount++
2025-01-10 12:17:06 +01:00
if eidx == len(edits) {
2024-12-08 22:41:16 +01:00
break
}
}
if len(edits) > 0 {
if *fl_verbose {
log.Printf("Applying %d diffs:\n%s\n", len(edits), pretty(edits, samfile))
}
win.Write("ctl", []byte("mark"))
win.Write("ctl", []byte("nomark"))
2024-12-08 22:41:16 +01:00
}
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 {
2025-01-10 12:17:06 +01:00
log.Fatalf("error writing %q to acme/%d/addr: %s\n", addr, wid, e)
2024-12-08 22:41:16 +01:00
}
win.Write("data", []byte(edit.New))
}
}
func pretty(e []textdiff.Edit, p string) string {
b := &bytes.Buffer{}
for _, e := range e {
2024-12-08 23:40:09 +01:00
fmt.Fprintf(b, "%s:#%d,#%d: »%s«\n", p, e.Start, e.End, e.New)
2024-12-08 22:41:16 +01:00
}
return b.String()
}