Skip to content

Commit c9db283

Browse files
committed
feat: add key bindings and help for result view modes
- Introduce resultsKeyMap struct to manage key bindings - Add help text for view mode switching (1/2) and detail view - Enable help display in results lists - Refactor mode switching to use key.Matches pattern - Consolidate enter key handling for opening detail view - Rename detailMode to resultsMode for clarity The key bindings are now properly documented in the help system, making it easier for users to discover view switching and detail navigation features.
1 parent 1cfef86 commit c9db283

File tree

1 file changed

+76
-36
lines changed

1 file changed

+76
-36
lines changed

tui.go

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111

1212
"github.com/Ajnasz/go-loggly-cli/search"
13+
"github.com/charmbracelet/bubbles/key"
1314
"github.com/charmbracelet/bubbles/list"
1415
"github.com/charmbracelet/bubbles/spinner"
1516
"github.com/charmbracelet/bubbles/textinput"
@@ -18,10 +19,10 @@ import (
1819
"github.com/charmbracelet/lipgloss"
1920
)
2021

21-
type detailMode int
22+
type resultMode int
2223

2324
const (
24-
detailModeRaw detailMode = iota
25+
detailModeRaw resultMode = iota
2526
detailModeFormatted
2627
)
2728

@@ -47,6 +48,29 @@ var (
4748
timestampStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
4849
)
4950

51+
type resultsKeyMap struct {
52+
openDetail key.Binding
53+
openRaw key.Binding
54+
openFormatted key.Binding
55+
}
56+
57+
func newResultsKeyMap() *resultsKeyMap {
58+
return &resultsKeyMap{
59+
openDetail: key.NewBinding(
60+
key.WithKeys("enter"),
61+
key.WithHelp("enter", "view detail"),
62+
),
63+
openRaw: key.NewBinding(
64+
key.WithKeys("1"),
65+
key.WithHelp("1", "raw view"),
66+
),
67+
openFormatted: key.NewBinding(
68+
key.WithKeys("2"),
69+
key.WithHelp("2", "formatted view"),
70+
),
71+
}
72+
}
73+
5074
type resultItemDelegateRaw struct{}
5175

5276
func (d resultItemDelegateRaw) Height() int { return 2 }
@@ -227,7 +251,8 @@ type model struct {
227251
fieldValues map[string]map[string]int
228252
showingDetail bool
229253

230-
detailMode detailMode
254+
resultsMode resultMode
255+
resultsKeyMap *resultsKeyMap
231256

232257
err error
233258
loading bool
@@ -259,6 +284,8 @@ var (
259284
)
260285

261286
func initialModel(ctx context.Context, config Config, query string) model {
287+
resultsKeys := newResultsKeyMap()
288+
262289
ti := textinput.New()
263290
ti.Placeholder = "Enter your Loggly query..."
264291
ti.Focus()
@@ -282,22 +309,36 @@ func initialModel(ctx context.Context, config Config, query string) model {
282309
resultsListRaw.Title = "Results"
283310
resultsListRaw.SetShowStatusBar(false)
284311
resultsListRaw.SetFilteringEnabled(false)
285-
resultsListRaw.SetShowHelp(false)
312+
resultsListRaw.SetShowHelp(true)
286313
resultsListRaw.SetShowPagination(true)
287314
resultsListRaw.SetShowTitle(true)
288315
resultsListRaw.DisableQuitKeybindings()
289316
resultsListRaw.SetFilteringEnabled(true)
317+
resultsListRaw.AdditionalShortHelpKeys = func() []key.Binding {
318+
return []key.Binding{
319+
resultsKeys.openRaw,
320+
resultsKeys.openFormatted,
321+
resultsKeys.openDetail,
322+
}
323+
}
290324

291325
// Results list showing compact previews
292326
resultsListFormatted := list.New([]list.Item{}, resultItemDelegateFormatted{}, 80, 20)
293327
resultsListFormatted.Title = "Results"
294328
resultsListFormatted.SetShowStatusBar(false)
295329
resultsListFormatted.SetFilteringEnabled(false)
296-
resultsListFormatted.SetShowHelp(false)
330+
resultsListFormatted.SetShowHelp(true)
297331
resultsListFormatted.SetShowPagination(true)
298332
resultsListFormatted.SetShowTitle(true)
299333
resultsListFormatted.DisableQuitKeybindings()
300334
resultsListFormatted.SetFilteringEnabled(true)
335+
resultsListFormatted.AdditionalShortHelpKeys = func() []key.Binding {
336+
return []key.Binding{
337+
resultsKeys.openRaw,
338+
resultsKeys.openFormatted,
339+
resultsKeys.openDetail,
340+
}
341+
}
301342

302343
// Detail viewport for full JSON view
303344
detailView := viewport.New(0, 0)
@@ -324,6 +365,8 @@ func initialModel(ctx context.Context, config Config, query string) model {
324365
fieldValues: make(map[string]map[string]int),
325366
fieldPath: []string{},
326367
showingDetail: false,
368+
resultsMode: detailModeRaw,
369+
resultsKeyMap: resultsKeys,
327370
}
328371
}
329372

@@ -342,18 +385,34 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
342385
return m, nil
343386

344387
case tea.KeyMsg:
345-
switch msg.String() {
346-
case "1":
347-
if m.currentPane == resultsPane && !m.showingDetail {
348-
m.detailMode = detailModeRaw
349-
}
350-
return m, nil
351-
case "2":
352-
if m.currentPane == resultsPane && !m.showingDetail {
353-
m.detailMode = detailModeFormatted
388+
if m.currentPane == resultsPane && !m.showingDetail {
389+
switch {
390+
case key.Matches(msg, m.resultsKeyMap.openRaw):
391+
m.resultsMode = detailModeRaw
392+
return m, nil
393+
case key.Matches(msg, m.resultsKeyMap.openFormatted):
394+
m.resultsMode = detailModeFormatted
395+
return m, nil
396+
case key.Matches(msg, m.resultsKeyMap.openDetail):
397+
// Show detail view for selected result
398+
if m.resultsMode == detailModeRaw {
399+
if item, ok := m.resultsListRaw.SelectedItem().(resultItem); ok {
400+
m.showDetailView(item)
401+
m.showingDetail = true
402+
m.currentPane = detailPane
403+
}
404+
} else {
405+
// Formatted mode
406+
if item, ok := m.resultsListFormatted.SelectedItem().(resultItem); ok {
407+
m.showDetailView(item)
408+
m.showingDetail = true
409+
m.currentPane = detailPane
410+
}
411+
}
412+
return m, nil
354413
}
355-
return m, nil
356-
414+
}
415+
switch msg.String() {
357416
case "ctrl+c", "q":
358417
return m, tea.Quit
359418

@@ -399,25 +458,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
399458
return m, m.executeQuery()
400459
}
401460

402-
if m.currentPane == resultsPane {
403-
// Show detail view for selected result
404-
if m.detailMode == detailModeRaw {
405-
if item, ok := m.resultsListRaw.SelectedItem().(resultItem); ok {
406-
m.showDetailView(item)
407-
m.showingDetail = true
408-
m.currentPane = detailPane
409-
}
410-
} else {
411-
// Formatted mode
412-
if item, ok := m.resultsListFormatted.SelectedItem().(resultItem); ok {
413-
m.showDetailView(item)
414-
m.showingDetail = true
415-
m.currentPane = detailPane
416-
}
417-
}
418-
return m, nil
419-
}
420-
421461
case "backspace":
422462
if m.currentPane == fieldsPane && len(m.fieldPath) > 0 {
423463
m.fieldPath = m.fieldPath[:len(m.fieldPath)-1]
@@ -580,7 +620,7 @@ func (m model) View() string {
580620
fieldsSection := fieldsStyle.Width(m.fieldsWidth).MaxHeight(m.paneHeight).Render(m.fieldsList.View())
581621
valuesSection := valuesStyle.Width(m.valuesWidth).MaxHeight(m.paneHeight).Render(m.valuesList.View())
582622
var resultsSection string
583-
if m.detailMode == detailModeRaw {
623+
if m.resultsMode == detailModeRaw {
584624
resultsSection = resultsStyle.Width(m.resultsWidth).MaxHeight(m.paneHeight).Render(m.resultsListRaw.View())
585625
} else {
586626
resultsSection = resultsStyle.Width(m.resultsWidth).MaxHeight(m.paneHeight).Render(m.resultsListFormatted.View())

0 commit comments

Comments
 (0)