4343 availableButtons = []button {scaffoldBtn , viewSourceBtn }
4444)
4545
46- func (b button ) String () string {
47- return []string {
48- "Scaffold" ,
49- "View Source in Browser" ,
50- }[b ]
51- }
52-
5346type Model struct {
5447 lists [numTabs ]list.Model
5548 logger log.Logger
@@ -73,25 +66,6 @@ type Model struct {
7366 userNavigated bool
7467}
7568
76- // ExitMessage returns the styled post-exit message the model set while
77- // handling its final action (e.g., a successful copy that generated a
78- // terragrunt.values.hcl file). The caller is responsible for printing it
79- // after the tea.Program returns, once the alt screen has been torn down.
80- func (m Model ) ExitMessage () string { //nolint:gocritic
81- return m .exitMessage
82- }
83-
84- // List returns the currently active list — the one filtered by the active
85- // tab. Exposed for tests and view code that need to inspect items.
86- func (m Model ) List () list.Model { //nolint:gocritic
87- return m .lists [m .activeTab ]
88- }
89-
90- // ActiveTab returns which of the All/Modules/Templates tabs is focused.
91- func (m Model ) ActiveTab () tabKind { //nolint:gocritic
92- return m .activeTab
93- }
94-
9569// NewModelStreaming creates a Model with a single initial entry and a channel
9670// for receiving additional entries as they are discovered.
9771func NewModelStreaming (l log.Logger , opts * options.TerragruntOptions , initial * ComponentEntry , componentCh chan * ComponentEntry ) Model {
@@ -103,79 +77,48 @@ func NewModelStreaming(l log.Logger, opts *options.TerragruntOptions, initial *C
10377 return m
10478}
10579
106- func newModelWithItems (l log.Logger , opts * options.TerragruntOptions , items []list.Item , componentCh chan * ComponentEntry ) Model {
107- listKeys := tui .NewListKeyMap ()
108- delegateKeys := tui .NewDelegateKeyMap ()
109- pagerKeys := tui .NewPagerKeyMap ()
110-
111- delegate := newCatalogDelegate (delegateKeys )
112-
113- titleStyle := lipgloss .NewStyle ().
114- Foreground (lipgloss .Color (titleForegroundColor )).
115- Background (lipgloss .Color (titleBackgroundColor )).
116- Padding (0 , 1 )
117-
118- var lists [numTabs ]list.Model
119-
120- for i := range int (numTabs ) {
121- t := tabKind (i )
80+ // NewModelWithExitMessageForTest constructs a Model carrying only an exit
81+ // message, for tests that exercise post-exit message emission without
82+ // standing up the full catalog list state.
83+ func NewModelWithExitMessageForTest (msg string ) Model {
84+ return Model {exitMessage : msg }
85+ }
12286
123- tabItems := filterItemsByTab (items , t )
87+ // ActiveTab returns which of the All/Modules/Templates tabs is focused.
88+ func (m Model ) ActiveTab () tabKind { //nolint:gocritic
89+ return m .activeTab
90+ }
12491
125- lst := list .New (tabItems , delegate , 0 , 0 )
126- lst .KeyMap = listKeys
127- lst .SetFilteringEnabled (true )
128- // The visible tab strip is rendered in the view; a per-list Title
129- // is redundant, so clear it to keep the tab bar the only label.
130- lst .Title = ""
131- lst .SetShowTitle (false )
132- lst .Styles .Title = titleStyle
133- lists [i ] = lst
134- }
92+ // ExitMessage returns the styled post-exit message the model set while
93+ // handling its final action (e.g., a successful copy that generated a
94+ // terragrunt.values.hcl file). The caller is responsible for printing it
95+ // after the tea.Program returns, once the alt screen has been torn down.
96+ func (m Model ) ExitMessage () string { //nolint:gocritic
97+ return m .exitMessage
98+ }
13599
136- vp := viewport .New (viewport .WithWidth (0 ), viewport .WithHeight (0 ))
100+ // Init implements bubbletea.Model.Init
101+ func (m Model ) Init () tea.Cmd { //nolint:gocritic
102+ cmds := []tea.Cmd {m .buttonBar .Init ()}
137103
138- bs := make ([]string , len (availableButtons ))
139- for i , b := range availableButtons {
140- bs [i ] = b .String ()
104+ if m .componentCh != nil {
105+ cmds = append (cmds , m .listenForComponent ())
141106 }
142107
143- bb := buttonbar .New (bs )
144-
145- return Model {
146- lists : lists ,
147- listKeys : listKeys ,
148- delegateKeys : delegateKeys ,
149- viewport : vp ,
150- buttonBar : bb ,
151- pagerKeys : pagerKeys ,
152- terragruntOptions : opts ,
153- logger : l ,
154- componentCh : componentCh ,
155- }
108+ return tea .Batch (cmds ... )
156109}
157110
158- // filterItemsByTab returns the subset of items whose Kind belongs in tab t.
159- // TabAll returns everything unchanged.
160- func filterItemsByTab (items []list.Item , t tabKind ) []list.Item {
161- if t == TabAll {
162- return items
163- }
164-
165- out := make ([]list.Item , 0 , len (items ))
166-
167- for _ , it := range items {
168- entry , ok := it .(* ComponentEntry )
169- if ! ok {
170- continue
171- }
172-
173- if t .matches (entry .Kind ()) {
174- out = append (out , entry )
175- }
176- }
111+ // List returns the currently active list — the one filtered by the active
112+ // tab. Exposed for tests and view code that need to inspect items.
113+ func (m Model ) List () list.Model { //nolint:gocritic
114+ return m .lists [m .activeTab ]
115+ }
177116
178- return out
117+ func (b button ) String () string {
118+ return []string {
119+ "Scaffold" ,
120+ "View Source in Browser" ,
121+ }[b ]
179122}
180123
181124// insertComponentSorted inserts a component into every tab whose filter
@@ -246,6 +189,45 @@ func (m *Model) insertIntoList(idx int, entry *ComponentEntry) tea.Cmd {
246189 return cmd
247190}
248191
192+ func (m Model ) listenForComponent () tea.Cmd { //nolint:gocritic
193+ ch := m .componentCh
194+ if ch == nil {
195+ return nil
196+ }
197+
198+ return func () tea.Msg {
199+ c , ok := <- ch
200+ if ! ok {
201+ return nil
202+ }
203+
204+ return componentMsg {entry : c }
205+ }
206+ }
207+
208+ // filterItemsByTab returns the subset of items whose Kind belongs in tab t.
209+ // TabAll returns everything unchanged.
210+ func filterItemsByTab (items []list.Item , t tabKind ) []list.Item {
211+ if t == TabAll {
212+ return items
213+ }
214+
215+ out := make ([]list.Item , 0 , len (items ))
216+
217+ for _ , it := range items {
218+ entry , ok := it .(* ComponentEntry )
219+ if ! ok {
220+ continue
221+ }
222+
223+ if t .matches (entry .Kind ()) {
224+ out = append (out , entry )
225+ }
226+ }
227+
228+ return out
229+ }
230+
249231// isDuplicate reports whether any item in the list has the same source path
250232// as sourcePath. This uses the stable TerraformSourcePath identity rather
251233// than the display title, so distinct components that share a title are not
@@ -262,29 +244,54 @@ func isDuplicate(items []list.Item, sourcePath string) bool {
262244 return false
263245}
264246
265- func (m Model ) listenForComponent () tea.Cmd { //nolint:gocritic
266- ch := m .componentCh
267- if ch == nil {
268- return nil
269- }
247+ func newModelWithItems (l log.Logger , opts * options.TerragruntOptions , items []list.Item , componentCh chan * ComponentEntry ) Model {
248+ listKeys := tui .NewListKeyMap ()
249+ delegateKeys := tui .NewDelegateKeyMap ()
250+ pagerKeys := tui .NewPagerKeyMap ()
270251
271- return func () tea.Msg {
272- c , ok := <- ch
273- if ! ok {
274- return nil
275- }
252+ delegate := newCatalogDelegate (delegateKeys )
276253
277- return componentMsg {entry : c }
254+ titleStyle := lipgloss .NewStyle ().
255+ Foreground (lipgloss .Color (titleForegroundColor )).
256+ Background (lipgloss .Color (titleBackgroundColor )).
257+ Padding (0 , 1 )
258+
259+ var lists [numTabs ]list.Model
260+
261+ for i := range int (numTabs ) {
262+ t := tabKind (i )
263+
264+ tabItems := filterItemsByTab (items , t )
265+
266+ lst := list .New (tabItems , delegate , 0 , 0 )
267+ lst .KeyMap = listKeys
268+ lst .SetFilteringEnabled (true )
269+ // The visible tab strip is rendered in the view; a per-list Title
270+ // is redundant, so clear it to keep the tab bar the only label.
271+ lst .Title = ""
272+ lst .SetShowTitle (false )
273+ lst .Styles .Title = titleStyle
274+ lists [i ] = lst
278275 }
279- }
280276
281- // Init implements bubbletea.Model.Init
282- func (m Model ) Init () tea.Cmd { //nolint:gocritic
283- cmds := []tea.Cmd {m .buttonBar .Init ()}
277+ vp := viewport .New (viewport .WithWidth (0 ), viewport .WithHeight (0 ))
284278
285- if m .componentCh != nil {
286- cmds = append (cmds , m .listenForComponent ())
279+ bs := make ([]string , len (availableButtons ))
280+ for i , b := range availableButtons {
281+ bs [i ] = b .String ()
287282 }
288283
289- return tea .Batch (cmds ... )
284+ bb := buttonbar .New (bs )
285+
286+ return Model {
287+ lists : lists ,
288+ listKeys : listKeys ,
289+ delegateKeys : delegateKeys ,
290+ viewport : vp ,
291+ buttonBar : bb ,
292+ pagerKeys : pagerKeys ,
293+ terragruntOptions : opts ,
294+ logger : l ,
295+ componentCh : componentCh ,
296+ }
290297}
0 commit comments