1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-01-22 05:29:44 +02:00

WIP using runDirectCommand with xdg-open

This commit is contained in:
Jesse Duffield 2018-08-31 18:43:54 +10:00
parent cff1dee6dc
commit ae0d88f855
10 changed files with 51 additions and 65 deletions

View File

@ -73,7 +73,7 @@ func NewApp(config config.AppConfigurer) (*App, error) {
} }
var err error var err error
app.Log = newLogger(config) app.Log = newLogger(config)
app.OSCommand = commands.NewOSCommand(app.Log) app.OSCommand = commands.NewOSCommand(app.Log, config)
app.Tr = i18n.NewLocalizer(app.Log) app.Tr = i18n.NewLocalizer(app.Log)

View File

@ -6,7 +6,8 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/davecgh/go-spew/spew" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mgutz/str" "github.com/mgutz/str"
@ -20,22 +21,25 @@ type Platform struct {
shell string shell string
shellArg string shellArg string
escapedQuote string escapedQuote string
openCommand string
} }
// OSCommand holds all the os commands // OSCommand holds all the os commands
type OSCommand struct { type OSCommand struct {
Log *logrus.Entry Log *logrus.Entry
Platform *Platform Platform *Platform
Config config.AppConfigurer
command func(string, ...string) *exec.Cmd command func(string, ...string) *exec.Cmd
getGlobalGitConfig func(string) (string, error) getGlobalGitConfig func(string) (string, error)
getenv func(string) string getenv func(string) string
} }
// NewOSCommand os command runner // NewOSCommand os command runner
func NewOSCommand(log *logrus.Entry) *OSCommand { func NewOSCommand(log *logrus.Entry, config config.AppConfigurer) *OSCommand {
return &OSCommand{ return &OSCommand{
Log: log, Log: log,
Platform: getPlatform(), Platform: getPlatform(),
Config: config,
command: exec.Command, command: exec.Command,
getGlobalGitConfig: gitconfig.Global, getGlobalGitConfig: gitconfig.Global,
getenv: os.Getenv, getenv: os.Getenv,
@ -74,12 +78,10 @@ func (c *OSCommand) FileType(path string) string {
// RunDirectCommand wrapper around direct commands // RunDirectCommand wrapper around direct commands
func (c *OSCommand) RunDirectCommand(command string) (string, error) { func (c *OSCommand) RunDirectCommand(command string) (string, error) {
c.Log.WithField("command", command).Info("RunDirectCommand") c.Log.WithField("command", command).Info("RunDirectCommand")
args := str.ToArgv(c.Platform.shellArg + " " + command)
c.Log.Info(spew.Sdump(args))
return sanitisedCommandOutput( return sanitisedCommandOutput(
exec. exec.
Command(c.Platform.shell, args...). Command(c.Platform.shell, c.Platform.shellArg, command).
CombinedOutput(), CombinedOutput(),
) )
} }
@ -95,45 +97,23 @@ func sanitisedCommandOutput(output []byte, err error) (string, error) {
} }
// getOpenCommand get open command // getOpenCommand get open command
func (c *OSCommand) getOpenCommand() (string, string, error) { func (c *OSCommand) getOpenCommand() string {
//NextStep open equivalents: xdg-open (linux), cygstart (cygwin), open (OSX) if c.Config.GetUserConfig().IsSet("os.openCommand") {
trailMap := map[string]string{ return c.Config.GetUserConfig().GetString("os.openCommand")
"xdg-open": " &>/dev/null &",
"cygstart": "",
"open": "",
} }
return c.Platform.openCommand
for name, trail := range trailMap {
if err := c.RunCommand("which " + name); err == nil {
return name, trail, nil
}
}
return "", "", errors.New("Unsure what command to use to open this file")
}
// VsCodeOpenFile opens the file in code, with the -r flag to open in the
// current window
// each of these open files needs to have the same function signature because
// they're being passed as arguments into another function,
// but only editFile actually returns a *exec.Cmd
func (c *OSCommand) VsCodeOpenFile(filename string) (*exec.Cmd, error) {
return nil, c.RunCommand("code -r " + filename)
}
// SublimeOpenFile opens the filein sublime
// may be deprecated in the future
func (c *OSCommand) SublimeOpenFile(filename string) (*exec.Cmd, error) {
return nil, c.RunCommand("subl " + filename)
} }
// OpenFile opens a file with the given // OpenFile opens a file with the given
func (c *OSCommand) OpenFile(filename string) error { func (c *OSCommand) OpenFile(filename string) error {
cmdName, cmdTrail, err := c.getOpenCommand() commandTemplate := c.getOpenCommand()
if err != nil { templateValues := map[string]string{
return err "filename": c.Quote(filename),
} }
return c.RunCommand(cmdName + " " + c.Quote(filename) + cmdTrail) // TODO: test on linux command := utils.ResolvePlaceholderString(commandTemplate, templateValues)
_, err := c.RunDirectCommand(command)
return err
} }
// EditFile opens a file in a subprocess using whatever editor is available, // EditFile opens a file in a subprocess using whatever editor is available,

View File

@ -12,5 +12,6 @@ func getPlatform() *Platform {
shell: "bash", shell: "bash",
shellArg: "-c", shellArg: "-c",
escapedQuote: "\"", escapedQuote: "\"",
openCommand: "open {{filename}}",
} }
} }

15
pkg/commands/os_linux.go Normal file
View File

@ -0,0 +1,15 @@
package commands
import (
"runtime"
)
func getPlatform() *Platform {
return &Platform{
os: runtime.GOOS,
shell: "bash",
shellArg: "-c",
escapedQuote: "\"",
openCommand: "xdg-open {{filename}} &>/dev/null &",
}
}

View File

@ -6,5 +6,6 @@ func getPlatform() *Platform {
shell: "cmd", shell: "cmd",
shellArg: "/c", shellArg: "/c",
escapedQuote: "\\\"", escapedQuote: "\\\"",
openCommand: "cygstart {{filename}}",
} }
} }

View File

@ -218,9 +218,9 @@ func GetDefaultConfig() []byte {
- white - white
optionsTextColor: optionsTextColor:
- blue - blue
git: # git:
# stuff relating to git # stuff relating to git
os: # os:
# stuff relating to the OS # stuff relating to the OS
update: update:
method: prompt # can be: prompt | background | never method: prompt # can be: prompt | background | never

View File

@ -7,7 +7,6 @@ import (
// "strings" // "strings"
"os/exec"
"strings" "strings"
"github.com/fatih/color" "github.com/fatih/color"
@ -250,11 +249,10 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) {
}) })
} }
func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, filename string, open func(string) (*exec.Cmd, error)) error { func (gui *Gui) editFile(filename string) error {
sub, err := gui.OSCommand.EditFile(filename)
sub, err := open(filename)
if err != nil { if err != nil {
return gui.createErrorPanel(g, err.Error()) return gui.createErrorPanel(gui.g, err.Error())
} }
if sub != nil { if sub != nil {
gui.SubProcess = sub gui.SubProcess = sub
@ -268,7 +266,8 @@ func (gui *Gui) handleFileEdit(g *gocui.Gui, v *gocui.View) error {
if err != nil { if err != nil {
return err return err
} }
return gui.genericFileOpen(g, v, file.Name, gui.OSCommand.EditFile)
return gui.editFile(file.Name)
} }
func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
@ -279,22 +278,6 @@ func (gui *Gui) handleFileOpen(g *gocui.Gui, v *gocui.View) error {
return gui.openFile(file.Name) return gui.openFile(file.Name)
} }
func (gui *Gui) handleSublimeFileOpen(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
return err
}
return gui.genericFileOpen(g, v, file.Name, gui.OSCommand.SublimeOpenFile)
}
func (gui *Gui) handleVsCodeFileOpen(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
return err
}
return gui.genericFileOpen(g, v, file.Name, gui.OSCommand.VsCodeOpenFile)
}
func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error {
return gui.refreshFiles(g) return gui.refreshFiles(g)
} }

View File

@ -34,8 +34,6 @@ func (gui *Gui) keybindings(g *gocui.Gui) error {
{ViewName: "files", Key: 'm', Modifier: gocui.ModNone, Handler: gui.handleSwitchToMerge}, {ViewName: "files", Key: 'm', Modifier: gocui.ModNone, Handler: gui.handleSwitchToMerge},
{ViewName: "files", Key: 'e', Modifier: gocui.ModNone, Handler: gui.handleFileEdit}, {ViewName: "files", Key: 'e', Modifier: gocui.ModNone, Handler: gui.handleFileEdit},
{ViewName: "files", Key: 'o', Modifier: gocui.ModNone, Handler: gui.handleFileOpen}, {ViewName: "files", Key: 'o', Modifier: gocui.ModNone, Handler: gui.handleFileOpen},
{ViewName: "files", Key: 's', Modifier: gocui.ModNone, Handler: gui.handleSublimeFileOpen},
{ViewName: "files", Key: 'v', Modifier: gocui.ModNone, Handler: gui.handleVsCodeFileOpen},
{ViewName: "files", Key: 'i', Modifier: gocui.ModNone, Handler: gui.handleIgnoreFile}, {ViewName: "files", Key: 'i', Modifier: gocui.ModNone, Handler: gui.handleIgnoreFile},
{ViewName: "files", Key: 'r', Modifier: gocui.ModNone, Handler: gui.handleRefreshFiles}, {ViewName: "files", Key: 'r', Modifier: gocui.ModNone, Handler: gui.handleRefreshFiles},
{ViewName: "files", Key: 'S', Modifier: gocui.ModNone, Handler: gui.handleStashSave}, {ViewName: "files", Key: 'S', Modifier: gocui.ModNone, Handler: gui.handleStashSave},

View File

@ -76,7 +76,7 @@ func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleEditConfig(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleEditConfig(g *gocui.Gui, v *gocui.View) error {
filename := gui.Config.GetUserConfig().ConfigFileUsed() filename := gui.Config.GetUserConfig().ConfigFileUsed()
return gui.genericFileOpen(g, v, filename, gui.OSCommand.EditFile) return gui.editFile(filename)
} }
func lazygitTitle() string { func lazygitTitle() string {

View File

@ -90,3 +90,11 @@ func Loader() string {
index := nanos / 50000000 % int64(len(characters)) index := nanos / 50000000 % int64(len(characters))
return characters[index : index+1] return characters[index : index+1]
} }
// ResolvePlaceholderString populates a template with values
func ResolvePlaceholderString(str string, arguments map[string]string) string {
for key, value := range arguments {
str = strings.Replace(str, "{{"+key+"}}", value, -1)
}
return str
}