Refactor lib/open to accept user provided arguments

* Get rid of open_darwin
	It just lead to code duplication for a simple one string change.
	Instead we query it during initialization
* Accept user provided arguments
	"open" on MacOS accepts things like -A to use a specific application
	Pass trough arguments the user provided in order to facilitate this
* Refactor the function to a struct
	This makes it more convenient for the caller and avoids signatures like
	lib.OpenFile(nil, u.String(), nil) which are fairly unreadable
This commit is contained in:
Reto Brunner 2021-01-30 11:33:31 +01:00
parent 9385827cae
commit 949781fa0a
5 changed files with 72 additions and 47 deletions

View file

@ -119,6 +119,5 @@ func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
} }
func unsubscribeHTTP(u *url.URL) error { func unsubscribeHTTP(u *url.URL) error {
lib.OpenFile(u.String(), nil) return lib.NewXDGOpen(u.String()).Start()
return nil
} }

View file

@ -1,7 +1,6 @@
package msgview package msgview
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -28,10 +27,6 @@ func (Open) Complete(aerc *widgets.Aerc, args []string) []string {
} }
func (Open) Execute(aerc *widgets.Aerc, args []string) error { func (Open) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: open")
}
mv := aerc.SelectedTab().(*widgets.MessageViewer) mv := aerc.SelectedTab().(*widgets.MessageViewer)
p := mv.SelectedMessagePart() p := mv.SelectedMessagePart()
@ -60,9 +55,22 @@ func (Open) Execute(aerc *widgets.Aerc, args []string) error {
return return
} }
lib.OpenFile(tmpFile.Name(), func(err error) { xdg := lib.NewXDGOpen(tmpFile.Name())
// pass through any arguments the user provided to the underlying handler
if len(args) > 1 {
xdg.SetArgs(args[1:])
}
err = xdg.Start()
if err != nil {
aerc.PushError(err.Error())
return
}
go func() {
err := xdg.Wait()
if err != nil {
aerc.PushError(" " + err.Error()) aerc.PushError(" " + err.Error())
}) }
}()
aerc.PushStatus("Opened", 10*time.Second) aerc.PushStatus("Opened", 10*time.Second)
}) })

View file

@ -307,9 +307,9 @@ message list, the message in the message viewer, etc).
Cycles between message parts being shown. The list of message parts is shown Cycles between message parts being shown. The list of message parts is shown
at the bottom of the message viewer. at the bottom of the message viewer.
*open* *open* [args...]
Saves the current message part in a temporary file and opens it Saves the current message part in a temporary file and opens it
with the system handler. with the system handler. Any given args are forwarded to the open handler
*save* [-fp] <path> *save* [-fp] <path>
Saves the current message part to the given path. Saves the current message part to the given path.

View file

@ -1,23 +1,62 @@
// +build !darwin
package lib package lib
import ( import (
"os/exec" "os/exec"
"runtime"
) )
func OpenFile(filename string, onErr func(error)) { var openBin string = "xdg-open"
cmd := exec.Command("xdg-open", filename)
err := cmd.Start() func init() {
if err != nil && onErr != nil { if runtime.GOOS == "darwin" {
onErr(err) openBin = "open"
return }
} }
type xdgOpen struct {
args []string
errCh chan (error)
cmd *exec.Cmd
}
// NewXDGOpen returns a handler for opening a file via the system handler xdg-open
// or comparable tools on other OSs than Linux
func NewXDGOpen(filename string) *xdgOpen {
errch := make(chan error, 1)
return &xdgOpen{
errCh: errch,
args: []string{filename},
}
}
// SetArgs sets additional arguments to the open command prior to the filename
func (xdg *xdgOpen) SetArgs(args []string) {
args = append([]string{}, args...) // don't overwrite array of caller
filename := xdg.args[len(xdg.args)-1]
xdg.args = append(args, filename)
}
// Start the open handler.
// Returns an error if the command could not be started.
// Use Wait to wait for the commands completion and to check the error.
func (xdg *xdgOpen) Start() error {
xdg.cmd = exec.Command(openBin, xdg.args...)
err := xdg.cmd.Start()
if err != nil {
xdg.errCh <- err // for callers that just check the error from Wait()
close(xdg.errCh)
return err
}
go func() { go func() {
err := cmd.Wait() xdg.errCh <- xdg.cmd.Wait()
if err != nil && onErr != nil { close(xdg.errCh)
onErr(err)
}
}() }()
return nil
}
// Wait for the xdg-open command to complete
// The xdgOpen must have been started
func (xdg *xdgOpen) Wait() error {
return <-xdg.errCh
} }

View file

@ -1,21 +0,0 @@
package lib
import (
"os/exec"
)
func OpenFile(filename string, onErr func(error)) {
cmd := exec.Command("open", filename)
err := cmd.Start()
if err != nil && onErr != nil {
onErr(err)
return
}
go func() {
err := cmd.Wait()
if err != nil && onErr != nil {
onErr(err)
}
}()
}