Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show help text #138

Merged
merged 8 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions internal/quickstart/choose_sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"strings"

"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
Expand All @@ -22,6 +23,8 @@ const (
)

type chooseSDKModel struct {
help help.Model
helpKeys keyMap
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern here is to have each model define the help keys it shows. These are separate from the keys we handle when they're pressed since we don't necessarily want to show, eg. tab in the help text of the toggle flag model.

list list.Model
selectedIndex int
selectedSDK sdkDetail
Expand All @@ -33,12 +36,26 @@ func NewChooseSDKModel(selectedIndex int) tea.Model {
// reset title styles
l.Styles.Title = lipgloss.NewStyle()
l.Styles.TitleBar = lipgloss.NewStyle()
l.SetShowHelp(false)
l.SetShowPagination(true)
l.SetShowStatusBar(false)
l.SetFilteringEnabled(false) // TODO: try to get filtering working
l.Paginator.PerPage = 5

return chooseSDKModel{
help: help.New(),
helpKeys: keyMap{
Back: BindingBack,
CursorUp: BindingCursorUp,
CursorDown: BindingCursorDown,
PrevPage: BindingPrevPage,
NextPage: BindingNextPage,
GoToStart: BindingGoToStart,
GoToEnd: BindingGoToEnd,
ShowFullHelp: BindingShowFullHelp,
CloseFullHelp: BindingCloseFullHelp,
Quit: BindingQuit,
},
list: l,
selectedIndex: selectedIndex,
}
Expand All @@ -53,13 +70,15 @@ func (m chooseSDKModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Enter):
case key.Matches(msg, pressableKeys.Enter):
i, ok := m.list.SelectedItem().(sdkDetail)
if ok {
m.selectedSDK = i
m.selectedSDK.index = m.list.Index()
cmd = sendChoseSDKMsg(m.selectedSDK)
}
case key.Matches(msg, m.helpKeys.CloseFullHelp):
m.help.ShowAll = !m.help.ShowAll
default:
m.list, cmd = m.list.Update(msg)
}
Expand All @@ -71,7 +90,9 @@ func (m chooseSDKModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (m chooseSDKModel) View() string {
return m.list.View()
helpView := m.help.View(m.helpKeys)

return m.list.View() + "\n\n" + helpView
}

type sdkDetail struct {
Expand Down
30 changes: 2 additions & 28 deletions internal/quickstart/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.width = msg.Width
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Quit):
case key.Matches(msg, pressableKeys.Quit):
m.quitting = true
cmd = tea.Quit
case key.Matches(msg, keys.Back):
case key.Matches(msg, pressableKeys.Back):
switch m.currentStep {
case stepCreateFlag:
// can't go back
Expand Down Expand Up @@ -172,29 +172,3 @@ func (m ContainerModel) View() string {

return wordwrap.String(out, m.width)
}

type keyMap struct {
Back key.Binding
Enter key.Binding
Quit key.Binding
Tab key.Binding
}

var keys = keyMap{
Back: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "go back"),
),
Enter: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "select"),
),
Quit: key.NewBinding(
key.WithKeys("ctrl+c"),
key.WithHelp("q", "quit"),
),
Tab: key.NewBinding(
key.WithKeys("tab"),
key.WithHelp("tab", "toggle"),
),
}
19 changes: 13 additions & 6 deletions internal/quickstart/create_flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package quickstart

import (
"fmt"
"ldcli/internal/flags"

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

"ldcli/internal/flags"
)

const defaultFlagName = "My New Flag"
Expand All @@ -16,6 +18,8 @@ type createFlagModel struct {
accessToken string
baseUri string
client flags.Client
help help.Model
helpKeys keyMap
textInput textinput.Model
}

Expand All @@ -30,7 +34,11 @@ func NewCreateFlagModel(client flags.Client, accessToken, baseUri string) tea.Mo
accessToken: accessToken,
baseUri: baseUri,
client: client,
textInput: ti,
help: help.New(),
helpKeys: keyMap{
Quit: BindingQuit,
},
textInput: ti,
}
}

Expand All @@ -43,7 +51,7 @@ func (m createFlagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Enter):
case key.Matches(msg, pressableKeys.Enter):
input := m.textInput.Value()
if input == "" {
input = defaultFlagName
Expand All @@ -54,8 +62,6 @@ func (m createFlagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

return m, sendCreateFlagMsg(m.client, m.accessToken, m.baseUri, input, flagKey, defaultProjKey)
case key.Matches(msg, keys.Quit):
return m, tea.Quit
default:
m.textInput, cmd = m.textInput.Update(msg)
}
Expand All @@ -67,9 +73,10 @@ func (m createFlagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m createFlagModel) View() string {
style := lipgloss.NewStyle().
MarginLeft(2)
helpView := m.help.View(m.helpKeys)

return fmt.Sprintf(
"Name your first feature flag (enter for default value):%s",
style.Render(m.textInput.View()),
) + "\n"
) + "\n\n" + helpView
}
95 changes: 95 additions & 0 deletions internal/quickstart/help.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package quickstart

import "github.com/charmbracelet/bubbles/key"

var (
BindingBack = key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "back"),
)
BindingCursorUp = key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑/k", "up"),
)
BindingCursorDown = key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓/j", "down"),
)
BindingPrevPage = key.NewBinding(
key.WithKeys("left", "h", "pgup", "b", "u"),
key.WithHelp("←/h/pgup", "prev page"),
)
BindingNextPage = key.NewBinding(
key.WithKeys("right", "l", "pgdown", "f", "d"),
key.WithHelp("→/l/pgdn", "next page"),
)
BindingGoToStart = key.NewBinding(
key.WithKeys("home", "g"),
key.WithHelp("g/home", "go to start"),
)
BindingGoToEnd = key.NewBinding(
key.WithKeys("end", "G"),
key.WithHelp("G/end", "go to end"),
)
BindingShowFullHelp = key.NewBinding(
key.WithKeys("?"),
key.WithHelp("?", "more"),
)
BindingCloseFullHelp = key.NewBinding(
key.WithKeys("?"),
key.WithHelp("?", "close help"),
)
BindingQuit = key.NewBinding(
key.WithKeys("ctrl+c"),
key.WithHelp("ctrl+c", "quit"),
)
)

// keyMap defines all the possible key presses we would respond to
type keyMap struct {
Back key.Binding
CloseFullHelp key.Binding
CursorDown key.Binding
CursorUp key.Binding
Enter key.Binding
GoToEnd key.Binding
GoToStart key.Binding
NextPage key.Binding
PrevPage key.Binding
Quit key.Binding
ShowFullHelp key.Binding
Tab key.Binding
}

func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.CursorUp, k.CursorDown, k.PrevPage, k.NextPage},
{k.Back, k.Quit, k.CloseFullHelp},
}
}

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

// pressableKeys are the possible key presses we support for all steps.
// We don't necessarily want to show these in the help text, but we want to handle them when
// pressed.
var pressableKeys = keyMap{
Back: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "go back"),
),
Enter: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "select"),
),
Quit: key.NewBinding(
key.WithKeys("ctrl+c"),
key.WithHelp("ctrl+c", "quit"),
),
Tab: key.NewBinding(
key.WithKeys("tab"),
key.WithHelp("tab", "toggle"),
),
}
17 changes: 13 additions & 4 deletions internal/quickstart/show_sdk_instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package quickstart
import (
"fmt"

"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
Expand All @@ -19,6 +20,8 @@ type showSDKInstructionsModel struct {
canonicalName string
displayName string
flagKey string
help help.Model
helpKeys keyMap
instructions string
sdkKey string
spinner spinner.Model
Expand All @@ -42,8 +45,13 @@ func NewShowSDKInstructionsModel(
canonicalName: canonicalName,
displayName: displayName,
flagKey: flagKey,
spinner: s,
url: url,
help: help.New(),
helpKeys: keyMap{
Back: BindingBack,
Quit: BindingQuit,
},
spinner: s,
url: url,
}
}

Expand All @@ -60,7 +68,7 @@ func (m showSDKInstructionsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Enter):
case key.Matches(msg, pressableKeys.Enter):
// TODO: only if all data are fetched?
cmd = sendShowToggleFlagMsg()
}
Expand All @@ -78,6 +86,7 @@ func (m showSDKInstructionsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

func (m showSDKInstructionsModel) View() string {
style := lipgloss.NewStyle().Border(lipgloss.NormalBorder(), true, false)
helpView := m.help.View(m.helpKeys)
md, err := m.renderMarkdown()
if err != nil {
return fmt.Sprintf("error rendering instructions: %s", err)
Expand All @@ -94,7 +103,7 @@ func (m showSDKInstructionsModel) View() string {
style.Render(md),
),
0,
)
) + "\n\n" + helpView
}

func (m showSDKInstructionsModel) renderMarkdown() (string, error) {
Expand Down
Loading
Loading