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:
parent
9a79154d05
commit
c679fd1924
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()}
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 ""
|
||||
//}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user