summaryrefslogtreecommitdiffstats
path: root/pkg/gui/services/custom_commands
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/gui/services/custom_commands')
-rw-r--r--pkg/gui/services/custom_commands/handler_creator.go10
-rw-r--r--pkg/gui/services/custom_commands/menu_generator_test.go1
-rw-r--r--pkg/gui/services/custom_commands/models.go100
-rw-r--r--pkg/gui/services/custom_commands/resolver.go1
-rw-r--r--pkg/gui/services/custom_commands/session_state_loader.go182
5 files changed, 253 insertions, 41 deletions
diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go
index 9a127f362..c1cfe09cb 100644
--- a/pkg/gui/services/custom_commands/handler_creator.go
+++ b/pkg/gui/services/custom_commands/handler_creator.go
@@ -292,7 +292,15 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
if strings.TrimSpace(output) == "" {
output = self.c.Tr.EmptyOutput
}
- return self.c.Alert(cmdStr, output)
+
+ title := cmdStr
+ if customCommand.OutputTitle != "" {
+ title, err = resolveTemplate(customCommand.OutputTitle)
+ if err != nil {
+ return err
+ }
+ }
+ return self.c.Alert(title, output)
}
return nil
diff --git a/pkg/gui/services/custom_commands/menu_generator_test.go b/pkg/gui/services/custom_commands/menu_generator_test.go
index c17f7e93a..81480d1d8 100644
--- a/pkg/gui/services/custom_commands/menu_generator_test.go
+++ b/pkg/gui/services/custom_commands/menu_generator_test.go
@@ -81,7 +81,6 @@ func TestMenuGenerator(t *testing.T) {
}
for _, s := range scenarios {
- s := s
t.Run(s.testName, func(t *testing.T) {
s.test(NewMenuGenerator(utils.NewDummyCommon()).call(s.cmdOut, s.filter, s.valueFormat, s.labelFormat))
})
diff --git a/pkg/gui/services/custom_commands/models.go b/pkg/gui/services/custom_commands/models.go
new file mode 100644
index 000000000..261bace45
--- /dev/null
+++ b/pkg/gui/services/custom_commands/models.go
@@ -0,0 +1,100 @@
+package custom_commands
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/commands/models"
+ "github.com/stefanhaller/git-todo-parser/todo"
+)
+
+// We create shims for all the model classes in order to get a more stable API
+// for custom commands. At the moment these are almost identical to the model
+// classes, but this allows us to add "private" fields to the model classes that
+// we don't want to expose to custom commands, or rename a model field to a
+// better name without breaking people's custom commands. In such a case we add
+// the new, better name to the shim but keep the old one for backwards
+// compatibility. We already did this for Commit.Sha, which was renamed to Hash.
+
+type Commit struct {
+ Hash string // deprecated: use Sha
+ Sha string
+ Name string
+ Status models.CommitStatus
+ Action todo.TodoCommand
+ Tags []string
+ ExtraInfo string
+ AuthorName string
+ AuthorEmail string
+ UnixTimestamp int64
+ Divergence models.Divergence
+ Parents []string
+}
+
+type File struct {
+ Name string
+ PreviousName string
+ HasStagedChanges bool
+ HasUnstagedChanges bool
+ Tracked bool
+ Added bool
+ Deleted bool
+ HasMergeConflicts bool
+ HasInlineMergeConflicts bool
+ DisplayString string
+ ShortStatus string
+ IsWorktree bool
+}
+
+type Branch struct {
+ Name string
+ DisplayName string
+ Recency string
+ Pushables string // deprecated: use AheadForPull
+ Pullables string // deprecated: use BehindForPull
+ AheadForPull string
+ BehindForPull string
+ AheadForPush string
+ BehindForPush string
+ UpstreamGone bool
+ Head bool
+ DetachedHead bool
+ UpstreamRemote string
+ UpstreamBranch string
+ Subject string
+ CommitHash string
+}
+
+type RemoteBranch struct {
+ Name string
+ RemoteName string
+}
+
+type Remote struct {
+ Name string
+ Urls []string
+ Branches []*RemoteBranch
+}
+
+type Tag struct {
+ Name string
+ Message string
+}
+
+type StashEntry struct {
+ Index int
+ Recency string
+ Name string
+}
+
+type CommitFile struct {
+ Name string
+ ChangeStatus string
+}
+
+type Worktree struct {
+ IsMain bool
+ IsCurrent bool
+ Path string
+ IsPathMissing bool
+ GitDir string
+ Branch string
+ Name string
+}
diff --git a/pkg/gui/services/custom_commands/resolver.go b/pkg/gui/services/custom_commands/resolver.go
index 67dd7be2d..bf2697355 100644
--- a/pkg/gui/services/custom_commands/resolver.go
+++ b/pkg/gui/services/custom_commands/resolver.go
@@ -72,7 +72,6 @@ func (self *Resolver) resolvePrompt(
func (self *Resolver) resolveMenuOptions(prompt *config.CustomCommandPrompt, resolveTemplate func(string) (string, error)) ([]config.CustomCommandMenuOption, error) {
newOptions := make([]config.CustomCommandMenuOption, 0, len(prompt.Options))
for _, option := range prompt.Options {
- option := option
newOption, err := self.resolveMenuOption(&option, resolveTemplate)
if err != nil {
return nil, err
diff --git a/pkg/gui/services/custom_commands/session_state_loader.go b/pkg/gui/services/custom_commands/session_state_loader.go
index 93ce9d179..6f39c5f8c 100644
--- a/pkg/gui/services/custom_commands/session_state_loader.go
+++ b/pkg/gui/services/custom_commands/session_state_loader.go
@@ -1,9 +1,9 @@
package custom_commands
import (
- "github.com/fsmiamoto/git-todo-parser/todo"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
+ "github.com/samber/lo"
)
// loads the session state at the time that a custom command is invoked, for use
@@ -20,22 +20,7 @@ func NewSessionStateLoader(c *helpers.HelperCommon, refsHelper *helpers.RefsHelp
}
}
-type Commit struct {
- Hash string
- Sha string
- Name string
- Status models.CommitStatus
- Action todo.TodoCommand
- Tags []string
- ExtraInfo string
- AuthorName string
- AuthorEmail string
- UnixTimestamp int64
- Divergence models.Divergence
- Parents []string
-}
-
-func commitWrapperFromModelCommit(commit *models.Commit) *Commit {
+func commitShimFromModelCommit(commit *models.Commit) *Commit {
if commit == nil {
return nil
}
@@ -56,39 +41,160 @@ func commitWrapperFromModelCommit(commit *models.Commit) *Commit {
}
}
+func fileShimFromModelFile(file *models.File) *File {
+ if file == nil {
+ return nil
+ }
+
+ return &File{
+ Name: file.Name,
+ PreviousName: file.PreviousName,
+ HasStagedChanges: file.HasStagedChanges,
+ HasUnstagedChanges: file.HasUnstagedChanges,
+ Tracked: file.Tracked,
+ Added: file.Added,
+ Deleted: file.Deleted,
+ HasMergeConflicts: file.HasMergeConflicts,
+ HasInlineMergeConflicts: file.HasInlineMergeConflicts,
+ DisplayString: file.DisplayString,
+ ShortStatus: file.ShortStatus,
+ IsWorktree: file.IsWorktree,
+ }
+}
+
+func branchShimFromModelBranch(branch *models.Branch) *Branch {
+ if branch == nil {
+ return nil
+ }
+
+ return &Branch{
+ Name: branch.Name,
+ DisplayName: branch.DisplayName,
+ Recency: branch.Recency,
+ Pushables: branch.AheadForPull,
+ Pullables: branch.BehindForPull,
+ AheadForPull: branch.AheadForPull,
+ BehindForPull: branch.BehindForPull,
+ AheadForPush: branch.AheadForPush,
+ BehindForPush: branch.BehindForPush,
+ UpstreamGone: branch.UpstreamGone,
+ Head: branch.Head,
+ DetachedHead: branch.DetachedHead,
+ UpstreamRemote: branch.UpstreamRemote,
+ UpstreamBranch: branch.UpstreamBranch,
+ Subject: branch.Subject,
+ CommitHash: branch.CommitHash,
+ }
+}
+
+func remoteBranchShimFromModelRemoteBranch(remoteBranch *models.RemoteBranch) *RemoteBranch {
+ if remoteBranch == nil {
+ return nil
+ }
+
+ return &RemoteBranch{
+ Name: remoteBranch.Name,
+ RemoteName: remoteBranch.RemoteName,
+ }
+}
+
+func remoteShimFromModelRemote(remote *models.Remote) *Remote {
+ if remote == nil {
+ return nil
+ }
+
+ return &Remote{
+ Name: remote.Name,
+ Urls: remote.Urls,
+ Branches: lo.Map(remote.Branches, func(branch *models.RemoteBranch, _ int) *RemoteBranch {
+ return remoteBranchShimFromModelRemoteBranch(branch)
+ }),
+ }
+}
+
+func tagShimFromModelRemote(tag *models.Tag) *Tag {
+ if tag == nil {
+ return nil
+ }
+
+ return &Tag{
+ Name: tag.Name,
+ Message: tag.Message,
+ }
+}
+
+func stashEntryShimFromModelRemote(stashEntry *models.StashEntry) *StashEntry {
+ if stashEntry == nil {
+ return nil
+ }
+
+ return &StashEntry{
+ Index: stashEntry.Index,
+ Recency: stashEntry.Recency,
+ Name: stashEntry.Name,
+ }
+}
+
+func commitFileShimFromModelRemote(commitFile *models.CommitFile) *CommitFile {
+ if commitFile == nil {
+ return nil
+ }
+
+ return &CommitFile{
+ Name: commitFile.Name,
+ ChangeStatus: commitFile.ChangeStatus,
+ }
+}
+
+func worktreeShimFromModelRemote(worktree *models.Worktree) *Worktree {
+ if worktree == nil {
+ return nil
+ }
+
+ return &Worktree{
+ IsMain: worktree.IsMain,
+ IsCurrent: worktree.IsCurrent,
+ Path: worktree.Path,
+ IsPathMissing: worktree.IsPathMissing,
+ GitDir: worktree.GitDir,
+ Branch: worktree.Branch,
+ Name: worktree.Name,
+ }
+}
+
// SessionState captures the current state of the application for use in custom commands
type SessionState struct {
SelectedLocalCommit *Commit
SelectedReflogCommit *Commit
SelectedSubCommit *Commit
- SelectedFile *models.File
+ SelectedFile *File
SelectedPath string
- SelectedLocalBranch *models.Branch
- SelectedRemoteBranch *models.RemoteBranch
- SelectedRemote *models.Remote
- SelectedTag *models.Tag
- SelectedStashEntry *models.StashEntry
- SelectedCommitFile *models.CommitFile
+ SelectedLocalBranch *Branch
+ SelectedRemoteBranch *RemoteBranch
+ SelectedRemote *Remote
+ SelectedTag *Tag
+ SelectedStashEntry *StashEntry
+ SelectedCommitFile *CommitFile
SelectedCommitFilePath string
- SelectedWorktree *models.Worktree
- CheckedOutBranch *models.Branch
+ SelectedWorktree *Worktree
+ CheckedOutBranch *Branch
}
func (self *SessionStateLoader) call() *SessionState {
return &SessionState{
- SelectedFile: self.c.Contexts().Files.GetSelectedFile(),
+ SelectedFile: fileShimFromModelFile(self.c.Contexts().Files.GetSelectedFile()),
SelectedPath: self.c.Contexts().Files.GetSelectedPath(),
- SelectedLocalCommit: commitWrapperFromModelCommit(self.c.Contexts().LocalCommits.GetSelected()),
- SelectedReflogCommit: commitWrapperFromModelCommit(self.c.Contexts().ReflogCommits.GetSelected()),
- SelectedLocalBranch: self.c.Contexts().Branches.GetSelected(),
- SelectedRemoteBranch: self.c.Contexts().RemoteBranches.GetSelected(),
- SelectedRemote: self.c.Contexts().Remotes.GetSelected(),
- SelectedTag: self.c.Contexts().Tags.GetSelected(),
- SelectedStashEntry: self.c.Contexts().Stash.GetSelected(),
- SelectedCommitFile: self.c.Contexts().CommitFiles.GetSelectedFile(),
+ SelectedLocalCommit: commitShimFromModelCommit(self.c.Contexts().LocalCommits.GetSelected()),
+ SelectedReflogCommit: commitShimFromModelCommit(self.c.Contexts().ReflogCommits.GetSelected()),
+ SelectedLocalBranch: branchShimFromModelBranch(self.c.Contexts().Branches.GetSelected()),
+ SelectedRemoteBranch: remoteBranchShimFromModelRemoteBranch(self.c.Contexts().RemoteBranches.GetSelected()),
+ SelectedRemote: remoteShimFromModelRemote(self.c.Contexts().Remotes.GetSelected()),
+ SelectedTag: tagShimFromModelRemote(self.c.Contexts().Tags.GetSelected()),
+ SelectedStashEntry: stashEntryShimFromModelRemote(self.c.Contexts().Stash.GetSelected()),
+ SelectedCommitFile: commitFileShimFromModelRemote(self.c.Contexts().CommitFiles.GetSelectedFile()),
SelectedCommitFilePath: self.c.Contexts().CommitFiles.GetSelectedPath(),
- SelectedSubCommit: commitWrapperFromModelCommit(self.c.Contexts().SubCommits.GetSelected()),
- SelectedWorktree: self.c.Contexts().Worktrees.GetSelected(),
- CheckedOutBranch: self.refsHelper.GetCheckedOutRef(),
+ SelectedSubCommit: commitShimFromModelCommit(self.c.Contexts().SubCommits.GetSelected()),
+ SelectedWorktree: worktreeShimFromModelRemote(self.c.Contexts().Worktrees.GetSelected()),
+ CheckedOutBranch: branchShimFromModelBranch(self.refsHelper.GetCheckedOutRef()),
}
}