ronantakizawa/codereview-bench huggingface dataset:
Repository: jesseduffield/lazygit
File: pkg/integration/components/view_driver.go (Go)

Code before:

	return self
}

func (self *ViewDriver) Press(keyStr string) *ViewDriver {
	self.IsFocused()

	self.t.press(keyStr)

	return self
}

// for use when typing or navigating, because in demos we want that to happen
// faster
func (self *ViewDriver) PressFast(keyStr string) *ViewDriver {
	self.IsFocused()

	self.t.pressFast(keyStr)

	return self
}

// i.e. pressing down arrow
func (self *ViewDriver) SelectNextItem() *ViewDriver {
	return self.PressFast(self.t.keys.Universal.NextItem)
}

// i.e. pressing up arrow
func (self *ViewDriver) SelectPreviousItem() *ViewDriver {
	return self.PressFast(self.t.keys.Universal.PrevItem)
}

// i.e. pressing space
func (self *ViewDriver) PressPrimaryAction() *ViewDriver {
	return self.Press(self.t.keys.Universal.Select)
}

// i.e. pressing space
func (self *ViewDriver) PressEnter() *ViewDriver {
	return self.Press(self.t.keys.Universal.Confirm)
}

// i.e. pressing tab
func (self *ViewDriver) PressTab() *ViewDriver {
	return self.Press(self.t.keys.Universal.TogglePanel)
}

// i.e. pressing escape
func (self *ViewDriver) PressEscape() *ViewDriver {
	return self.Press(self.t.keys.Universal.Return)
}

Review comment (suggestion):
@jesseduffield I was unsure why the additional `+1`s are needed here, but they are. I expected `offsetX+x, offsetY+y` to work here. Just curious what the intuition is that I'm missing here.

Code after:

	return self
}

func (self *ViewDriver) Press(keyStr string) *ViewDriver {
	self.IsFocused()

	self.t.press(keyStr)

	return self
}

// for use when typing or navigating, because in demos we want that to happen
// faster
func (self *ViewDriver) PressFast(keyStr string) *ViewDriver {
	self.IsFocused()

	self.t.pressFast(keyStr)

	return self
}

func (self *ViewDriver) Click(x, y int) *ViewDriver {
	offsetX, offsetY, _, _ := self.getView().Dimensions()

	self.t.click(offsetX+1+x, offsetY+1+y)

	return self
}

// i.e. pressing down arrow
func (self *ViewDriver) SelectNextItem() *ViewDriver {
	return self.PressFast(self.t.keys.Universal.NextItem)
}

// i.e. pressing up arrow
func (self *ViewDriver) SelectPreviousItem() *ViewDriver {
	return self.PressFast(self.t.keys.Universal.PrevItem)
}

// i.e. pressing space
func (self *ViewDriver) PressPrimaryAction() *ViewDriver {
	return self.Press(self.t.keys.Universal.Select)
}

// i.e. pressing space
func (self *ViewDriver) PressEnter() *ViewDriver {
	return self.Press(self.t.keys.Universal.Confirm)
}

// i.e. pressing tab
Repository: jesseduffield/lazygit
File: pkg/gui/information_panel.go (Go)

Code before:
			return nil
		}
		return activeMode.Reset()
	}

	var title, url string

	// if we're not in an active mode we show the donate button
	if cx <= runewidth.StringWidth(gui.c.Tr.Donate) {
		url = constants.Links.Donate
		title = gui.c.Tr.Donate
	} else if cx <= runewidth.StringWidth(gui.c.Tr.Donate)+1+runewidth.StringWidth(gui.c.Tr.AskQuestion) {
		url = constants.Links.Discussions
		title = gui.c.Tr.AskQuestion
	}
	err := gui.os.OpenLink(url)
	if err != nil {
		// Opening the link via the OS failed for some reason. (For example, this
		// can happen if the `os.openLink` config key references a command that
		// doesn't exist, or that errors when called.)
		//
		// In that case, rather than crash the app, fall back to simply showing a
		// dialog asking the user to visit the URL.
		placeholders := map[string]string{"url": url}
		message := utils.ResolvePlaceholderString(gui.c.Tr.PleaseGoToURL, placeholders)
		return gui.PopupHandler.Alert(title, message)
	}

	return nil
}


Review comment (suggestion):
```suggestion
		return gui.c.Alert(title, message)
```
This is a minor thing relating to the fact that I'm yet to standardise on everything going through this `common` field

Code after:
			return nil
		}
		return activeMode.Reset()
	}

	var title, url string

	// if we're not in an active mode we show the donate button
	if cx <= runewidth.StringWidth(gui.c.Tr.Donate) {
		url = constants.Links.Donate
		title = gui.c.Tr.Donate
	} else if cx <= runewidth.StringWidth(gui.c.Tr.Donate)+1+runewidth.StringWidth(gui.c.Tr.AskQuestion) {
		url = constants.Links.Discussions
		title = gui.c.Tr.AskQuestion
	}
	err := gui.os.OpenLink(url)
	if err != nil {
		// Opening the link via the OS failed for some reason. (For example, this
		// can happen if the `os.openLink` config key references a command that
		// doesn't exist, or that errors when called.)
		//
		// In that case, rather than crash the app, fall back to simply showing a
		// dialog asking the user to visit the URL.
		placeholders := map[string]string{"url": url}
		message := utils.ResolvePlaceholderString(gui.c.Tr.PleaseGoToURL, placeholders)
		return gui.c.Alert(title, message)
	}

	return nil
}
Repository: jesseduffield/lazygit
File: pkg/integration/tests/branch/reset_to_upstream.go (Go)

Code before:
					Select(Contains("View reset options targetting selected branch upstream")).
					Confirm()

				t.ExpectPopup().Menu().
					Title(Equals("Reset to origin/soft-branch")).
					Select(Contains("Soft reset")).
					Confirm()
			})
		t.Views().Commits().Lines(
			Contains("soft commit"),
			Contains("hard commit"),
		)
		t.Views().Files().Lines(
			Contains("file-1").Contains("A"),
			Contains("file-2").Contains("A"),
		)

		// hard reset
		t.Views().Branches().
			Focus().
			Lines(
				Contains("base"),
				Contains("soft-branch").IsSelected(),
				Contains("hard-branch"),
			).
			SelectNextItem().
			Lines(
				Contains("base"),
				Contains("soft-branch"),
				Contains("hard-branch").IsSelected(),
			).
			Press(keys.Branches.SetUpstream).
			Tap(func() {
				t.ExpectPopup().Menu().
					Title(Equals("Set/Unset upstream")).
					Select(Contains("View reset options targetting selected branch upstream")).
					Confirm()

				t.ExpectPopup().Menu().
					Title(Equals("Reset to origin/hard-branch")).
					Select(Contains("Hard reset")).
					Confirm()
			})
		t.Views().Commits().Lines(Contains("hard commit"))
		t.Views().Files().LineCount(EqualsInt(0))
	},
})


Review comment (suggestion):
```suggestion
			NavigateToLine(Contains("hard-branch")).
```

I prefer this approach because then there's no need to check which line is selected (i.e. we can remove lines 86-90)

Code after:
					Title(Equals("Upstream options")).
					Select(Contains("Reset checked-out branch onto origin/soft-branch...")).
					Confirm()

				t.ExpectPopup().Menu().
					Title(Equals("Reset to origin/soft-branch")).
					Select(Contains("Soft reset")).
					Confirm()
			})
		t.Views().Commits().Lines(
			Contains("soft commit"),
			Contains("hard commit"),
		)
		t.Views().Files().Lines(
			Contains("file-1").Contains("A"),
			Contains("file-2").Contains("A"),
		)

		// hard reset
		t.Views().Branches().
			Focus().
			Lines(
				Contains("base"),
				Contains("soft-branch").IsSelected(),
				Contains("hard-branch"),
			).
			NavigateToLine(Contains("hard-branch")).
			Press(keys.Branches.SetUpstream).
			Tap(func() {
				t.ExpectPopup().Menu().
					Title(Equals("Upstream options")).
					Select(Contains("Reset checked-out branch onto origin/hard-branch...")).
					Confirm()

				t.ExpectPopup().Menu().
					Title(Equals("Reset to origin/hard-branch")).
					Select(Contains("Hard reset")).
					Confirm()
			})
		t.Views().Commits().Lines(Contains("hard commit"))
		t.Views().Files().IsEmpty()
	},
})
Repository: jesseduffield/lazygit
File: pkg/utils/utils.go (Go)

Code before:
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/jesseduffield/gocui"
)

// GetProjectRoot returns the path to the root of the project. Only to be used
// in testing contexts, as with binaries it's unlikely this path will exist on
// the machine
func GetProjectRoot() string {
	dir, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return strings.Split(dir, "lazygit")[0] + "lazygit"
}

// The duration between two frames of the loader animation in milliseconds
const LoaderAnimationInterval = 120

// Loader dumps a string to be displayed as a loader
func Loader() string {
	strings := []string{"•...", ".•..", "..•.", "...•", "..•.", ".•.."}
	now := time.Now()
	milliseconds := now.UnixMilli()
	index := milliseconds / LoaderAnimationInterval % int64(len(strings))
	return "[" + strings[index] + "]"
}

// Min returns the minimum of two integers
func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func Clamp(x int, min int, max int) int {
	if x < min {
		return min
	} else if x > max {

Review comment (suggestion):
I prefer the original loader mostly because using a loader like this makes our intermittent micro-freezes less apparent. I have no idea what causes those micro-freezes (presumably something blocking the UI thread) but I find the spinner makes the app seem snappier

Code after:
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/jesseduffield/gocui"
)

// GetProjectRoot returns the path to the root of the project. Only to be used
// in testing contexts, as with binaries it's unlikely this path will exist on
// the machine
func GetProjectRoot() string {
	dir, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	return strings.Split(dir, "lazygit")[0] + "lazygit"
}

// The duration between two frames of the loader animation in milliseconds
const LoaderAnimationInterval = 50

// Loader dumps a string to be displayed as a loader
func Loader() string {
	characters := "|/-\\"
	now := time.Now()
	milliseconds := now.UnixMilli()
	index := milliseconds / LoaderAnimationInterval % int64(len(characters))
	return characters[index : index+1]
}

// Min returns the minimum of two integers
func Min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func Max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func Clamp(x int, min int, max int) int {
	if x < min {
		return min
	} else if x > max {
Repository: jesseduffield/lazygit
File: vendor/github.com/jesseduffield/gocui/task.go (Go)

Code before:
package gocui

// A task represents the fact that the program is busy doing something, which
// is useful for integration tests which only want to proceed when the program
// is idle.
//
// Tasks can be paused in cases where you don't want the program to be
// considered busy even though a task is running. For example, when a pull or
// push operation needs to bring up a panel to type in a password, we need to
// pause the pull/push task so that integration tests can interact with the
// panel; they would otherwise block waiting for the end of the operation.
//
// In such as case, only the task running "our" operation is paused; it is
// important that other task that might be running in parallel still make the
// program busy. Sometimes, an operation might spawn other tasks that run in
// parallel; an example is a task that puts up a spinner in the status bar. In
// this case this other task needs to be added to the original one as a sub
// task, so that it can be paused together with the main one.

type Task interface {
	Done()
	Pause()
	Continue()
	AddSubTask(Task)

	// not exporting because we don't need to
	pauseNoMutex()
	continueNoMutex()
	isBusy() bool
}

type TaskImpl struct {
	id        int
	busy      bool
	onDone    func()
	withMutex func(func())
	subTasks  []Task
}


Review comment (suggestion):
```suggestion
// important that other tasks that might be running in parallel still make the
```

Code after:
package gocui

// A task represents the fact that the program is busy doing something, which
// is useful for integration tests which only want to proceed when the program
// is idle.

type Task interface {
	Done()
	Pause()
	Continue()
	// not exporting because we don't need to
	isBusy() bool
}

type TaskImpl struct {
	id        int
	busy      bool
	onDone    func()
	withMutex func(func())
}

func (self *TaskImpl) Done() {
	self.onDone()
}

func (self *TaskImpl) Pause() {
	self.withMutex(func() {
		self.busy = false
	})
}

func (self *TaskImpl) Continue() {
	self.withMutex(func() {
		self.busy = true
	})
}

func (self *TaskImpl) isBusy() bool {
	return self.busy
Repository: jesseduffield/lazygit
File: pkg/gui/views.go (Go)

Code before:

	gui.Views.Snake.Title = gui.c.Tr.SnakeTitle
	gui.Views.Snake.FgColor = gocui.ColorGreen

	if gui.c.UserConfig.Gui.ShowPanelJumps {
		jumpBindings := gui.c.UserConfig.Keybinding.Universal.JumpToBlock
		jumpLabels := make([]string, len(jumpBindings))
		for i, binding := range jumpBindings {
			jumpLabels[i] = fmt.Sprintf("[%s]", binding)
		}

		gui.Views.Status.Title = fmt.Sprintf("%s %s", jumpLabels[0], gui.Views.Status.Title)

		gui.Views.Files.Title = jumpLabels[1]
		gui.Views.Worktrees.Title = jumpLabels[1]
		gui.Views.Submodules.Title = jumpLabels[1]

		gui.Views.Branches.Title = jumpLabels[2]
		gui.Views.Remotes.Title = jumpLabels[2]
		gui.Views.Tags.Title = jumpLabels[2]

		gui.Views.Commits.Title = jumpLabels[3]
		gui.Views.ReflogCommits.Title = jumpLabels[3]

		gui.Views.Stash.Title = fmt.Sprintf("%s %s", jumpLabels[4], gui.Views.Stash.Title)
	}

	return nil
}


Review comment (bug):
You need to set the titles to empty in an `else` block. Or (probably better) find the code that sets the titles in the first place, and remove it. Otherwise it looks very wrong when you set the config to false.

Code after:

	gui.Views.Snake.Title = gui.c.Tr.SnakeTitle
	gui.Views.Snake.FgColor = gocui.ColorGreen

	if gui.c.UserConfig.Gui.ShowPanelJumps {
		jumpBindings := gui.c.UserConfig.Keybinding.Universal.JumpToBlock
		jumpLabels := lo.Map(jumpBindings, func(binding string, _ int) string {
			return fmt.Sprintf("[%s]", binding)
		})

		gui.Views.Status.TitlePrefix = jumpLabels[0]

		gui.Views.Files.TitlePrefix = jumpLabels[1]
		gui.Views.Worktrees.TitlePrefix = jumpLabels[1]
		gui.Views.Submodules.TitlePrefix = jumpLabels[1]

		gui.Views.Branches.TitlePrefix = jumpLabels[2]
		gui.Views.Remotes.TitlePrefix = jumpLabels[2]
		gui.Views.Tags.TitlePrefix = jumpLabels[2]

		gui.Views.Commits.TitlePrefix = jumpLabels[3]
		gui.Views.ReflogCommits.TitlePrefix = jumpLabels[3]

		gui.Views.Stash.TitlePrefix = jumpLabels[4]
	}

	return nil
}
Repository: jesseduffield/lazygit
File: vendor/github.com/jesseduffield/gocui/view.go (Go)

Code before:
	return lines
}

func linesToString(lines [][]cell) string {
	str := make([]string, len(lines))
	for i := range lines {
		rns := make([]rune, 0, len(lines[i]))
		line := lineType(lines[i]).String()
		for _, c := range line {
			if c != '\x00' {
				rns = append(rns, c)
			}
		}
		str[i] = string(rns)
	}

	return strings.Join(str, "\n")
}

// GetClickedTabIndex tells us which tab was clicked
func (v *View) GetClickedTabIndex(x int) int {
	if len(v.Tabs) <= 1 {
		return 0
	}

	charX := runewidth.StringWidth(v.Title)
	if x <= 1 {
		return -1
	}
	for i, tab := range v.Tabs {
		charX += runewidth.StringWidth(tab)
		if x <= charX {
			return i
		}
		charX += runewidth.StringWidth(" - ")
		if x <= charX {
			return -1
		}
	}

	return -1
}

func (v *View) SelectedLineIdx() int {
	_, seletedLineIdx := v.SelectedPoint()
	return seletedLineIdx
}

// expected to only be used in tests
func (v *View) SelectedLine() string {
	v.writeMutex.Lock()

Review comment (suggestion):
This must be + 1 for the offset of the title to the left view edge (like the 1 that was there before), and then again plus 1 if the title is non-empty, for the space.

To test whether this function works correctly, you want to be able to click the first and last letter of every tab title, and that should select that tab.

Code after:
		}
	}

	lines = append(lines, line[offset:])
	return lines
}

func linesToString(lines [][]cell) string {
	str := make([]string, len(lines))
	for i := range lines {
		rns := make([]rune, 0, len(lines[i]))
		line := lineType(lines[i]).String()
		for _, c := range line {
			if c != '\x00' {
				rns = append(rns, c)
			}
		}
		str[i] = string(rns)
	}

	return strings.Join(str, "\n")
}

// GetClickedTabIndex tells us which tab was clicked
func (v *View) GetClickedTabIndex(x int) int {
	if len(v.Tabs) <= 1 {
		return 0
	}

	charX := len(v.TitlePrefix) + 1
	if v.TitlePrefix != "" {
		charX += 1
	}
	if x <= charX {
		return -1
	}
	for i, tab := range v.Tabs {
		charX += runewidth.StringWidth(tab)
		if x <= charX {
			return i
		}
		charX += runewidth.StringWidth(" - ")
		if x <= charX {
			return -1
		}
	}

	return -1
}

func (v *View) SelectedLineIdx() int {
Repository: jesseduffield/lazygit
File: vendor/github.com/jesseduffield/gocui/gui.go (Go)

Code before:
		runeBR = corner(v, TOP|LEFT)
	}

	corners := []struct {
		x, y int
		ch   rune
	}{{v.x0, v.y0, runeTL}, {v.x1, v.y0, runeTR}, {v.x0, v.y1, runeBL}, {v.x1, v.y1, runeBR}}

	for _, c := range corners {
		if c.x >= 0 && c.y >= 0 && c.x < g.maxX && c.y < g.maxY {
			if err := g.SetRune(c.x, c.y, c.ch, fgColor, bgColor); err != nil {
				return err
			}
		}
	}
	return nil
}

// drawTitle draws the title of the view.
func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error {
	if v.y0 < 0 || v.y0 >= g.maxY {
		return nil
	}

	tabs := v.Tabs
	prefix := v.TitlePrefix
	separator := " - "
	charIndex := 0
	currentTabStart := - 1
	currentTabEnd := - 1
	if len(tabs) == 0 {
		tabs = []string{v.Title}
	} else {
		for i, tab := range tabs {
			if i == v.TabIndex {
				currentTabStart = charIndex
				currentTabEnd = charIndex + len(tab)
				break
			}
			charIndex += len(tab)
			if i < len(tabs) - 1 {
				charIndex += len(separator)
			}
		}
	}

	str := strings.Join(tabs, separator)

	x := v.x0 + 2
	for _, ch := range prefix {
		if err := g.SetRune(x, v.y0, ch, fgColor, bgColor); err != nil {

Review comment (suggestion):
We'd only have to add
```
	if prefix != "" {
		prefix += "─"
	}
```
here to make it work.

Code after:
		runeBR = corner(v, TOP|LEFT)
	}

	corners := []struct {
		x, y int
		ch   rune
	}{{v.x0, v.y0, runeTL}, {v.x1, v.y0, runeTR}, {v.x0, v.y1, runeBL}, {v.x1, v.y1, runeBR}}

	for _, c := range corners {
		if c.x >= 0 && c.y >= 0 && c.x < g.maxX && c.y < g.maxY {
			if err := g.SetRune(c.x, c.y, c.ch, fgColor, bgColor); err != nil {
				return err
			}
		}
	}
	return nil
}

// drawTitle draws the title of the view.
func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error {
	if v.y0 < 0 || v.y0 >= g.maxY {
		return nil
	}

	tabs := v.Tabs
	prefix := v.TitlePrefix
	if prefix != "" {
		if len(v.FrameRunes) > 0 {
			prefix += string(v.FrameRunes[0])
		} else {
			prefix += "─"
		}
	}
	separator := " - "
	charIndex := 0
	currentTabStart := -1
	currentTabEnd := -1
	if len(tabs) == 0 {
		tabs = []string{v.Title}
	} else {
		for i, tab := range tabs {
			if i == v.TabIndex {
				currentTabStart = charIndex
				currentTabEnd = charIndex + len(tab)
				break
			}
			charIndex += len(tab)
			if i < len(tabs)-1 {
				charIndex += len(separator)
			}
		}
Repository: jesseduffield/lazygit
File: vendor/github.com/jesseduffield/gocui/view.go (Go)

Code before:
	return lines
}

func linesToString(lines [][]cell) string {
	str := make([]string, len(lines))
	for i := range lines {
		rns := make([]rune, 0, len(lines[i]))
		line := lineType(lines[i]).String()
		for _, c := range line {
			if c != '\x00' {
				rns = append(rns, c)
			}
		}
		str[i] = string(rns)
	}

	return strings.Join(str, "\n")
}

// GetClickedTabIndex tells us which tab was clicked
func (v *View) GetClickedTabIndex(x int) int {
	if len(v.Tabs) <= 1 {
		return 0
	}

	charX := len(v.TitlePrefix) + 1
	if x <= charX {
		return -1
	}
	for i, tab := range v.Tabs {
		charX += runewidth.StringWidth(tab)
		if x <= charX {
			return i
		}
		charX += runewidth.StringWidth(" - ")
		if x <= charX {
			return -1
		}
	}

	return -1
}

func (v *View) SelectedLineIdx() int {
	_, seletedLineIdx := v.SelectedPoint()
	return seletedLineIdx
}

// expected to only be used in tests
func (v *View) SelectedLine() string {
	v.writeMutex.Lock()

Review comment (suggestion):
And this would need
```
	if v.TitlePrefix != "" {
		charX += 1
	}
```

Code after:
	return lines
}

func linesToString(lines [][]cell) string {
	str := make([]string, len(lines))
	for i := range lines {
		rns := make([]rune, 0, len(lines[i]))
		line := lineType(lines[i]).String()
		for _, c := range line {
			if c != '\x00' {
				rns = append(rns, c)
			}
		}
		str[i] = string(rns)
	}

	return strings.Join(str, "\n")
}

// GetClickedTabIndex tells us which tab was clicked
func (v *View) GetClickedTabIndex(x int) int {
	if len(v.Tabs) <= 1 {
		return 0
	}

	charX := len(v.TitlePrefix) + 1
	if v.TitlePrefix != "" {
		charX += 1
	}
	if x <= charX {
		return -1
	}
	for i, tab := range v.Tabs {
		charX += runewidth.StringWidth(tab)
		if x <= charX {
			return i
		}
		charX += runewidth.StringWidth(" - ")
		if x <= charX {
			return -1
		}
	}

	return -1
}

func (v *View) SelectedLineIdx() int {
	_, seletedLineIdx := v.SelectedPoint()
	return seletedLineIdx
}
Repository: jesseduffield/lazygit
File: pkg/gui/controllers/branches_controller.go (Go)

Code before:
		OpensMenu:    true,
		OnPress: func() error {
			err := self.c.Helpers().Refs.CreateGitResetMenu(upstream)
			if err != nil {
				return self.c.Error(err)
			}
			return nil
		},
		Tooltip: upstreamResetTooltip,
		Key:     'g',
	}

	upstreamRebaseItem := &types.MenuItem{
		LabelColumns: []string{upstreamRebaseOptions},
		OpensMenu:    true,
		OnPress: func() error {
			if err := self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranch.ShortUpstreamRefName()); err != nil {
				return self.c.Error(err)
			}
			return nil
		},
		Tooltip: upstreamRebaseTooltip,
		Key:     'r',
	}

	if !selectedBranch.IsTrackingRemote() || selectedBranch.UpstreamGone {
		upstreamRebaseItem.DisabledReason = self.c.Tr.UpstreamNotSetError
	}

	if !selectedBranch.RemoteBranchStoredLocally() {
		viewDivergenceItem.DisabledReason = self.c.Tr.UpstreamNotSetError
		unsetUpstreamItem.DisabledReason = self.c.Tr.UpstreamNotSetError
		upstreamResetItem.DisabledReason = self.c.Tr.UpstreamNotSetError
	}

	options := []*types.MenuItem{
		viewDivergenceItem,
		unsetUpstreamItem,
		setUpstreamItem,
		upstreamResetItem,
		upstreamRebaseItem,
	}

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

func (self *BranchesController) Context() types.Context {
	return self.context()

Review comment (suggestion):
Seems to me we should be able to use `if !selectedBranch.RemoteBranchStoredLocally()` like we do for the others below. 

Code after:
		OpensMenu:    true,
		OnPress: func() error {
			err := self.c.Helpers().Refs.CreateGitResetMenu(upstream)
			if err != nil {
				return self.c.Error(err)
			}
			return nil
		},
		Tooltip: upstreamResetTooltip,
		Key:     'g',
	}

	upstreamRebaseItem := &types.MenuItem{
		LabelColumns: []string{upstreamRebaseOptions},
		OpensMenu:    true,
		OnPress: func() error {
			if err := self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranch.ShortUpstreamRefName()); err != nil {
				return self.c.Error(err)
			}
			return nil
		},
		Tooltip: upstreamRebaseTooltip,
		Key:     'r',
	}

	if !selectedBranch.RemoteBranchStoredLocally() {
		viewDivergenceItem.DisabledReason = self.c.Tr.UpstreamNotSetError
		unsetUpstreamItem.DisabledReason = self.c.Tr.UpstreamNotSetError
		upstreamResetItem.DisabledReason = self.c.Tr.UpstreamNotSetError
		upstreamRebaseItem.DisabledReason = self.c.Tr.UpstreamNotSetError
	}

	options := []*types.MenuItem{
		viewDivergenceItem,
		unsetUpstreamItem,
		setUpstreamItem,
		upstreamResetItem,
		upstreamRebaseItem,
	}

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

func (self *BranchesController) Context() types.Context {
	return self.context()
}

func (self *BranchesController) context() *context.BranchesContext {