@@ -18,6 +18,13 @@ import (
1818 "github.com/charmbracelet/lipgloss"
1919)
2020
21+ type detailMode int
22+
23+ const (
24+ detailModeRaw detailMode = iota
25+ detailModeFormatted
26+ )
27+
2128// Custom styles for result items
2229var (
2330 resultItemStyle = lipgloss .NewStyle ().
@@ -35,33 +42,30 @@ var (
3542 PaddingRight (2 ).
3643 BorderStyle (lipgloss .RoundedBorder ()).
3744 BorderForeground (lipgloss .Color ("170" ))
45+
46+ msgStyle = lipgloss .NewStyle ().Bold (true )
47+ timestampStyle = lipgloss .NewStyle ().Foreground (lipgloss .Color ("241" ))
3848)
3949
40- // resultItemDelegate is a custom delegate for rendering result items in list view
41- type resultItemDelegate struct {}
50+ type resultItemDelegateRaw struct {}
4251
43- func (d resultItemDelegate ) Height () int { return 2 }
44- func (d resultItemDelegate ) Spacing () int { return 1 }
45- func (d resultItemDelegate ) Update (msg tea.Msg , m * list.Model ) tea.Cmd { return nil }
46- func (d resultItemDelegate ) Render (w io.Writer , m list.Model , index int , item list.Item ) {
52+ func (d resultItemDelegateRaw ) Height () int { return 2 }
53+ func (d resultItemDelegateRaw ) Spacing () int { return 1 }
54+ func (d resultItemDelegateRaw ) Update (msg tea.Msg , m * list.Model ) tea.Cmd { return nil }
55+ func (d resultItemDelegateRaw ) Render (w io.Writer , m list.Model , index int , item list.Item ) {
4756 result , ok := item .(resultItem )
4857 if ! ok {
4958 return
5059 }
5160
52- // Show a compact preview across 2 lines
5361 data , _ := json .Marshal (result .data )
5462 preview := string (data )
5563
56- // Calculate available width per line
57- maxLen := m .Width () - 4 // Reduce the padding subtraction
58-
59- isSelected := index == m .Index ()
60-
61- // Split into two lines
62- line1 := fmt .Sprintf ("%d. %s" , index + 1 , preview )
64+ line1 := preview
6365 line2 := ""
6466
67+ maxLen := m .Width () - 4
68+
6569 if len (preview ) > maxLen {
6670 line1 = preview [:maxLen ]
6771 if len (preview ) > maxLen * 2 {
@@ -71,22 +75,73 @@ func (d resultItemDelegate) Render(w io.Writer, m list.Model, index int, item li
7175 }
7276 }
7377
74- firstLine := line1
75- secondLine := fmt .Sprintf ("%s" , line2 )
76-
77- output := firstLine
78+ output := line1
7879 if line2 != "" {
79- output += "\n " + secondLine
80+ output += "\n " + line2
8081 }
8182
83+ isSelected := index == m .Index ()
84+
8285 if isSelected {
8386 fmt .Fprint (w , selectedResultStyle .Render (output ))
8487 } else {
8588 fmt .Fprint (w , resultItemStyle .Render (output ))
8689 }
8790}
8891
89- // resultItemDelegate is a custom delegate for rendering result items in list view
92+ type resultItemDelegateFormatted struct {}
93+
94+ func (d resultItemDelegateFormatted ) Height () int { return 2 }
95+ func (d resultItemDelegateFormatted ) Spacing () int { return 1 }
96+ func (d resultItemDelegateFormatted ) Update (msg tea.Msg , m * list.Model ) tea.Cmd { return nil }
97+
98+ func (d resultItemDelegateFormatted ) Render (w io.Writer , m list.Model , index int , item list.Item ) {
99+ result , ok := item .(resultItem )
100+ if ! ok {
101+ return
102+ }
103+
104+ data , _ := json .Marshal (result .data )
105+ preview := string (data )
106+
107+ line1 := ""
108+
109+ if msg , ok := result .data ["message" ]; ok {
110+ if message , ok := msg .(string ); ok {
111+ line1 = msgStyle .Render (message )
112+ } else {
113+ line1 = msgStyle .Render (fmt .Sprintf ("%v" , msg ))
114+ }
115+ }
116+
117+ if ts , ok := result .data ["timestamp" ]; ok {
118+ if timestamp , ok := ts .(string ); ok {
119+ line1 = fmt .Sprintf ("%s - %s" , timestampStyle .Render (timestamp ), line1 )
120+ }
121+ }
122+
123+ maxLen := m .Width () - 4
124+
125+ line2 := preview
126+
127+ if len (line1 ) > maxLen {
128+ line1 = line1 [:maxLen ]
129+ }
130+ if len (preview ) > maxLen {
131+ line2 = preview [:maxLen ]
132+ } else {
133+ line2 = preview
134+ }
135+
136+ output := line1 + "\n " + line2
137+ isSelected := index == m .Index ()
138+
139+ if isSelected {
140+ fmt .Fprint (w , selectedResultStyle .Render (output ))
141+ } else {
142+ fmt .Fprint (w , resultItemStyle .Render (output ))
143+ }
144+ }
90145
91146type pane int
92147
@@ -146,13 +201,14 @@ type model struct {
146201 size int
147202 maxPages int64
148203
149- queryInput textinput.Model
150- fieldsList list.Model
151- valuesList list.Model
152- resultsList list.Model
153- detailView viewport.Model
154- spinner spinner.Model
155- debugView string
204+ queryInput textinput.Model
205+ fieldsList list.Model
206+ valuesList list.Model
207+ resultsListRaw list.Model
208+ resultsListFormatted list.Model
209+ detailView viewport.Model
210+ spinner spinner.Model
211+ debugView string
156212
157213 selectedField fieldItem
158214
@@ -171,6 +227,8 @@ type model struct {
171227 fieldValues map [string ]map [string ]int
172228 showingDetail bool
173229
230+ detailMode detailMode
231+
174232 err error
175233 loading bool
176234}
@@ -220,40 +278,52 @@ func initialModel(ctx context.Context, config Config, query string) model {
220278 valuesList .SetFilteringEnabled (true )
221279
222280 // Results list showing compact previews
223- resultsList := list .New ([]list.Item {}, resultItemDelegate {}, 80 , 20 )
224- resultsList .Title = "Results"
225- resultsList .SetShowStatusBar (false )
226- resultsList .SetFilteringEnabled (false )
227- resultsList .SetShowHelp (false )
228- resultsList .SetShowPagination (true )
229- resultsList .SetShowTitle (true )
230- resultsList .DisableQuitKeybindings ()
231- resultsList .SetFilteringEnabled (true )
281+ resultsListRaw := list .New ([]list.Item {}, resultItemDelegateRaw {}, 80 , 20 )
282+ resultsListRaw .Title = "Results"
283+ resultsListRaw .SetShowStatusBar (false )
284+ resultsListRaw .SetFilteringEnabled (false )
285+ resultsListRaw .SetShowHelp (false )
286+ resultsListRaw .SetShowPagination (true )
287+ resultsListRaw .SetShowTitle (true )
288+ resultsListRaw .DisableQuitKeybindings ()
289+ resultsListRaw .SetFilteringEnabled (true )
290+
291+ // Results list showing compact previews
292+ resultsListFormatted := list .New ([]list.Item {}, resultItemDelegateFormatted {}, 80 , 20 )
293+ resultsListFormatted .Title = "Results"
294+ resultsListFormatted .SetShowStatusBar (false )
295+ resultsListFormatted .SetFilteringEnabled (false )
296+ resultsListFormatted .SetShowHelp (false )
297+ resultsListFormatted .SetShowPagination (true )
298+ resultsListFormatted .SetShowTitle (true )
299+ resultsListFormatted .DisableQuitKeybindings ()
300+ resultsListFormatted .SetFilteringEnabled (true )
232301
233302 // Detail viewport for full JSON view
234303 detailView := viewport .New (0 , 0 )
235304
236305 return model {
237- ctx : ctx ,
238- account : config .Account ,
239- token : config .Token ,
240- size : config .Size ,
241- maxPages : config .MaxPages ,
242- from : config .From ,
243- to : config .To ,
244- concurrency : config .Concurrency ,
245- queryInput : ti ,
246- fieldsList : fieldsList ,
247- valuesList : valuesList ,
248- resultsList : resultsList ,
249- detailView : detailView ,
250- spinner : spinner .New (),
251- debugView : "" ,
252- currentPane : queryPane ,
253- allFields : make (map [string ]int ),
254- fieldValues : make (map [string ]map [string ]int ),
255- fieldPath : []string {},
256- showingDetail : false ,
306+ ctx : ctx ,
307+ account : config .Account ,
308+ token : config .Token ,
309+ size : config .Size ,
310+ maxPages : config .MaxPages ,
311+ from : config .From ,
312+ to : config .To ,
313+ concurrency : config .Concurrency ,
314+ queryInput : ti ,
315+ fieldsList : fieldsList ,
316+ valuesList : valuesList ,
317+ resultsListRaw : resultsListRaw ,
318+ resultsListFormatted : resultsListFormatted ,
319+ detailView : detailView ,
320+ spinner : spinner .New (),
321+ debugView : "" ,
322+ currentPane : queryPane ,
323+ allFields : make (map [string ]int ),
324+ fieldValues : make (map [string ]map [string ]int ),
325+ fieldPath : []string {},
326+ showingDetail : false ,
257327 }
258328}
259329
@@ -273,6 +343,17 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
273343
274344 case tea.KeyMsg :
275345 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
354+ }
355+ return m , nil
356+
276357 case "ctrl+c" , "q" :
277358 return m , tea .Quit
278359
@@ -320,10 +401,19 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
320401
321402 if m .currentPane == resultsPane {
322403 // Show detail view for selected result
323- if item , ok := m .resultsList .SelectedItem ().(resultItem ); ok {
324- m .showDetailView (item )
325- m .showingDetail = true
326- m .currentPane = detailPane
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+ }
327417 }
328418 return m , nil
329419 }
@@ -384,7 +474,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
384474 cmds = append (cmds , cmd )
385475 case resultsPane :
386476 var cmd tea.Cmd
387- m .resultsList , cmd = m .resultsList .Update (msg )
477+ m .resultsListRaw , cmd = m .resultsListRaw .Update (msg )
478+ m .resultsListFormatted , _ = m .resultsListFormatted .Update (msg )
388479 cmds = append (cmds , cmd )
389480 }
390481 }
@@ -410,7 +501,8 @@ func (m *model) updateSizes() {
410501 // Set sizes to content area (borders will be added by lipgloss)
411502 m .fieldsList .SetSize (leftPaneWidth , paneHeight - 2 )
412503 m .valuesList .SetSize (midPaneWidth , paneHeight - 2 )
413- m .resultsList .SetSize (rightPaneWidth , paneHeight - 2 )
504+ m .resultsListRaw .SetSize (rightPaneWidth , paneHeight - 2 )
505+ m .resultsListFormatted .SetSize (rightPaneWidth , paneHeight - 2 )
414506
415507 // Store widths and height for rendering
416508 m .fieldsWidth = leftPaneWidth
@@ -487,7 +579,12 @@ func (m model) View() string {
487579
488580 fieldsSection := fieldsStyle .Width (m .fieldsWidth ).MaxHeight (m .paneHeight ).Render (m .fieldsList .View ())
489581 valuesSection := valuesStyle .Width (m .valuesWidth ).MaxHeight (m .paneHeight ).Render (m .valuesList .View ())
490- resultsSection := resultsStyle .Width (m .resultsWidth ).MaxHeight (m .paneHeight ).Render (m .resultsList .View ())
582+ var resultsSection string
583+ if m .detailMode == detailModeRaw {
584+ resultsSection = resultsStyle .Width (m .resultsWidth ).MaxHeight (m .paneHeight ).Render (m .resultsListRaw .View ())
585+ } else {
586+ resultsSection = resultsStyle .Width (m .resultsWidth ).MaxHeight (m .paneHeight ).Render (m .resultsListFormatted .View ())
587+ }
491588
492589 panesRow := lipgloss .JoinHorizontal (lipgloss .Top ,
493590 fieldsSection ,
@@ -677,14 +774,16 @@ func (m *model) updateResultsView() {
677774 var items []list.Item
678775
679776 for i , result := range m .results {
680- m .resultsList .SetItems (items )
777+ m .resultsListRaw .SetItems (items )
778+ m .resultsListFormatted .SetItems (items )
681779 items = append (items , resultItem {
682780 index : i ,
683781 data : result ,
684782 })
685783 }
686784
687- m .resultsList .SetItems (items )
785+ m .resultsListRaw .SetItems (items )
786+ m .resultsListFormatted .SetItems (items )
688787}
689788
690789func replaceExisitingSearch (query , field , value string ) string {
0 commit comments