1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-05 15:15:49 +02:00

Style missing worktree as red and display better error when trying to switch to them

Use a broken link icon for missing worktrees
This commit is contained in:
Joel Baranick 2022-09-02 09:35:08 -07:00 committed by Jesse Duffield
parent 9a79154d05
commit c679fd1924
10 changed files with 103 additions and 85 deletions

View File

@ -1,10 +1,6 @@
package git_commands
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@ -28,11 +24,6 @@ func NewWorktreeLoader(
}
func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
currentDir, err := os.Getwd()
if err != nil {
return nil, err
}
cmdArgs := NewGitCmd("worktree").Arg("list", "--porcelain", "-z").ToArgv()
worktreesOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err != nil {
@ -51,25 +42,9 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
}
if strings.HasPrefix(splitLine, "worktree ") {
path := strings.SplitN(splitLine, " ", 2)[1]
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
// Ignore because the worktree is points to a non-existing filesystem location
continue
}
main := false
name := "main"
if len(worktrees) == 0 {
main = true
} else {
name = filepath.Base(path)
}
currentWorktree = &models.Worktree{
Name: name,
Id: len(worktrees),
Path: path,
Main: main,
Current: path == currentDir,
}
}
}

View File

@ -1,15 +1,22 @@
package models
import (
"fmt"
"github.com/go-errors/errors"
"io/fs"
"log"
"os"
"path/filepath"
)
// Worktree : A git worktree
type Worktree struct {
Name string
Main bool
Current bool
Id int
Path string
}
func (w *Worktree) RefName() string {
return w.Name
return w.Name()
}
func (w *Worktree) ID() string {
@ -19,3 +26,30 @@ func (w *Worktree) ID() string {
func (w *Worktree) Description() string {
return w.RefName()
}
func (w *Worktree) Name() string {
return filepath.Base(w.Path)
}
func (w *Worktree) Main() bool {
return w.Id == 0
}
func (w *Worktree) Current() bool {
pwd, err := os.Getwd()
if err != nil {
log.Fatalln(err.Error())
}
return pwd == w.Path
}
func (w *Worktree) Missing() bool {
if _, err := os.Stat(w.Path); err != nil {
if errors.Is(err, fs.ErrNotExist) {
return true
}
log.Fatalln(fmt.Errorf("failed to check if worktree path `%s` exists\n%w", w.Path, err).Error())
}
return false
}

View File

@ -17,7 +17,7 @@ func NewWorktreesContext(c *ContextCommon) *WorktreesContext {
viewModel := NewFilteredListViewModel(
func() []*models.Worktree { return c.Model().Worktrees },
func(Worktree *models.Worktree) []string {
return []string{Worktree.Name}
return []string{Worktree.Name()}
},
)

View File

@ -638,16 +638,13 @@ func (self *RefreshHelper) refreshStatus() {
}
name := presentation.GetBranchTextStyle(currentBranch.Name).Sprint(currentBranch.Name)
var repoName string
worktreeName := self.worktreeHelper.GetCurrentWorktreeName()
if len(worktreeName) > 0 {
worktreeName = fmt.Sprintf("[%s]", worktreeName)
repoName = self.worktreeHelper.GetMainWorktreeName()
} else {
repoName = utils.GetCurrentRepoName()
mainWorktreeName := self.worktreeHelper.GetMainWorktreeName()
if repoName != mainWorktreeName {
repoName = fmt.Sprintf("%s(%s)", mainWorktreeName, style.FgBlue.Sprint(repoName))
}
status += fmt.Sprintf("%s%s → %s ", repoName, worktreeName, name)
status += fmt.Sprintf("%s → %s ", repoName, name)
self.c.SetViewContent(self.c.Views().Status, status)
}

View File

@ -138,6 +138,10 @@ func (self *ReposHelper) CreateRecentReposMenu() error {
}
func (self *ReposHelper) DispatchSwitchToRepo(path string, reuse bool) error {
return self.DispatchSwitchTo(path, reuse, self.c.Tr.ErrRepositoryMovedOrDeleted)
}
func (self *ReposHelper) DispatchSwitchTo(path string, reuse bool, errMsg string) error {
env.UnsetGitDirEnvs()
originalPath, err := os.Getwd()
if err != nil {
@ -146,7 +150,7 @@ func (self *ReposHelper) DispatchSwitchToRepo(path string, reuse bool) error {
if err := os.Chdir(path); err != nil {
if os.IsNotExist(err) {
return self.c.ErrorMsg(self.c.Tr.ErrRepositoryMovedOrDeleted)
return self.c.ErrorMsg(errMsg)
}
return err
}

View File

@ -1,9 +1,5 @@
package helpers
import (
"path/filepath"
)
type IWorktreeHelper interface {
GetMainWorktreeName() string
GetCurrentWorktreeName() string
@ -21,23 +17,23 @@ func NewWorktreeHelper(c *HelperCommon) *WorktreeHelper {
func (self *WorktreeHelper) GetMainWorktreeName() string {
for _, worktree := range self.c.Model().Worktrees {
if worktree.Main {
return filepath.Base(worktree.Path)
if worktree.Main() {
return worktree.Name()
}
}
return ""
}
func (self *WorktreeHelper) GetCurrentWorktreeName() string {
for _, worktree := range self.c.Model().Worktrees {
if worktree.Current {
if worktree.Main {
return ""
}
return worktree.Name
}
}
return ""
}
//func (self *WorktreeHelper) GetCurrentWorktreeName() string {
// for _, worktree := range self.c.Model().Worktrees {
// if worktree.Current() {
// if worktree.Main() {
// return ""
// }
// return worktree.Name()
// }
// }
//
// return ""
//}

View File

@ -2,7 +2,6 @@ package controllers
import (
"fmt"
"os"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
@ -56,7 +55,11 @@ func (self *WorktreesController) GetOnRenderToMain() func() error {
if worktree == nil {
task = types.NewRenderStringTask("No worktrees")
} else {
task = types.NewRenderStringTask(fmt.Sprintf("%s\nPath: %s", style.FgGreen.Sprint(worktree.Name), worktree.Path))
missing := ""
if worktree.Missing() {
missing = style.FgRed.Sprint(" (missing)")
}
task = types.NewRenderStringTask(fmt.Sprintf("%s\nPath: %s%s", style.FgGreen.Sprint(worktree.Name()), worktree.Path, missing))
}
return self.c.RenderToMainViews(types.RefreshMainOpts{
@ -86,11 +89,11 @@ func (self *WorktreesController) GetOnRenderToMain() func() error {
//}
func (self *WorktreesController) delete(worktree *models.Worktree) error {
if worktree.Main {
if worktree.Main() {
return self.c.ErrorMsg(self.c.Tr.CantDeleteMainWorktree)
}
if worktree.Current {
if worktree.Current() {
return self.c.ErrorMsg(self.c.Tr.CantDeleteCurrentWorktree)
}
@ -108,7 +111,7 @@ func (self *WorktreesController) deleteWithForce(worktree *models.Worktree, forc
message := utils.ResolvePlaceholderString(
templateStr,
map[string]string{
"worktreeName": worktree.Name,
"worktreeName": worktree.Name(),
},
)
@ -170,14 +173,11 @@ func (self *WorktreesController) GetOnClick() func() error {
}
func (self *WorktreesController) enter(worktree *models.Worktree) error {
wd, err := os.Getwd()
if err != nil {
return err
}
// if we were in a submodule, we want to forget about that stack of repos
// so that hitting escape in the new repo does nothing
self.c.State().GetRepoPathStack().Clear()
self.c.State().GetRepoPathStack().Push(wd)
return self.c.Helpers().Repos.DispatchSwitchToRepo(worktree.Path, true)
return self.c.Helpers().Repos.DispatchSwitchTo(worktree.Path, true, self.c.Tr.ErrWorktreeMovedOrDeleted)
}
func (self *WorktreesController) checkSelected(callback func(worktree *models.Worktree) error) func() error {

View File

@ -15,6 +15,7 @@ var (
DEFAULT_REMOTE_ICON = "\uf02a2" // 󰊢
STASH_ICON = "\uf01c" // 
LINKED_WORKTREE_ICON = "\uf838" // 
MISSING_LINKED_WORKTREE_ICON = "\uf839" // 
)
var remoteIcons = map[string]string{
@ -70,9 +71,12 @@ func IconForStash(stash *models.StashEntry) string {
return STASH_ICON
}
func IconForWorktree(worktree *models.Worktree) string {
if worktree.Main {
func IconForWorktree(worktree *models.Worktree, missing bool) string {
if worktree.Main() {
return ""
}
if missing {
return MISSING_LINKED_WORKTREE_ICON
}
return LINKED_WORKTREE_ICON
}

View File

@ -20,16 +20,22 @@ func getWorktreeDisplayStrings(w *models.Worktree) []string {
current := ""
currentColor := style.FgCyan
if w.Current {
if w.Current() {
current = " *"
currentColor = style.FgGreen
}
icon := icons.IconForWorktree(w, false)
if w.Missing() {
textStyle = style.FgRed
icon = icons.IconForWorktree(w, true)
}
res := make([]string, 0, 3)
res = append(res, currentColor.Sprint(current))
if icons.IsIconEnabled() {
res = append(res, textStyle.Sprint(icons.IconForWorktree(w)))
res = append(res, textStyle.Sprint(icon))
}
res = append(res, textStyle.Sprint(w.Name))
res = append(res, textStyle.Sprint(w.Name()))
return res
}

View File

@ -482,6 +482,7 @@ type TranslationSet struct {
ErrCannotEditDirectory string
ErrStageDirWithInlineMergeConflicts string
ErrRepositoryMovedOrDeleted string
ErrWorktreeMovedOrDeleted string
CommandLog string
ToggleShowCommandLog string
FocusCommandLog string
@ -1191,6 +1192,7 @@ func EnglishTranslationSet() TranslationSet {
ErrStageDirWithInlineMergeConflicts: "Cannot stage/unstage directory containing files with inline merge conflicts. Please fix up the merge conflicts first",
ErrRepositoryMovedOrDeleted: "Cannot find repo. It might have been moved or deleted ¯\\_(ツ)_/¯",
CommandLog: "Command log",
ErrWorktreeMovedOrDeleted: "Cannot find worktree. It might have been moved or deleted ¯\\_(ツ)_/¯",
ToggleShowCommandLog: "Toggle show/hide command log",
FocusCommandLog: "Focus command log",
CommandLogHeader: "You can hide/focus this panel by pressing '%s'\n",