@@ -72,16 +72,16 @@ await AnsiConsole.Live(layout).StartAsync(async ctx =>
7272 _state . WindowHeight = Console . WindowHeight ;
7373 _state . WindowWidth = Console . WindowWidth ;
7474
75- var count = _state . SelectedTable switch
76- {
77- KrpTable . PortForwards => _portForwardTable . Count ,
78- KrpTable . Logs => _logsTable . Count ,
79- _ => 0 ,
80- } ;
81-
82- var redraw = init ;
83- var redrawInfo = false ;
84- var redrawContext = false ;
75+ var count = _state . SelectedTable switch
76+ {
77+ KrpTable . PortForwards => _portForwardTable . Count ,
78+ KrpTable . Logs => _logsTable . Count ,
79+ _ => 0 ,
80+ } ;
81+
82+ var redraw = init ;
83+ var redrawInfo = false ;
84+ var redrawContext = false ;
8585
8686 // Keyboard handling.
8787 if ( Console . KeyAvailable )
@@ -98,27 +98,29 @@ await AnsiConsole.Live(layout).StartAsync(async ctx =>
9898
9999 var shift = ( key . Modifiers & ConsoleModifiers . Shift ) != 0 ;
100100 var ctrl = ( key . Modifiers & ConsoleModifiers . Control ) != 0 ;
101-
101+
102102 switch ( key . Key )
103103 {
104- case ConsoleKey . Home : _state . SelectedRow [ _state . SelectedTable ] = 0 ; redraw = true ; break ;
105- case ConsoleKey . End : _state . SelectedRow [ _state . SelectedTable ] = count - 1 ; redraw = true ; break ;
106- case ConsoleKey . LeftArrow : _state . ColumnOffset = Math . Max ( 0 , _state . ColumnOffset - 1 ) ; redraw = true ; break ;
107- case ConsoleKey . RightArrow : _state . ColumnOffset = Math . Min ( _state . ColumnOffset + 1 , _state . ColumnOffsetMax ) ; redraw = true ; break ;
104+ case ConsoleKey . Home : redraw = true ; _state . SelectedRow [ _state . SelectedTable ] = 0 ; break ;
105+ case ConsoleKey . End : redraw = true ; _state . SelectedRow [ _state . SelectedTable ] = Math . Max ( 0 , count - 1 ) ; break ;
106+ case ConsoleKey . PageUp : redraw = _state . SelectedRow [ _state . SelectedTable ] != ( _state . SelectedRow [ _state . SelectedTable ] = Math . Max ( 0 , _state . SelectedRow [ _state . SelectedTable ] - GetPageSize ( _state . SelectedTable ) ) ) ; break ;
107+ case ConsoleKey . PageDown : redraw = _state . SelectedRow [ _state . SelectedTable ] != ( _state . SelectedRow [ _state . SelectedTable ] = Math . Min ( Math . Max ( 0 , count - 1 ) , _state . SelectedRow [ _state . SelectedTable ] + GetPageSize ( _state . SelectedTable ) ) ) ; break ;
108+ case ConsoleKey . LeftArrow : redraw = true ; _state . ColumnOffset = Math . Max ( 0 , _state . ColumnOffset - 1 ) ; break ;
109+ case ConsoleKey . RightArrow : redraw = true ; _state . ColumnOffset = Math . Min ( _state . ColumnOffset + 1 , _state . ColumnOffsetMax ) ; break ;
108110 case ConsoleKey . UpArrow : redraw = _state . SelectedRow [ _state . SelectedTable ] != ( _state . SelectedRow [ _state . SelectedTable ] = Math . Max ( 0 , _state . SelectedRow [ _state . SelectedTable ] - 1 ) ) ; break ;
109111 case ConsoleKey . DownArrow : redraw = _state . SelectedRow [ _state . SelectedTable ] != ( _state . SelectedRow [ _state . SelectedTable ] = Math . Min ( count - 1 , _state . SelectedRow [ _state . SelectedTable ] + 1 ) ) ; break ;
110- case ConsoleKey . D1 : _state . SelectedTable = KrpTable . PortForwards ; redraw = true ; redrawContext = true ; break ;
111- case ConsoleKey . D2 : _state . SelectedTable = KrpTable . Logs ; redraw = true ; redrawContext = true ; break ;
112- case ConsoleKey . I when shift : ToggleSort ( SortField . Ip , ref redraw ) ; break ;
113- case ConsoleKey . N when shift : ToggleSort ( SortField . Namespace , ref redraw ) ; break ;
114- case ConsoleKey . P when shift : ToggleSort ( SortField . PortForward , ref redraw ) ; break ;
115- case ConsoleKey . R when shift : ToggleSort ( SortField . Resource , ref redraw ) ; break ;
116- case ConsoleKey . U when shift : ToggleSort ( SortField . Url , ref redraw ) ; break ;
117- case ConsoleKey . Enter when _state . SelectedTable == KrpTable . PortForwards : _ = _portForwardTable . ForceStart ( ) ; break ;
118- case ConsoleKey . D when ctrl && _state . SelectedTable == KrpTable . PortForwards : _portForwardTable . ForceStop ( ) ; break ;
119- case ConsoleKey . F5 : return ; // Abort inner loop to force a new AnsiConsole.Live instance, forcing a refresh.
120- }
121- }
112+ case ConsoleKey . D1 : redraw = true ; redrawContext = true ; _state . SelectedTable = KrpTable . PortForwards ; break ;
113+ case ConsoleKey . D2 : redraw = true ; redrawContext = true ; _state . SelectedTable = KrpTable . Logs ; break ;
114+ case ConsoleKey . I when shift : redraw = true ; ToggleSort ( SortField . Ip ) ; break ;
115+ case ConsoleKey . N when shift : redraw = true ; ToggleSort ( SortField . Namespace ) ; break ;
116+ case ConsoleKey . P when shift : redraw = true ; ToggleSort ( SortField . PortForward ) ; break ;
117+ case ConsoleKey . R when shift : redraw = true ; ToggleSort ( SortField . Resource ) ; break ;
118+ case ConsoleKey . U when shift : redraw = true ; ToggleSort ( SortField . Url ) ; break ;
119+ case ConsoleKey . Enter when _state . SelectedTable == KrpTable . PortForwards : _ = _portForwardTable . ForceStart ( ) ; break ;
120+ case ConsoleKey . D when ctrl && _state . SelectedTable == KrpTable . PortForwards : _portForwardTable . ForceStop ( ) ; break ;
121+ case ConsoleKey . F5 : return ; // Abort inner loop to force a new AnsiConsole.Live instance, forcing a refresh.
122+ }
123+ }
122124
123125 // Handle kubernetes context (1s).
124126 if ( ! redraw && lastCtx . Elapsed >= TimeSpan . FromSeconds ( 1 ) )
@@ -178,14 +180,20 @@ await AnsiConsole.Live(layout).StartAsync(async ctx =>
178180 return ;
179181 }
180182
181- redraw = true ;
183+ redraw = true ;
182184 }
183185
184- // Redraw panels .
185- if ( redraw )
186+ // Keep viewport anchor in sync with selection for scrolling tables .
187+ if ( _state . SelectedTable == KrpTable . PortForwards )
186188 {
187- layout [ "main" ] . Update ( BuildMainPanel ( ) ) ;
188- init = false ;
189+ UpdateFirstRowAnchor ( _state . SelectedTable , count ) ;
190+ }
191+
192+ // Redraw panels.
193+ if ( redraw )
194+ {
195+ layout [ "main" ] . Update ( BuildMainPanel ( ) ) ;
196+ init = false ;
189197 lastRedrawMain . Restart ( ) ;
190198 }
191199
@@ -300,11 +308,11 @@ private Panel BuildContextMenuPanel()
300308 return panel . NoBorder ( ) . Padding ( 0 , 0 , 0 , 0 ) . HeaderAlignment ( Justify . Left ) ;
301309 }
302310
303- private Panel BuildLogoPanel ( )
304- {
305- var figlet = new FigletText ( _logoFont , "KRP" ) . Color ( Color . Orange1 ) ;
306- var panel = new Panel ( figlet ) ;
307- var padding = 1 ;
311+ private Panel BuildLogoPanel ( )
312+ {
313+ var figlet = new FigletText ( _logoFont , "KRP" ) . Color ( Color . Orange1 ) ;
314+ var panel = new Panel ( figlet ) ;
315+ var padding = 1 ;
308316
309317 if ( _state . WindowSize == WindowSize . XS )
310318 {
@@ -315,11 +323,41 @@ private Panel BuildLogoPanel()
315323 return panel . NoBorder ( ) . Padding ( padding , 0 , 0 , 0 ) ;
316324 }
317325
318- private void ToggleSort ( SortField field , ref bool redraw )
326+ private int GetPageSize ( KrpTable table )
327+ {
328+ return table switch
329+ {
330+ KrpTable . PortForwards => Math . Max ( 1 , _state . WindowHeight - ( PortForwardTable . HEADER_SIZE + HEADER_SIZE ) ) ,
331+ KrpTable . Logs => Math . Max ( 1 , _state . WindowHeight - ( LogsTable . HEADER_SIZE + HEADER_SIZE ) ) ,
332+ _ => 1 ,
333+ } ;
334+ }
335+
336+ private void UpdateFirstRowAnchor ( KrpTable table , int count )
337+ {
338+ var maxRows = Math . Max ( 1 , _state . WindowHeight - ( PortForwardTable . HEADER_SIZE + HEADER_SIZE ) ) ;
339+ var maxFirst = Math . Max ( 0 , count - maxRows ) ;
340+
341+ var selected = Math . Clamp ( _state . SelectedRow [ table ] , 0 , Math . Max ( 0 , count - 1 ) ) ;
342+ var first = _state . AnchorRowIndex [ _state . SelectedTable ] ;
343+
344+ // Keep the selection visible; adjust just enough without paging jumps.
345+ if ( selected < first )
346+ {
347+ first = selected ;
348+ }
349+ else if ( selected >= first + maxRows )
350+ {
351+ first = selected - maxRows + 1 ;
352+ }
353+
354+ _state . AnchorRowIndex [ table ] = Math . Clamp ( first , 0 , maxFirst ) ;
355+ }
356+
357+ private void ToggleSort ( SortField field )
319358 {
320359 _state . SortAscending = _state . SortField != field || ! _state . SortAscending ;
321360 _state . SortField = field ;
322361 _state . SelectedRow [ _state . SelectedTable ] = 0 ; // Reset cursor to top.
323- redraw = true ;
324362 }
325363}
0 commit comments