125 lines
2.5 KiB
Go
125 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"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(`File: stdin, orig line is ([\d]+), orig col is ([\d])`)
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
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
|
|
|
|
samfile = filepath.Base(samfile)
|
|
|
|
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+":")
|
|
str = pos_rx.ReplaceAllString(str, fmt.Sprintf("%s:$1:#$2", 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 {
|
|
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"))
|
|
}
|
|
|
|
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: »%s«\n", p, e.Start, e.End, e.New)
|
|
}
|
|
return b.String()
|
|
}
|