ronantakizawa/codereview-bench huggingface dataset:
Repository: derailed/k9s
File: internal/view/exec.go (Go)

Code before:
	var priv bool = true

	log.Debug().Msgf("Shell Config %#v", cfg)
	c := v1.Container{
		Name:  k9sShell,
		Image: cfg.Image,
		VolumeMounts: []v1.VolumeMount{
			{
				Name:      "root-vol",
				MountPath: "/host",
				ReadOnly:  true,
			},
		},
		Resources: asResource(cfg.Limits),
		Stdin:     true,
		SecurityContext: &v1.SecurityContext{
			Privileged: &priv,
		},
	}
	if len(cfg.Command) != 0 {
		c.Command = cfg.Command
	}
	if len(cfg.Args) > 0 {
		c.Args = cfg.Args
	}
	if len(cfg.ImagePullPolicy) > 0 {
		c.ImagePullPolicy = v1.PullPolicy(cfg.ImagePullPolicy)
	}

	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      k9sShellPodName(),
			Namespace: cfg.Namespace,
			Labels:    cfg.Labels,
		},
		Spec: v1.PodSpec{
			NodeName:                      node,
			RestartPolicy:                 v1.RestartPolicyNever,
			HostPID:                       true,
			HostNetwork:                   true,
			ImagePullSecrets:              cfg.ImagePullSecrets,
			TerminationGracePeriodSeconds: &grace,
			Volumes: []v1.Volume{
				{
					Name: "root-vol",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Path: "/",
						},
					},
				},

Review comment (suggestion):
No need to check the length. We should be able to assign the pullPolicy on the container declaration above. I think this is ok if nil.

Code after:
	var priv bool = true

	log.Debug().Msgf("Shell Config %#v", cfg)
	c := v1.Container{
		Name:            k9sShell,
		Image:           cfg.Image,
		ImagePullPolicy: cfg.ImagePullPolicy,
		VolumeMounts: []v1.VolumeMount{
			{
				Name:      "root-vol",
				MountPath: "/host",
				ReadOnly:  true,
			},
		},
		Resources: asResource(cfg.Limits),
		Stdin:     true,
		SecurityContext: &v1.SecurityContext{
			Privileged: &priv,
		},
	}
	if len(cfg.Command) != 0 {
		c.Command = cfg.Command
	}
	if len(cfg.Args) > 0 {
		c.Args = cfg.Args
	}

	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      k9sShellPodName(),
			Namespace: cfg.Namespace,
			Labels:    cfg.Labels,
		},
		Spec: v1.PodSpec{
			NodeName:                      node,
			RestartPolicy:                 v1.RestartPolicyNever,
			HostPID:                       true,
			HostNetwork:                   true,
			ImagePullSecrets:              cfg.ImagePullSecrets,
			TerminationGracePeriodSeconds: &grace,
			Volumes: []v1.Volume{
				{
					Name: "root-vol",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Path: "/",
						},
					},
				},
			},
			Containers: []v1.Container{c},
Repository: derailed/k9s
File: internal/view/app.go (Go)

Code before:
// ExitStatus indicates UI exit conditions.
var ExitStatus = ""

const (
	splashDelay      = 1 * time.Second
	clusterRefresh   = 15 * time.Second
	clusterInfoWidth = 50
	clusterInfoPad   = 15
)

// App represents an application view.
type App struct {
	version string
	*ui.App
	Content       *PageStack
	command       *Command
	factory       *watch.Factory
	cancelFn      context.CancelFunc
	clusterModel  *model.ClusterInfo
	cmdHistory    *model.History
	filterHistory *model.History
	conRetry      int32
	showHeader    bool
	showLogo      bool
	showCrumbs    bool
	namespaces    []string
}

// NewApp returns a K9s app instance.
func NewApp(cfg *config.Config) *App {
	a := App{
		App:           ui.NewApp(cfg, cfg.K9s.CurrentContext),
		cmdHistory:    model.NewHistory(model.MaxHistory),
		filterHistory: model.NewHistory(model.MaxHistory),
		Content:       NewPageStack(),
	}

	a.Views()["statusIndicator"] = ui.NewStatusIndicator(a.App, a.Styles)
	a.Views()["clusterInfo"] = NewClusterInfo(&a)

	return &a
}

// ConOK checks the connection is cool, returns false otherwise.
func (a *App) ConOK() bool {
	return atomic.LoadInt32(&a.conRetry) == 0
}

// Init initializes the application.
func (a *App) Init(version string, rate int) error {
	a.version = model.NormalizeVersion(version)

Review comment (performance):
Likely not a good idea to cache the namespaces here as the list will change over the course of the session.

Code after:
// ExitStatus indicates UI exit conditions.
var ExitStatus = ""

const (
	splashDelay      = 1 * time.Second
	clusterRefresh   = 15 * time.Second
	clusterInfoWidth = 50
	clusterInfoPad   = 15
)

// App represents an application view.
type App struct {
	version string
	*ui.App
	Content       *PageStack
	command       *Command
	factory       *watch.Factory
	cancelFn      context.CancelFunc
	clusterModel  *model.ClusterInfo
	cmdHistory    *model.History
	filterHistory *model.History
	conRetry      int32
	showHeader    bool
	showLogo      bool
	showCrumbs    bool
}

// NewApp returns a K9s app instance.
func NewApp(cfg *config.Config) *App {
	a := App{
		App:           ui.NewApp(cfg, cfg.K9s.CurrentContext),
		cmdHistory:    model.NewHistory(model.MaxHistory),
		filterHistory: model.NewHistory(model.MaxHistory),
		Content:       NewPageStack(),
	}

	a.Views()["statusIndicator"] = ui.NewStatusIndicator(a.App, a.Styles)
	a.Views()["clusterInfo"] = NewClusterInfo(&a)

	return &a
}

// ConOK checks the connection is cool, returns false otherwise.
func (a *App) ConOK() bool {
	return atomic.LoadInt32(&a.conRetry) == 0
}

// Init initializes the application.
func (a *App) Init(version string, rate int) error {
	a.version = model.NormalizeVersion(version)
Repository: derailed/k9s
File: internal/render/hpa.go (Go)

Code before:
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s

package render

import (
	"strconv"
	"strings"

	"github.com/derailed/tcell/v2"
)

// HorizontalPodAutoscaler renders a K8s HorizontalPodAutoscaler to screen.
type HorizontalPodAutoscaler struct {
	Generic
}

// ColorerFunc colors a resource row.
func (hpa HorizontalPodAutoscaler) ColorerFunc() ColorerFunc {
	return func(ns string, h Header, re RowEvent) tcell.Color {
		c := DefaultColorer(ns, h, re)

		maxPodsS := strings.TrimSpace(re.Row.Fields[h.IndexOf("MAXPODS", true)])
		currentReplicasS := strings.TrimSpace(re.Row.Fields[h.IndexOf("REPLICAS", true)])

		maxPods, err := strconv.Atoi(maxPodsS)
		if err != nil {
			return c
		}
		currentReplicas, err := strconv.Atoi(currentReplicasS)
		if err != nil {
			return c
		}
		if currentReplicas >= maxPods {
			c = ErrColor
		}
		return c
	}
}


Review comment (suggestion):
We should validate `IndexOf` returns a valid index ie within the Fields range.

Code after:
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s

package render

import (
	"strconv"
	"strings"

	"github.com/derailed/tcell/v2"
)

// HorizontalPodAutoscaler renders a K8s HorizontalPodAutoscaler to screen.
type HorizontalPodAutoscaler struct {
	Generic
}

// ColorerFunc colors a resource row.
func (hpa HorizontalPodAutoscaler) ColorerFunc() ColorerFunc {
	return func(ns string, h Header, re RowEvent) tcell.Color {
		c := DefaultColorer(ns, h, re)

		maxPodsIndex := h.IndexOf("MAXPODS", true)
		replicasIndex := h.IndexOf("REPLICAS", true)
		if (maxPodsIndex < 0 || maxPodsIndex >= len(re.Row.Fields)) || (replicasIndex < 0 || replicasIndex >= len(re.Row.Fields)) {
			return c
		}

		maxPodsS := strings.TrimSpace(re.Row.Fields[maxPodsIndex])
		currentReplicasS := strings.TrimSpace(re.Row.Fields[replicasIndex])

		maxPods, err := strconv.Atoi(maxPodsS)
		if err != nil {
			return c
		}
		currentReplicas, err := strconv.Atoi(currentReplicasS)
		if err != nil {
			return c
		}
		if currentReplicas >= maxPods {
			c = ErrColor
		}
		return c
	}
}
Repository: derailed/k9s
File: internal/view/secret.go (Go)

Code before:
}

func (s *Secret) describe(evt *tcell.EventKey) *tcell.EventKey {
	path := s.GetTable().GetSelectedItem()
	if path == "" {
		return evt
	}

	o, err := s.App().factory.Get(s.GVR().String(), path, true, labels.Everything())
	if err != nil {
		s.App().Flash().Err(err)
		return nil
	}

	var secret v1.Secret
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &secret)
	if err != nil {
		s.App().Flash().Err(err)
		return nil
	}

	describe, err := dao.Describe(s.App().Conn(), s.GVR(), path)

	// Remove the encoded part from k8s's describe API
	// More details about the reasoning of index: https://github.com/kubernetes/kubectl/blob/v0.29.0/pkg/describe/describe.go#L2542
	dataEndIndex := strings.Index(describe, "====") + 4
	describe = string([]rune(describe)[0:dataEndIndex])

	for k, v := range secret.Data {
		describe = fmt.Sprintf("%s\n%s:\t%s", describe, k, string(v))
	}

	details := NewDetails(s.App(), "Secret Decoder", path, contentYAML, true).Update(describe)
	if err := s.App().inject(details, false); err != nil {
		s.App().Flash().Err(err)
	}

	return nil
}

func (s *Secret) refCmd(evt *tcell.EventKey) *tcell.EventKey {
	return scanRefs(evt, s.App(), s.GetTable(), dao.SecGVR)
}

func (s *Secret) decodeCmd(evt *tcell.EventKey) *tcell.EventKey {
	path := s.GetTable().GetSelectedItem()
	if path == "" {
		return evt
	}

	o, err := s.App().factory.Get(s.GVR().String(), path, true, labels.Everything())

Review comment (refactor):
We should probably check for bounds here in case we're getting something unexpected that could yield a panic.  Perhaps extracting the behavior and reuse it between `decode` and `describe` might be worth considering? Also some tests around this would be great!


Code after:
func (s *Secret) decodeCmd(evt *tcell.EventKey) *tcell.EventKey {
	path := s.GetTable().GetSelectedItem()
	if path == "" {
		return evt
	}

	o, err := s.App().factory.Get(s.GVR().String(), path, true, labels.Everything())
	if err != nil {
		s.App().Flash().Err(err)
		return nil
	}

	d, err := dao.ExtractSecrets(o.(*unstructured.Unstructured))
	if err != nil {
		s.App().Flash().Err(err)
		return nil
	}

	raw, err := yaml.Marshal(d)
	if err != nil {
		s.App().Flash().Errf("Error decoding secret %s", err)
		return nil
	}

	details := NewDetails(s.App(), "Secret Decoder", path, contentYAML, true).Update(string(raw))
	if err := s.App().inject(details, false); err != nil {
		s.App().Flash().Err(err)
	}

	return nil
}
Repository: derailed/k9s
File: internal/dao/secret.go (Go)

Code before:
	}

	dataEndIndex := strings.Index(encodedDescription, "====") + 4

	if dataEndIndex == -1 {
		return "", fmt.Errorf("unable to find data section in secret description")
	}

	d, err := ExtractSecrets(o.(*unstructured.Unstructured))

	if err != nil {
		return "", err
	}

	// Remove the encoded part from k8s's describe API
	// More details about the reasoning of index: https://github.com/kubernetes/kubectl/blob/v0.29.0/pkg/describe/describe.go#L2542
	decodedDescription := string([]rune(encodedDescription)[0:dataEndIndex])

	for k, v := range d {
		decodedDescription = fmt.Sprintf("%s\n%s:\t%s", decodedDescription, k, v)
	}

	return decodedDescription, nil
}

// ExtractSecrets takes an unstructured object and attempts to convert it into a
// Kubernetes Secret.
// It returns a map where the keys are the secret data keys and the values are
// the corresponding secret data values.
// If the conversion fails, it returns an error.
func ExtractSecrets(o *unstructured.Unstructured) (map[string]string, error) {
	var secret v1.Secret
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.Object, &secret)

	if err != nil {
		return nil, err
	}

	secretData := make(map[string]string, len(secret.Data))

	for k, val := range secret.Data {
		secretData[k] = string(val)
	}

	return secretData, nil
}


Review comment (suggestion):
This could be sizeable! Better to compute key/vals and append to the rest of the body + don't want to keep resetting the entire body on every iteration.

Code after:

	dataEndIndex := strings.Index(encodedDescription, "====")

	if dataEndIndex == -1 {
		return "", fmt.Errorf("Unable to find data section in secret description")
	}

	dataEndIndex += 4

	if dataEndIndex >= len(encodedDescription) {
		return "", fmt.Errorf("Data section in secret description is invalid")
	}

	// Remove the encoded part from k8s's describe API
	// More details about the reasoning of index: https://github.com/kubernetes/kubectl/blob/v0.29.0/pkg/describe/describe.go#L2542
	body := encodedDescription[0:dataEndIndex]

	d, err := ExtractSecrets(o.(*unstructured.Unstructured))

	if err != nil {
		return "", err
	}

	decodedSecrets := []string{}

	for k, v := range d {
		decodedSecrets = append(decodedSecrets, "\n", k, ":\t", v)
	}

	return body + strings.Join(decodedSecrets, ""), nil
}

// ExtractSecrets takes an unstructured object and attempts to convert it into a
// Kubernetes Secret.
// It returns a map where the keys are the secret data keys and the values are
// the corresponding secret data values.
// If the conversion fails, it returns an error.
func ExtractSecrets(o *unstructured.Unstructured) (map[string]string, error) {
	var secret v1.Secret
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.Object, &secret)

	if err != nil {
		return nil, err
	}

	secretData := make(map[string]string, len(secret.Data))

	for k, val := range secret.Data {
		secretData[k] = string(val)
	}
Repository: derailed/k9s
File: internal/view/actions.go (Go)

Code before:
		}
	}

	return false
}

func hotKeyActions(r Runner, aa ui.KeyActions) error {
	hh := config.NewHotKeys()
	for k, a := range aa {
		if a.Opts.HotKey {
			delete(aa, k)
		}
	}

	var errs error
	if err := hh.Load(r.App().Config.ContextHotkeysPath()); err != nil {
		errs = errors.Join(errs, err)
	}
	for k, hk := range hh.HotKey {
		key, err := asKey(hk.ShortCut)
		if err != nil {
			errs = errors.Join(errs, err)
			continue
		}
		_, ok := aa[key]
		if ok && !hk.Override {
			errs = errors.Join(errs, fmt.Errorf("duplicated hotkeys found for %q in %q", hk.ShortCut, k))
			continue
		}

		command, err := r.EnvFn()().Substitute(hk.Command)
		if err != nil {
			log.Warn().Err(err).Msg("Invalid shortcut command")
			continue
		}

		aa[key] = ui.NewKeyActionWithOpts(
			hk.Description,
			gotoCmd(r, command, "", !hk.KeepHistory),
			ui.ActionOpts{
				Shared: true,
				HotKey: true,
			},
		)
	}

	return errs
}

func gotoCmd(r Runner, cmd, path string, clearStack bool) ui.ActionHandler {
	return func(evt *tcell.EventKey) *tcell.EventKey {

Review comment (suggestion):
I think we should flag this in the logs so users can check why a familiar key either stopped working or enabled a different functionality... Best to let users know which plugin/hotkey caused it.

Code after:
		}
	}

	return false
}

func hotKeyActions(r Runner, aa ui.KeyActions) error {
	hh := config.NewHotKeys()
	for k, a := range aa {
		if a.Opts.HotKey {
			delete(aa, k)
		}
	}

	var errs error
	if err := hh.Load(r.App().Config.ContextHotkeysPath()); err != nil {
		errs = errors.Join(errs, err)
	}
	for k, hk := range hh.HotKey {
		key, err := asKey(hk.ShortCut)
		if err != nil {
			errs = errors.Join(errs, err)
			continue
		}
		_, ok := aa[key]
		if ok && !hk.Override {
			errs = errors.Join(errs, fmt.Errorf("duplicated hotkeys found for %q in %q", hk.ShortCut, k))
			continue
		} else if ok && hk.Override == true {
			log.Info().Msgf("Action %q has been overrided by hotkey in %q", hk.ShortCut, k)
		}

		command, err := r.EnvFn()().Substitute(hk.Command)
		if err != nil {
			log.Warn().Err(err).Msg("Invalid shortcut command")
			continue
		}

		aa[key] = ui.NewKeyActionWithOpts(
			hk.Description,
			gotoCmd(r, command, "", !hk.KeepHistory),
			ui.ActionOpts{
				Shared: true,
				HotKey: true,
			},
		)
	}

	return errs
}
Repository: derailed/k9s
File: internal/dao/helm_chart.go (Go)

Code before:

// Uninstall uninstalls a HelmChart.
func (h *HelmChart) Uninstall(path string, keepHist bool) error {
	ns, n := client.Namespaced(path)
	flags := h.Client().Config().Flags()
	flags.Namespace = &ns
	cfg, err := ensureHelmConfig(flags, ns)
	if err != nil {
		return err
	}

	u := action.NewUninstall(cfg)
	u.KeepHistory = keepHist
	res, err := u.Run(n)
	if err != nil {
		return err
	}
	if res != nil && res.Info != "" {
		return fmt.Errorf("%s", res.Info)
	}

	return nil
}

// ensureHelmConfig return a new configuration.
func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.Configuration, error) {
	settings := &genericclioptions.ConfigFlags{
		Namespace:        &ns,
		Context:          flags.Context,
		BearerToken:      flags.BearerToken,
		APIServer:        flags.APIServer,
		CAFile:           flags.CAFile,
		KubeConfig:       flags.KubeConfig,
		Impersonate:      flags.Impersonate,
		Insecure:         flags.Insecure,
		TLSServerName:    flags.TLSServerName,
		ImpersonateGroup: flags.ImpersonateGroup,
		WrapConfigFn:     flags.WrapConfigFn,
	}
	cfg := new(action.Configuration)
	err := cfg.Init(settings, ns, os.Getenv("HELM_DRIVER"), helmLogger)

	return cfg, err
}

func helmLogger(fmt string, args ...interface{}) {
	log.Debug().Msgf("[Helm] "+fmt, args...)
}


Review comment (suggestion):
I don't think we need to clone all the flags. Setting the namespace should be sufficient since the namespace override is not considered.

Code after:

// Uninstall uninstalls a HelmChart.
func (h *HelmChart) Uninstall(path string, keepHist bool) error {
	ns, n := client.Namespaced(path)
	flags := h.Client().Config().Flags()
	cfg, err := ensureHelmConfig(flags, ns)
	if err != nil {
		return err
	}

	u := action.NewUninstall(cfg)
	u.KeepHistory = keepHist
	res, err := u.Run(n)
	if err != nil {
		return err
	}
	if res != nil && res.Info != "" {
		return fmt.Errorf("%s", res.Info)
	}

	return nil
}

// ensureHelmConfig return a new configuration.
func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.Configuration, error) {
	settings := &genericclioptions.ConfigFlags{
		Namespace:        &ns,
		Context:          flags.Context,
		BearerToken:      flags.BearerToken,
		APIServer:        flags.APIServer,
		CAFile:           flags.CAFile,
		KubeConfig:       flags.KubeConfig,
		Impersonate:      flags.Impersonate,
		Insecure:         flags.Insecure,
		TLSServerName:    flags.TLSServerName,
		ImpersonateGroup: flags.ImpersonateGroup,
		WrapConfigFn:     flags.WrapConfigFn,
	}
	cfg := new(action.Configuration)
	err := cfg.Init(settings, ns, os.Getenv("HELM_DRIVER"), helmLogger)

	return cfg, err
}

func helmLogger(fmt string, args ...interface{}) {
	log.Debug().Msgf("[Helm] "+fmt, args...)
}
Repository: derailed/k9s
File: internal/dao/helm_chart.go (Go)

Code before:
	res, err := u.Run(n)
	if err != nil {
		return err
	}
	if res != nil && res.Info != "" {
		return fmt.Errorf("%s", res.Info)
	}

	return nil
}

// ensureHelmConfig return a new configuration.
func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.Configuration, error) {
	settings := &genericclioptions.ConfigFlags{
		Namespace:        &ns,
		Context:          flags.Context,
		BearerToken:      flags.BearerToken,
		APIServer:        flags.APIServer,
		CAFile:           flags.CAFile,
		KubeConfig:       flags.KubeConfig,
		Impersonate:      flags.Impersonate,
		Insecure:         flags.Insecure,
		TLSServerName:    flags.TLSServerName,
		ImpersonateGroup: flags.ImpersonateGroup,
		WrapConfigFn:     flags.WrapConfigFn,
	}
	cfg := new(action.Configuration)
	err := cfg.Init(settings, ns, os.Getenv("HELM_DRIVER"), helmLogger)

	return cfg, err
}

func helmLogger(fmt string, args ...interface{}) {
	log.Debug().Msgf("[Helm] "+fmt, args...)
}


Review comment (suggestion):
Hi @derailed, unfortunately I'm not too familiar with k9s' and Helms' codebase, so I've just been trying to orient myself on [how helm constructs their client](https://github.com/helm/helm/blob/main/pkg/cli/environment.go#L115-L136).

Just to be clear: You are suggesting to do this instead?
```suggestion
func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.Configuration, error) {
	settings := &genericclioptions.ConfigFlags{
		Namespace:        &ns,
	}
	cfg := new(action.Configuration)
```

Code after:
	if err != nil {
		return err
	}
	if res != nil && res.Info != "" {
		return fmt.Errorf("%s", res.Info)
	}

	return nil
}

// ensureHelmConfig return a new configuration.
func ensureHelmConfig(flags *genericclioptions.ConfigFlags, ns string) (*action.Configuration, error) {
	settings := &genericclioptions.ConfigFlags{
		Namespace:        &ns,
		Context:          flags.Context,
		BearerToken:      flags.BearerToken,
		APIServer:        flags.APIServer,
		CAFile:           flags.CAFile,
		KubeConfig:       flags.KubeConfig,
		Impersonate:      flags.Impersonate,
		Insecure:         flags.Insecure,
		TLSServerName:    flags.TLSServerName,
		ImpersonateGroup: flags.ImpersonateGroup,
		WrapConfigFn:     flags.WrapConfigFn,
	}
	cfg := new(action.Configuration)
	err := cfg.Init(settings, ns, os.Getenv("HELM_DRIVER"), helmLogger)

	return cfg, err
}

func helmLogger(fmt string, args ...interface{}) {
	log.Debug().Msgf("[Helm] "+fmt, args...)
}
Repository: derailed/k9s
File: internal/view/app.go (Go)

Code before:
	// overwrite the default ctrl-c behavior of tview
	return nil
}

func (a *App) helpCmd(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == '?' && a.Prompt().InCmdMode() {
		return evt
	}

	top := a.Content.Top()
	if top != nil && top.Name() == "help" {
		a.Content.Pop()
		return nil
	}

	if err := a.inject(NewHelp(a), false); err != nil {
		a.Flash().Err(err)
	}

	a.Prompt().Deactivate()
	return nil
}

// previousView returns to the view prior to the current one in the history
func (a *App) previousView(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == 'b' && a.Prompt().InCmdMode() {
		return evt
	}
	cmds := a.cmdHistory.List()
	if !(len(cmds) > 1) {
		dialog.ShowError(
			a.Styles.Dialog(),
			a.Content.Pages,
			"Can't go back any further")
		return evt
	} else {
		previousCmd := cmds[1]
		a.cmdHistory.Pop()
		a.gotoResource(previousCmd, "", true)
		a.ResetCmd()
	}

	return nil
}

// lastView switches between the last view and this one a la `cd -`
func (a *App) lastView(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == '-' && a.Prompt().InCmdMode() {
		return evt
	}
	cmds := a.cmdHistory.List()

Review comment (suggestion):
IMHO `evt.Rune() == 'b'` should use a variable for the comparison, not a hardcoded value. This would potentially allow rebinding the key in the future.

Code after:

	// overwrite the default ctrl-c behavior of tview
	return nil
}

func (a *App) helpCmd(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == '?' && a.Prompt().InCmdMode() {
		return evt
	}

	top := a.Content.Top()
	if top != nil && top.Name() == "help" {
		a.Content.Pop()
		return nil
	}

	if err := a.inject(NewHelp(a), false); err != nil {
		a.Flash().Err(err)
	}

	a.Prompt().Deactivate()
	return nil
}

// previousCommand returns to the command prior to the current one in the history
func (a *App) previousCommand(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == rune(ui.KeyLeftBracket) && a.Prompt().InCmdMode() {
		return evt
	}
	cmds := a.cmdHistory.List()
	if !a.cmdHistory.Back() {
		a.App.Flash().Warn("Can't go back any further")
		return evt
	}
	a.gotoResource(cmds[a.cmdHistory.CurrentIndex()], "", true, false)
	return nil
}

// nextCommand returns to the command subsequent to the current one in the history
func (a *App) nextCommand(evt *tcell.EventKey) *tcell.EventKey {
	if evt != nil && evt.Rune() == rune(ui.KeyRightBracket) && a.Prompt().InCmdMode() {
		return evt
	}
	cmds := a.cmdHistory.List()
	if !a.cmdHistory.Forward() {
		a.App.Flash().Warn("Can't go forward any further")
		return evt
	}
	// We go to the resource before updating the history so that
	// gotoResource doesn't add this command to the history
	a.gotoResource(cmds[a.cmdHistory.CurrentIndex()], "", true, false)