bubbles icon indicating copy to clipboard operation
bubbles copied to clipboard

fix(help): Fix help bubble not centering correctly

Open gabe565 opened this issue 1 year ago • 0 comments

The help bubble appends the separator after the final column, which results in it being shifted 4 cols to the left when centered. This PR removes the final separator column.

I don't know the reasoning for this decision, so feel free to close this if the final separator column is intended! If it is, maybe a bool should be added to toggle the behavior?

Fixes #415

Thank you!

Examples

ascii-movie

I built ascii-movie, and have seen this behavior. Here's a screenshot before and after the fix:

Before: image

After: image

simple repro

Before/After: image

Code:

package main

import (
	"fmt"
	"os"

	"github.com/charmbracelet/bubbles/help"
	"github.com/charmbracelet/bubbles/key"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

type keyMap struct {
	Up    key.Binding
	Down  key.Binding
	Left  key.Binding
	Right key.Binding
	Help  key.Binding
	Quit  key.Binding
}

func (k keyMap) ShortHelp() []key.Binding {
	return []key.Binding{k.Help, k.Quit}
}

func (k keyMap) FullHelp() [][]key.Binding {
	return [][]key.Binding{
		{k.Up, k.Down, k.Left, k.Right},
		{k.Help, k.Quit},
	}
}

var keys = keyMap{
	Up: key.NewBinding(
		key.WithKeys("up", "k"),
		key.WithHelp("↑/k", "move up"),
	),
	Down: key.NewBinding(
		key.WithKeys("down", "j"),
		key.WithHelp("↓/j", "move down"),
	),
	Left: key.NewBinding(
		key.WithKeys("left", "h"),
		key.WithHelp("←/h", "move left"),
	),
	Right: key.NewBinding(
		key.WithKeys("right", "l"),
		key.WithHelp("→/l", "move right"),
	),
	Help: key.NewBinding(
		key.WithKeys("?"),
		key.WithHelp("?", "toggle help"),
	),
	Quit: key.NewBinding(
		key.WithKeys("q", "esc", "ctrl+c"),
		key.WithHelp("q", "quit"),
	),
}

type model struct {
	keys          keyMap
	help          help.Model
	style         lipgloss.Style
	width, height int
}

func newModel() model {
	h := help.New()
	h.ShowAll = true
	return model{
		keys:  keys,
		help:  h,
		style: lipgloss.NewStyle().Margin(2),
	}
}

func (m model) Init() tea.Cmd {
	return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		m.width, m.height = msg.Width, msg.Height

	case tea.KeyMsg:
		switch {
		case key.Matches(msg, m.keys.Help):
			m.help.ShowAll = !m.help.ShowAll
		case key.Matches(msg, m.keys.Quit):
			return m, tea.Quit
		}
	}

	return m, nil
}

func (m model) View() string {
	text := "Example text to test alignment\n"
	helpView := m.help.View(m.keys)
	content := lipgloss.JoinVertical(lipgloss.Center, text, helpView)
	return m.style.Render(content)
}

func main() {
	if _, err := tea.NewProgram(newModel()).Run(); err != nil {
		fmt.Printf("Could not start program :(\n%v\n", err)
		os.Exit(1)
	}
}

gabe565 avatar Apr 28 '24 07:04 gabe565