mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-15 11:56:37 +02:00
We pass all of them to a single editor command, hoping that the editor will be able to handle multiple files (VS Code and vim do). We ignore directories that happen to be in the selection range; this makes it easier to edit multiple files in different folders in tree view. We show an error if only directories are selected, though.
171 lines
4.9 KiB
Go
171 lines
4.9 KiB
Go
package git_commands
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
type FileCommands struct {
|
|
*GitCommon
|
|
}
|
|
|
|
func NewFileCommands(gitCommon *GitCommon) *FileCommands {
|
|
return &FileCommands{
|
|
GitCommon: gitCommon,
|
|
}
|
|
}
|
|
|
|
// Cat obtains the content of a file
|
|
func (self *FileCommands) Cat(fileName string) (string, error) {
|
|
buf, err := os.ReadFile(fileName)
|
|
if err != nil {
|
|
return "", nil
|
|
}
|
|
return string(buf), nil
|
|
}
|
|
|
|
func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) {
|
|
editor := self.UserConfig.OS.EditCommand
|
|
|
|
if editor == "" {
|
|
editor = self.config.GetCoreEditor()
|
|
}
|
|
if editor == "" {
|
|
editor = self.os.Getenv("GIT_EDITOR")
|
|
}
|
|
if editor == "" {
|
|
editor = self.os.Getenv("VISUAL")
|
|
}
|
|
if editor == "" {
|
|
editor = self.os.Getenv("EDITOR")
|
|
}
|
|
if editor == "" {
|
|
if err := self.cmd.New([]string{"which", "vi"}).DontLog().Run(); err == nil {
|
|
editor = "vi"
|
|
}
|
|
}
|
|
if editor == "" {
|
|
return "", errors.New("No editor defined in config file, $GIT_EDITOR, $VISUAL, $EDITOR, or git config")
|
|
}
|
|
|
|
templateValues := map[string]string{
|
|
"editor": editor,
|
|
"filename": self.cmd.Quote(filename),
|
|
"line": strconv.Itoa(lineNumber),
|
|
}
|
|
|
|
editCmdTemplate := self.UserConfig.OS.EditCommandTemplate
|
|
if len(editCmdTemplate) == 0 {
|
|
switch editor {
|
|
case "emacs", "nano", "vi", "vim", "nvim":
|
|
editCmdTemplate = "{{editor}} +{{line}} -- {{filename}}"
|
|
case "subl":
|
|
editCmdTemplate = "{{editor}} -- {{filename}}:{{line}}"
|
|
case "code":
|
|
editCmdTemplate = "{{editor}} -r --goto -- {{filename}}:{{line}}"
|
|
default:
|
|
editCmdTemplate = "{{editor}} -- {{filename}}"
|
|
}
|
|
}
|
|
return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil
|
|
}
|
|
|
|
func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) {
|
|
// Legacy support for old config; to be removed at some point
|
|
if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
|
// If multiple files are selected, we'll simply edit just the first one.
|
|
// It's not worth fixing this for the legacy support.
|
|
if cmdStr, err := self.GetEditCmdStrLegacy(filenames[0], 1); err == nil {
|
|
return cmdStr, true
|
|
}
|
|
}
|
|
|
|
template, suspend := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
|
quotedFilenames := lo.Map(filenames, func(filename string, _ int) string { return self.cmd.Quote(filename) })
|
|
|
|
templateValues := map[string]string{
|
|
"filename": strings.Join(quotedFilenames, " "),
|
|
}
|
|
|
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
|
return cmdStr, suspend
|
|
}
|
|
|
|
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
|
|
// Legacy support for old config; to be removed at some point
|
|
if self.UserConfig.OS.EditAtLine == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
|
return cmdStr, true
|
|
}
|
|
}
|
|
|
|
template, suspend := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
|
|
|
templateValues := map[string]string{
|
|
"filename": self.cmd.Quote(filename),
|
|
"line": strconv.Itoa(lineNumber),
|
|
}
|
|
|
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
|
return cmdStr, suspend
|
|
}
|
|
|
|
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
|
// Legacy support for old config; to be removed at some point
|
|
if self.UserConfig.OS.EditAtLineAndWait == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
|
return cmdStr
|
|
}
|
|
}
|
|
|
|
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
|
|
|
templateValues := map[string]string{
|
|
"filename": self.cmd.Quote(filename),
|
|
"line": strconv.Itoa(lineNumber),
|
|
}
|
|
|
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
|
return cmdStr
|
|
}
|
|
|
|
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
|
|
template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
|
|
|
templateValues := map[string]string{
|
|
"dir": self.cmd.Quote(path),
|
|
}
|
|
|
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
|
return cmdStr, suspend
|
|
}
|
|
|
|
func (self *FileCommands) guessDefaultEditor() string {
|
|
// Try to query a few places where editors get configured
|
|
editor := self.config.GetCoreEditor()
|
|
if editor == "" {
|
|
editor = self.os.Getenv("GIT_EDITOR")
|
|
}
|
|
if editor == "" {
|
|
editor = self.os.Getenv("VISUAL")
|
|
}
|
|
if editor == "" {
|
|
editor = self.os.Getenv("EDITOR")
|
|
}
|
|
|
|
if editor != "" {
|
|
// At this point, it might be more than just the name of the editor;
|
|
// e.g. it might be "code -w" or "vim -u myvim.rc". So assume that
|
|
// everything up to the first space is the editor name.
|
|
editor = strings.Split(editor, " ")[0]
|
|
}
|
|
|
|
return editor
|
|
}
|