diff options
| author | Drew DeVault <sir@cmpwn.com> | 2019-03-30 11:58:24 -0400 | 
|---|---|---|
| committer | Drew DeVault <sir@cmpwn.com> | 2019-03-30 11:58:24 -0400 | 
| commit | 700dea23fa75f213af2f99449db994008eab9d21 (patch) | |
| tree | fa142784bf4ccb6aba1cd2b8513228dd4b968b28 | |
| parent | 4465646fedc5dd3efa680a7cc8d06671350b75b9 (diff) | |
Implement :pipe
| -rw-r--r-- | commands/account/pipe.go | 73 | ||||
| -rw-r--r-- | commands/terminal/close.go | 1 | ||||
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | widgets/terminal.go | 20 | 
5 files changed, 91 insertions, 7 deletions
diff --git a/commands/account/pipe.go b/commands/account/pipe.go new file mode 100644 index 0000000..5693d4a --- /dev/null +++ b/commands/account/pipe.go @@ -0,0 +1,73 @@ +package account + +import ( +	"bytes" +	"errors" +	"io" +	"os/exec" +	"time" + +	"git.sr.ht/~sircmpwn/aerc2/widgets" + +	"github.com/gdamore/tcell" +	"github.com/mohamedattahri/mail" +) + +func init() { +	register("pipe", Pipe) +} + +func Pipe(aerc *widgets.Aerc, args []string) error { +	if len(args) < 2 { +		return errors.New("Usage: :pipe <cmd> [args...]") +	} +	acct := aerc.SelectedAccount() +	if acct == nil { +		return errors.New("No account selected") +	} +	store := acct.Messages().Store() +	msg := acct.Messages().Selected() +	store.FetchBodies([]uint32{msg.Uid}, func(msg *mail.Message) { +		cmd := exec.Command(args[1], args[2:]...) +		pipe, err := cmd.StdinPipe() +		if err != nil { +			aerc.PushStatus(" "+err.Error(), 10*time.Second). +				Color(tcell.ColorRed, tcell.ColorWhite) +			return +		} +		term, err := widgets.NewTerminal(cmd) +		if err != nil { +			aerc.PushStatus(" "+err.Error(), 10*time.Second). +				Color(tcell.ColorRed, tcell.ColorWhite) +			return +		} +		host := widgets.NewTermHost(term, aerc.Config()) +		name := msg.Subject() +		if len(name) > 12 { +			name = name[:12] +		} +		aerc.NewTab(host, args[1] + " <" + name) +		term.OnClose = func(err error) { +			if err != nil { +				aerc.PushStatus(" "+err.Error(), 10*time.Second). +					Color(tcell.ColorRed, tcell.ColorWhite) +			} else { +				// TODO: Tab-specific status stacks +				aerc.PushStatus("Process complete, press any key to close.", +					10*time.Second) +			} +		} +		term.OnStart = func() { +			go func() { +				reader := bytes.NewBuffer(msg.Bytes()) +				_, err := io.Copy(pipe, reader) +				if err != nil { +					aerc.PushStatus(" "+err.Error(), 10*time.Second). +						Color(tcell.ColorRed, tcell.ColorWhite) +				} +				pipe.Close() +			}() +		} +	}) +	return nil +} diff --git a/commands/terminal/close.go b/commands/terminal/close.go index 68be6ac..cb5702e 100644 --- a/commands/terminal/close.go +++ b/commands/terminal/close.go @@ -19,5 +19,6 @@ func CommandClose(aerc *widgets.Aerc, args []string) error {  		return errors.New("Error: not a terminal")  	}  	thost.Terminal().Close(nil) +	aerc.RemoveTab(thost)  	return nil  } @@ -2,6 +2,7 @@ module git.sr.ht/~sircmpwn/aerc2  require (  	git.sr.ht/~sircmpwn/go-libvterm v0.0.0-20190322002230-17c9f17a421a +	git.sr.ht/~sircmpwn/pty v0.0.0-20190330154901-3a43678975a9  	github.com/emersion/go-imap v1.0.0-beta.1  	github.com/emersion/go-imap-idle v0.0.0-20180114101550-2af93776db6b  	github.com/emersion/go-sasl v0.0.0-20161116183048-7e096a0a6197 // indirect @@ -9,7 +10,6 @@ require (  	github.com/gdamore/tcell v1.0.0  	github.com/go-ini/ini v1.42.0  	github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf -	github.com/kr/pty v1.1.3  	github.com/kyoh86/xdg v0.0.0-20171127140545-8db68a8ea76a  	github.com/lucasb-eyer/go-colorful v0.0.0-20180531031333-d9cec903b20c  	github.com/mattn/go-isatty v0.0.3 @@ -20,6 +20,8 @@ git.sr.ht/~sircmpwn/go-libvterm v0.0.0-20190322001004-741298f37f76 h1:D9PCVZ+pgt  git.sr.ht/~sircmpwn/go-libvterm v0.0.0-20190322001004-741298f37f76/go.mod h1:hT88+cTemwwESbMptwC7O33qrJfQX0SgRWbXlndUS2c=  git.sr.ht/~sircmpwn/go-libvterm v0.0.0-20190322002230-17c9f17a421a h1:ktjo0NVokhdhhyS/VYA1/8R/Az8x5x43r0SuI6McqW4=  git.sr.ht/~sircmpwn/go-libvterm v0.0.0-20190322002230-17c9f17a421a/go.mod h1:hT88+cTemwwESbMptwC7O33qrJfQX0SgRWbXlndUS2c= +git.sr.ht/~sircmpwn/pty v0.0.0-20190330154901-3a43678975a9 h1:WWPN5lf6KzXp3xWRrPQZ4MLR3yrFEI4Ysz7HSQ1G/yo= +git.sr.ht/~sircmpwn/pty v0.0.0-20190330154901-3a43678975a9/go.mod h1:8Jmcax8M9nYoEwBhVBhv2ixLRCoUqlbQPE95VpPu43I=  github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=  github.com/emersion/go-imap v1.0.0-beta.1 h1:bTCaVlUnb5mKoW9lEukusxguSYYZPer+q0g5t+vw5X0= diff --git a/widgets/terminal.go b/widgets/terminal.go index e7286f9..45e3591 100644 --- a/widgets/terminal.go +++ b/widgets/terminal.go @@ -9,8 +9,8 @@ import (  	"git.sr.ht/~sircmpwn/aerc2/lib/ui"  	"git.sr.ht/~sircmpwn/go-libvterm" +	"git.sr.ht/~sircmpwn/pty"  	"github.com/gdamore/tcell" -	"github.com/kr/pty"  )  type vtermKey struct { @@ -105,6 +105,7 @@ type Terminal struct {  	vterm        *vterm.VTerm  	OnClose func(err error) +	OnStart func()  	OnTitle func(title string)  } @@ -192,6 +193,9 @@ func (term *Terminal) flushTerminal() {  }  func (term *Terminal) Close(err error) { +	if term.closed { +		return +	}  	term.mutex.Lock()  	defer term.mutex.Unlock()  	term.err = err @@ -226,11 +230,6 @@ func (term *Terminal) Invalidate() {  func (term *Terminal) Draw(ctx *ui.Context) {  	if term.closed { -		if term.err != nil { -			ui.NewText(term.err.Error()).Strategy(ui.TEXT_CENTER).Draw(ctx) -		} else { -			ui.NewText("Terminal closed").Strategy(ui.TEXT_CENTER).Draw(ctx) -		}  		return  	} @@ -252,6 +251,9 @@ func (term *Terminal) Draw(ctx *ui.Context) {  			return  		}  		term.start <- nil +		if term.OnStart != nil { +			term.OnStart() +		}  	}  	term.ctx = ctx // gross @@ -309,6 +311,9 @@ func (term *Terminal) Draw(ctx *ui.Context) {  }  func (term *Terminal) Focus(focus bool) { +	if term.closed { +		return +	}  	term.focus = focus  	if term.ctx != nil {  		if !term.focus { @@ -339,6 +344,9 @@ func convertMods(mods tcell.ModMask) vterm.Modifier {  }  func (term *Terminal) Event(event tcell.Event) bool { +	if term.closed { +		return false +	}  	switch event := event.(type) {  	case *tcell.EventKey:  		if event.Key() == tcell.KeyRune {  | 
