Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: recent repos management #4086

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions pkg/config/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ type ConfigFile struct {
exists bool
}

type RecentReposPolicy int

const (
RecentReposPolicyPerRepoConfirmation RecentReposPolicy = iota
RecentReposPolicyAcceptAll
RecentReposPolicyRejectAll
)

// NewAppConfig makes a new app config
func NewAppConfig(
name string,
Expand Down Expand Up @@ -448,6 +456,7 @@ func (c *AppConfig) SaveGlobalUserConfig() {
type AppState struct {
LastUpdateCheck int64
RecentRepos []string
RecentReposPolicy RecentReposPolicy
StartupPopupVersion int
LastVersion string // this is the last version the user was using, for the purpose of showing release notes

Expand Down Expand Up @@ -476,6 +485,7 @@ func getDefaultAppState() *AppState {
return &AppState{
LastUpdateCheck: 0,
RecentRepos: []string{},
RecentReposPolicy: RecentReposPolicyPerRepoConfirmation,
StartupPopupVersion: 0,
LastVersion: "",
DiffContextSize: 3,
Expand Down
45 changes: 45 additions & 0 deletions pkg/gui/controllers/helpers/repos_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"sync"

Expand Down Expand Up @@ -137,9 +138,53 @@ func (self *ReposHelper) CreateRecentReposMenu() error {
}
})

// TODO: At this point maybe just re-do the recent repos menu to a prompt? I'm basically re-doing it...
section := types.MenuSection{
Title: "Actions",
}

menuItems = append(menuItems, &types.MenuItem{
// TODO: i18n
Label: "Delete item",
OpensMenu: true,
Section: &section,
OnPress: func() error {
self.c.Prompt(types.PromptOpts{
// TODO: i18n
Title: "Delete from recent repositories",
AllowEditSuggestion: false,
FindSuggestionsFunc: self.GetRecentReposSuggestionsFunc(recentRepoPaths),
HandleConfirm: func(string) error { return nil },
HandleClose: func() error { return nil },
HandleDeleteSuggestion: func(index int) error {
// TODO: copied from the shell command one, might be worth pulling this out into a shared function?
item := self.c.Contexts().Suggestions.GetItems()[index].Value
fullIndex := lo.IndexOf(self.c.GetAppState().RecentRepos, item)
if fullIndex == -1 {
self.c.Log.Warnf("Failed to find this repo in the app state %s", item)
return nil
}

self.c.GetAppState().RecentRepos = slices.Delete(self.c.GetAppState().RecentRepos, fullIndex, fullIndex+1)
self.c.SaveAppStateAndLogError()
self.c.Contexts().Suggestions.RefreshSuggestions()
return nil
},
})

return nil
},
})

return self.c.Menu(types.CreateMenuOptions{Title: self.c.Tr.RecentRepos, Items: menuItems})
}

func (self *ReposHelper) GetRecentReposSuggestionsFunc(recentRepoPaths []string) func(string) []*types.Suggestion {
return func(input string) []*types.Suggestion {
return FilterFunc(recentRepoPaths, self.c.UserConfig().Gui.UseFuzzySearch())(input)
}
}

func (self *ReposHelper) DispatchSwitchToRepo(path string, contextKey types.ContextKey) error {
return self.DispatchSwitchTo(path, self.c.Tr.ErrRepositoryMovedOrDeleted, contextKey)
}
Expand Down
80 changes: 73 additions & 7 deletions pkg/gui/recent_repos_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package gui
import (
"os"
"path/filepath"

"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)

// updateRecentRepoList registers the fact that we opened lazygit in this repo,
Expand All @@ -16,17 +19,80 @@ func (gui *Gui) updateRecentRepoList() error {
return nil
}

recentRepos := gui.c.GetAppState().RecentRepos
originalRepos := gui.c.GetAppState().RecentRepos
currentRepo, err := os.Getwd()
if err != nil {
return err
}
known, recentRepos := newRecentReposList(recentRepos, currentRepo)
gui.IsNewRepo = known
// TODO: migrate this file to use forward slashes on all OSes for consistency
// (windows uses backslashes at the moment)
gui.c.GetAppState().RecentRepos = recentRepos
return gui.c.SaveAppState()

isNew, updatedRepos := newRecentReposList(originalRepos, currentRepo)

setRecentRepos := func(repos []string) error {
// TODO: migrate this file to use forward slashes on all OSes for consistency
// (windows uses backslashes at the moment)
gui.c.GetAppState().RecentRepos = repos

return gui.c.SaveAppState()
}

denyRepo := func() error { return setRecentRepos(originalRepos) }
acceptRepo := func() error { return setRecentRepos(updatedRepos) }

if !isNew {
return acceptRepo()
}

menuSection := types.MenuSection{
Title: "Policy",
Column: 0,
}

getRadioState := func(policy config.RecentReposPolicy) bool {
return gui.c.GetAppState().RecentReposPolicy == policy
}

// TODO: how can we make our radio selection without exiting the menu?
// I want to select one then press confirm
setRecentReposPolicy := func(policy config.RecentReposPolicy) error {
gui.c.GetAppState().RecentReposPolicy = policy
return gui.c.SaveAppState()
}

menuItems := []*types.MenuItem{
{
Label: "Accept",
OnPress: acceptRepo,
},
{
Label: "Deny",
OnPress: denyRepo,
},
{
Label: "Per-repo confirmation",
Widget: types.MakeMenuRadioButton(getRadioState(config.RecentReposPolicyPerRepoConfirmation)),
OnPress: func() error { return setRecentReposPolicy(config.RecentReposPolicyPerRepoConfirmation) },
Section: &menuSection,
},
{
Label: "Accept all",
Widget: types.MakeMenuRadioButton(getRadioState(config.RecentReposPolicyAcceptAll)),
OnPress: func() error { return setRecentReposPolicy(config.RecentReposPolicyAcceptAll) },
Section: &menuSection,
},
{
Label: "Reject all",
Widget: types.MakeMenuRadioButton(getRadioState(config.RecentReposPolicyRejectAll)),
OnPress: func() error { return setRecentReposPolicy(config.RecentReposPolicyRejectAll) },
Section: &menuSection,
},
}

return gui.c.Menu(types.CreateMenuOptions{
Title: "Add to recent repos",
Prompt: "Repo: " + currentRepo,
Items: menuItems,
HideCancel: true,
})
}

// newRecentReposList returns a new repo list with a new entry but only when it doesn't exist yet
Expand Down