Skip to content

Commit dc48cf9

Browse files
committed
Add config os.shellFunctionsFile
1 parent 41e9335 commit dc48cf9

File tree

10 files changed

+75
-24
lines changed

10 files changed

+75
-24
lines changed

docs/Config.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ os:
442442
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
443443
readFromClipboardCmd: ""
444444

445+
# A shell startup file containing shell aliases or shell functions. This will be sourced before running any shell commands, so that shell functions are available in the `:` command prompt or even in custom commands.
446+
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#using-aliases-or-functions-in-shell-commands
447+
shellFunctionsFile: ""
448+
445449
# If true, don't display introductory popups upon opening Lazygit.
446450
disableStartupPopups: false
447451

@@ -740,6 +744,21 @@ The `editInTerminal` option is used to decide whether lazygit needs to suspend i
740744

741745
Contributions of new editor presets are welcome; see the `getPreset` function in [`editor_presets.go`](https://github.com/jesseduffield/lazygit/blob/master/pkg/config/editor_presets.go).
742746

747+
## Using aliases or functions in shell commands
748+
749+
Lazygit has a command prompt (`:`) for quickly executing shell commands without having to quit lazygit or switch to a different terminal. Most people find it convenient to have their usual shell aliases or shell functions available at this prompt. To achieve this, put your alias definitions in a separate shell startup file (which you source from your normal startup file, i.e. from `.bashrc` or `.zshrc`), and then tell lazygit about this file like so:
750+
751+
```yml
752+
os:
753+
shellFunctionsFile: ~/.my_aliases.sh
754+
```
755+
756+
For many people it might work well enough to use their entire shell config file (`~/.bashrc` or `~/.zshrc`) as the `shellFunctionsFile`, but these config files typically do a lot more than defining aliases (e.g. initialize the completion system, start an ssh-agent, etc.) and this may unnecessarily delay execution of shell commands.
757+
758+
When using zsh, aliases can't be used here, but functions can. It is easy to convert your existing aliases into functions, just change `alias l="ls -la"` to `l() ls -la`, for example. This way it will work as before both in the shell and in lazygit.
759+
760+
Note that the shell aliases file is not only used when executing shell commands, but also for [custom commands](Custom_Command_Keybindings.md), and when opening a file in the editor.
761+
743762
## Overriding default config file location
744763

745764
To override the default config directory, use `CONFIG_DIR="$HOME/.config/lazygit"`. This directory contains the config file in addition to some other files lazygit uses to keep track of state across sessions.

pkg/commands/git_cmd_obj_builder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ func (self *gitCmdObjBuilder) New(args []string) oscommands.ICmdObj {
3434
return self.innerBuilder.New(args).AddEnvVars(defaultEnvVar)
3535
}
3636

37-
func (self *gitCmdObjBuilder) NewShell(cmdStr string) oscommands.ICmdObj {
38-
return self.innerBuilder.NewShell(cmdStr).AddEnvVars(defaultEnvVar)
37+
func (self *gitCmdObjBuilder) NewShell(cmdStr string, shellFunctionsFile string) oscommands.ICmdObj {
38+
return self.innerBuilder.NewShell(cmdStr, shellFunctionsFile).AddEnvVars(defaultEnvVar)
3939
}
4040

4141
func (self *gitCmdObjBuilder) Quote(str string) string {

pkg/commands/oscommands/cmd_obj_builder.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ type ICmdObjBuilder interface {
1313
// NewFromArgs takes a slice of strings like []string{"git", "commit"} and returns a new command object.
1414
New(args []string) ICmdObj
1515
// NewShell takes a string like `git commit` and returns an executable shell command for it e.g. `sh -c 'git commit'`
16-
NewShell(commandStr string) ICmdObj
16+
// shellFunctionsFile is an optional file path that will be sourced before executing the command. Callers should pass
17+
// the value of UserConfig.OS.ShellFunctionsFile.
18+
NewShell(commandStr string, shellFunctionsFile string) ICmdObj
1719
// Quote wraps a string in quotes with any necessary escaping applied. The reason for bundling this up with the other methods in this interface is that we basically always need to make use of this when creating new command objects.
1820
Quote(str string) string
1921
}
@@ -42,7 +44,10 @@ func (self *CmdObjBuilder) NewWithEnviron(args []string, env []string) ICmdObj {
4244
}
4345
}
4446

45-
func (self *CmdObjBuilder) NewShell(commandStr string) ICmdObj {
47+
func (self *CmdObjBuilder) NewShell(commandStr string, shellFunctionsFile string) ICmdObj {
48+
if len(shellFunctionsFile) > 0 {
49+
commandStr = fmt.Sprintf("%ssource %s\n%s", self.platform.PrefixForShellFunctionsFile, shellFunctionsFile, commandStr)
50+
}
4651
quotedCommand := self.quotedCommandString(commandStr)
4752
cmdArgs := str.ToArgv(fmt.Sprintf("%s %s %s", self.platform.Shell, self.platform.ShellArg, quotedCommand))
4853

pkg/commands/oscommands/os.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ type OSCommand struct {
3535

3636
// Platform stores the os state
3737
type Platform struct {
38-
OS string
39-
Shell string
40-
ShellArg string
41-
OpenCommand string
42-
OpenLinkCommand string
38+
OS string
39+
Shell string
40+
ShellArg string
41+
PrefixForShellFunctionsFile string
42+
OpenCommand string
43+
OpenLinkCommand string
4344
}
4445

4546
// NewOSCommand os command runner
@@ -90,7 +91,7 @@ func (c *OSCommand) OpenFile(filename string) error {
9091
"filename": c.Quote(filename),
9192
}
9293
command := utils.ResolvePlaceholderString(commandTemplate, templateValues)
93-
return c.Cmd.NewShell(command).Run()
94+
return c.Cmd.NewShell(command, c.UserConfig().OS.ShellFunctionsFile).Run()
9495
}
9596

9697
func (c *OSCommand) OpenLink(link string) error {
@@ -107,7 +108,7 @@ func (c *OSCommand) OpenLink(link string) error {
107108
}
108109

109110
command := utils.ResolvePlaceholderString(commandTemplate, templateValues)
110-
return c.Cmd.NewShell(command).Run()
111+
return c.Cmd.NewShell(command, c.UserConfig().OS.ShellFunctionsFile).Run()
111112
}
112113

113114
// Quote wraps a message in platform-specific quotation marks
@@ -296,7 +297,7 @@ func (c *OSCommand) CopyToClipboard(str string) error {
296297
cmdStr := utils.ResolvePlaceholderString(c.UserConfig().OS.CopyToClipboardCmd, map[string]string{
297298
"text": c.Cmd.Quote(str),
298299
})
299-
return c.Cmd.NewShell(cmdStr).Run()
300+
return c.Cmd.NewShell(cmdStr, c.UserConfig().OS.ShellFunctionsFile).Run()
300301
}
301302

302303
return clipboard.WriteAll(str)
@@ -307,7 +308,7 @@ func (c *OSCommand) PasteFromClipboard() (string, error) {
307308
var err error
308309
if c.UserConfig().OS.CopyToClipboardCmd != "" {
309310
cmdStr := c.UserConfig().OS.ReadFromClipboardCmd
310-
s, err = c.Cmd.NewShell(cmdStr).RunWithOutput()
311+
s, err = c.Cmd.NewShell(cmdStr, c.UserConfig().OS.ShellFunctionsFile).RunWithOutput()
311312
} else {
312313
s, err = clipboard.ReadAll()
313314
}
@@ -357,5 +358,5 @@ func (c *OSCommand) UpdateWindowTitle() error {
357358
return getWdErr
358359
}
359360
argString := fmt.Sprint("title ", filepath.Base(path), " - Lazygit")
360-
return c.Cmd.NewShell(argString).Run()
361+
return c.Cmd.NewShell(argString, c.UserConfig().OS.ShellFunctionsFile).Run()
361362
}

pkg/commands/oscommands/os_default_platform.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,33 @@
44
package oscommands
55

66
import (
7+
"os"
78
"runtime"
9+
"strings"
810
)
911

1012
func GetPlatform() *Platform {
13+
shell := getUserShell()
14+
15+
prefixForShellFunctionsFile := ""
16+
if strings.HasSuffix(shell, "bash") {
17+
prefixForShellFunctionsFile = "shopt -s expand_aliases\n"
18+
}
19+
1120
return &Platform{
12-
OS: runtime.GOOS,
13-
Shell: "bash",
14-
ShellArg: "-c",
15-
OpenCommand: "open {{filename}}",
16-
OpenLinkCommand: "open {{link}}",
21+
OS: runtime.GOOS,
22+
Shell: shell,
23+
ShellArg: "-c",
24+
PrefixForShellFunctionsFile: prefixForShellFunctionsFile,
25+
OpenCommand: "open {{filename}}",
26+
OpenLinkCommand: "open {{link}}",
1727
}
1828
}
29+
30+
func getUserShell() string {
31+
if shell := os.Getenv("SHELL"); shell != "" {
32+
return shell
33+
}
34+
35+
return "bash"
36+
}

pkg/config/user_config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ type OSConfig struct {
589589
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
590590
ReadFromClipboardCmd string `yaml:"readFromClipboardCmd,omitempty"`
591591

592+
// A shell startup file containing shell aliases or shell functions. This will be sourced before running any shell commands, so that shell functions are available in the `:` command prompt or even in custom commands.
593+
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#using-aliases-or-functions-in-shell-commands
594+
ShellFunctionsFile string `yaml:"shellFunctionsFile"`
595+
592596
// --------
593597

594598
// The following configs are all deprecated and kept for backward

pkg/gui/controllers/helpers/files_helper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ func (self *FilesHelper) OpenDirInEditor(path string) error {
7171
func (self *FilesHelper) callEditor(cmdStr string, suspend bool) error {
7272
if suspend {
7373
return self.c.RunSubprocessAndRefresh(
74-
self.c.OS().Cmd.NewShell(cmdStr),
74+
self.c.OS().Cmd.NewShell(cmdStr, self.c.UserConfig().OS.ShellFunctionsFile),
7575
)
7676
}
7777

78-
return self.c.OS().Cmd.NewShell(cmdStr).Run()
78+
return self.c.OS().Cmd.NewShell(cmdStr, self.c.UserConfig().OS.ShellFunctionsFile).Run()
7979
}
8080

8181
func (self *FilesHelper) OpenFile(filename string) error {

pkg/gui/controllers/shell_command_action.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (self *ShellCommandAction) Call() error {
3131

3232
self.c.LogAction(self.c.Tr.Actions.CustomCommand)
3333
return self.c.RunSubprocessAndRefresh(
34-
self.c.OS().Cmd.NewShell(command),
34+
self.c.OS().Cmd.NewShell(command, self.c.UserConfig().OS.ShellFunctionsFile),
3535
)
3636
},
3737
HandleDeleteSuggestion: func(index int) error {

pkg/gui/services/custom_commands/handler_creator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func (self *HandlerCreator) generateFindSuggestionsFunc(prompt *config.CustomCom
148148

149149
func (self *HandlerCreator) getCommandSuggestionsFn(command string) (func(string) []*types.Suggestion, error) {
150150
lines := []*types.Suggestion{}
151-
err := self.c.OS().Cmd.NewShell(command).RunAndProcessLines(func(line string) (bool, error) {
151+
err := self.c.OS().Cmd.NewShell(command, self.c.UserConfig().OS.ShellFunctionsFile).RunAndProcessLines(func(line string) (bool, error) {
152152
lines = append(lines, &types.Suggestion{Value: line, Label: line})
153153
return false, nil
154154
})
@@ -259,7 +259,7 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
259259
return err
260260
}
261261

262-
cmdObj := self.c.OS().Cmd.NewShell(cmdStr)
262+
cmdObj := self.c.OS().Cmd.NewShell(cmdStr, self.c.UserConfig().OS.ShellFunctionsFile)
263263

264264
if customCommand.Subprocess != nil && *customCommand.Subprocess {
265265
return self.c.RunSubprocessAndRefresh(cmdObj)

schema/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,10 @@
15591559
"type": "string",
15601560
"description": "ReadFromClipboardCmd is the command for reading the clipboard.\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard"
15611561
},
1562+
"shellFunctionsFile": {
1563+
"type": "string",
1564+
"description": "A shell startup file containing shell aliases or shell functions. This will be sourced before running any shell commands, so that shell functions are available in the `:` command prompt or even in custom commands.\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#using-aliases-or-functions-in-shell-commands"
1565+
},
15621566
"editCommand": {
15631567
"type": "string",
15641568
"description": "EditCommand is the command for editing a file.\nDeprecated: use Edit instead. Note that semantics are different:\nEditCommand is just the command itself, whereas Edit contains a\n\"{{filename}}\" variable."

0 commit comments

Comments
 (0)