diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e6c489 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# binaries +/editinacme + +# clutter +.DS_Store +.localized + +# Everybody has their own so don't check in by accident. +guide diff --git a/acme/editinacme/main.go b/acme/editinacme/main.go index 5ce5739..15c6dff 100644 --- a/acme/editinacme/main.go +++ b/acme/editinacme/main.go @@ -6,26 +6,34 @@ // // Usage: // -// editinacme +// editinacme [-nw] // -// Editinacme uses the plumber to ask acme to open the file, -// waits until the file's acme window is deleted, and exits. +// Editinacme uses the plumber to ask acme to open the file, waits until +// the file's acme window is deleted, and exits. Use the -nw flag to exit +// immediately after opening the file. package main import ( + "bufio" "flag" "fmt" "log" "os" "os/exec" "path/filepath" + "strings" "9fans.net/go/acme" + "9fans.net/go/plan9" + "9fans.net/go/plumb" ) func main() { log.SetFlags(0) log.SetPrefix("editinacme: ") + + nowait := flag.Bool("nw", false, "Don't wait for Acme to close the file") + flag.Usage = func() { fmt.Fprintf(os.Stderr, "usage: editinacme file\n") os.Exit(2) @@ -47,21 +55,61 @@ func main() { if err != nil { log.Fatal(err) } + defer r.Close() - log.Printf("editing %s", file) + filenamechan := make(chan string) + if !*nowait { + fid, err := plumb.Open("edit", plan9.OREAD) + if err != nil { + log.Fatalf("can't open plumber: %v", err) + } + defer fid.Close() + brd := bufio.NewReader(fid) + m := new(plumb.Message) + + go func() { + for { + err := m.Recv(brd) + if err != nil { + log.Fatalf("recv: %s", err) + } + if filename, likelymy := likelymyplumbrequest(m, file); likelymy { + filenamechan <- filename + return + } + } + }() + } + log.Printf("editing %s", file) out, err := exec.Command("plumb", "-d", "edit", file).CombinedOutput() if err != nil { log.Fatalf("executing plumb: %v\n%s", err, out) } - for { - ev, err := r.Read() - if err != nil { - log.Fatalf("reading acme log: %v", err) - } - if ev.Op == "del" && ev.Name == file { - break + if !*nowait { + filename := <-filenamechan + for { + ev, err := r.Read() + if err != nil { + log.Fatalf("reading acme log: %v", err) + } + if ev.Op == "del" && ev.Name == filename { + break + } } } } + +// likelymyplumbrequest applies some heuristics to determine if this +// message likely corresponds to the just made plumb edit request and +// returns the filename that the plumber asked Acme to open. +func likelymyplumbrequest(msg *plumb.Message, arg string) (string, bool) { + cwd, err := os.Getwd() + if err != nil { + log.Fatalf("aww shucks! %v", err) + } + plumbedfname := string(msg.Data) + myreq := (msg.Dir == cwd && strings.HasPrefix(arg, plumbedfname)) + return plumbedfname, myreq +}