@@ -491,11 +491,18 @@ public void DrawMenu(Menu previousMenu, bool menuSelect)
491
491
}
492
492
}
493
493
494
+ bool extraPreRowsCleared = false ;
494
495
if ( previousMenu != null )
495
496
{
496
497
if ( Rows < previousMenu . Rows + previousMenu . ToolTipLines )
497
498
{
498
- // Rest of the current line was erased, but the cursor was not moved to the next line.
499
+ // If the last menu row took the whole buffer width, then the cursor could be pushed to the
500
+ // beginning of the next line in the legacy console host (NOT in modern terminals such as
501
+ // Windows Terminal, VSCode Terminal, or virtual-terminal-enabled console host). In such a
502
+ // case, there is no need to move the cursor to the next line.
503
+ //
504
+ // If that is not the case, namely 'CursorLeft != 0', then the rest of the last menu row was
505
+ // erased, but the cursor was not moved to the next line, so we will move the cursor.
499
506
if ( console . CursorLeft != 0 )
500
507
{
501
508
// There are lines from the previous rendering that need to be cleared,
@@ -504,13 +511,25 @@ public void DrawMenu(Menu previousMenu, bool menuSelect)
504
511
}
505
512
506
513
Singleton . WriteBlankLines ( previousMenu . Rows + previousMenu . ToolTipLines - Rows ) ;
514
+ extraPreRowsCleared = true ;
507
515
}
508
516
}
509
517
510
518
// if the menu has moved, we need to clear the lines under it
511
519
if ( bufferEndPoint . Y < PreviousTop )
512
520
{
513
- console . BlankRestOfLine ( ) ;
521
+ // In either of the following two cases, we will need to move the cursor to the next line:
522
+ // - if extra rows from previous menu were cleared, then we know the current line was erased
523
+ // but the cursor was not moved to the next line.
524
+ // - if 'CursorLeft != 0', then the rest of the last menu row was erased, but the cursor
525
+ // was not moved to the next line.
526
+ if ( extraPreRowsCleared || console . CursorLeft != 0 )
527
+ {
528
+ // There are lines from the previous rendering that need to be cleared,
529
+ // so we are sure there is no need to scroll.
530
+ MoveCursorDown ( 1 ) ;
531
+ }
532
+
514
533
Singleton . WriteBlankLines ( PreviousTop - bufferEndPoint . Y ) ;
515
534
}
516
535
@@ -614,10 +633,62 @@ public void UpdateMenuSelection(int selectedItem, bool select, bool showTooltips
614
633
RestoreCursor ( ) ;
615
634
}
616
635
617
- public void MoveRight ( ) => CurrentSelection = Math . Min ( CurrentSelection + Rows , MenuItems . Count - 1 ) ;
618
- public void MoveLeft ( ) => CurrentSelection = Math . Max ( CurrentSelection - Rows , 0 ) ;
619
- public void MoveUp ( ) => CurrentSelection = Math . Max ( CurrentSelection - 1 , 0 ) ;
620
- public void MoveDown ( ) => CurrentSelection = Math . Min ( CurrentSelection + 1 , MenuItems . Count - 1 ) ;
636
+ public void MoveRight ( )
637
+ {
638
+ int nextInSameRow = CurrentSelection + Rows ;
639
+ if ( nextInSameRow <= MenuItems . Count - 1 )
640
+ {
641
+ CurrentSelection = nextInSameRow ;
642
+ return ;
643
+ }
644
+
645
+ // Index of the column where 'CurrentSelection' is at, assuming columns start from left at index 0.
646
+ int columnIndex = CurrentSelection / Rows ;
647
+ int leftmostItemInSameRow = CurrentSelection - columnIndex * Rows ;
648
+
649
+ // Index of the row where 'leftMostItemAtSameRow' is at, assuming rows start from top at index 0.
650
+ int rowIndex = leftmostItemInSameRow % Rows ;
651
+
652
+ // If 'rowIndex == Rows - 1', then 'CurrentSelection' is at the rightmost position in the last row,
653
+ // so moving-to-right again should move to the item at index 0.
654
+ CurrentSelection = rowIndex == Rows - 1 ? 0 : leftmostItemInSameRow + 1 ;
655
+ }
656
+
657
+ public void MoveLeft ( )
658
+ {
659
+ int previousInSameRow = CurrentSelection - Rows ;
660
+ if ( previousInSameRow >= 0 )
661
+ {
662
+ CurrentSelection = previousInSameRow ;
663
+ return ;
664
+ }
665
+
666
+ // Index of the row where 'CurrentSelection' is at, assuming rows start from top at index 0.
667
+ int rowIndex = CurrentSelection % Rows ;
668
+ int leftmostItemInPreviousRow = rowIndex == 0 ? Rows - 1 : rowIndex - 1 ;
669
+
670
+ int lastItemIndex = MenuItems . Count - 1 ;
671
+ // Index of the column where the last item is at, assuming columns start from left at index 0.
672
+ int lastItemColumnIndex = lastItemIndex / Rows ;
673
+
674
+ // Get the rightmost item in the previous row.
675
+ CurrentSelection = leftmostItemInPreviousRow + lastItemColumnIndex * Rows ;
676
+ if ( CurrentSelection > lastItemIndex )
677
+ {
678
+ CurrentSelection = leftmostItemInPreviousRow + ( lastItemColumnIndex - 1 ) * Rows ;
679
+ }
680
+ }
681
+
682
+ public void MoveUp ( )
683
+ {
684
+ CurrentSelection = CurrentSelection > 0 ? CurrentSelection - 1 : MenuItems . Count - 1 ;
685
+ }
686
+
687
+ public void MoveDown ( )
688
+ {
689
+ CurrentSelection = CurrentSelection < ( MenuItems . Count - 1 ) ? CurrentSelection + 1 : 0 ;
690
+ }
691
+
621
692
public void MovePageDown ( ) => CurrentSelection = Math . Min ( CurrentSelection + Rows - ( CurrentSelection % Rows ) - 1 ,
622
693
MenuItems . Count - 1 ) ;
623
694
public void MovePageUp ( ) => CurrentSelection = Math . Max ( CurrentSelection - ( CurrentSelection % Rows ) , 0 ) ;
@@ -808,9 +879,6 @@ private void MenuCompleteImpl(Menu menu, CommandCompletion completions)
808
879
809
880
var userInitialCompletionLength = userCompletionText . Length ;
810
881
811
- completions . CurrentMatchIndex = 0 ;
812
- menu . DrawMenu ( null , menuSelect : true ) ;
813
-
814
882
bool processingKeys = true ;
815
883
int previousSelection = - 1 ;
816
884
@@ -832,38 +900,51 @@ private void MenuCompleteImpl(Menu menu, CommandCompletion completions)
832
900
833
901
ExchangePointAndMark ( ) ;
834
902
835
- // After replacement, the menu might be misplaced from the command line
836
- // getting shorter or longer.
837
- var endOfCommandLine = ConvertOffsetToPoint ( _buffer . Length ) ;
838
- var topAdjustment = ( endOfCommandLine . Y + 1 ) - menu . Top ;
839
-
840
- if ( topAdjustment != 0 )
903
+ if ( previousSelection == - 1 )
841
904
{
842
- menu . Top += topAdjustment ;
843
- menu . DrawMenu ( null , menuSelect : true ) ;
905
+ completions . CurrentMatchIndex = 0 ;
906
+ menu . DrawMenu ( null , menuSelect : true ) ;
844
907
}
845
- if ( topAdjustment > 0 )
908
+ else
846
909
{
847
- // Render did not clear the rest of the command line which flowed
848
- // into the menu, so we must do that here.
849
- menu . SaveCursor ( ) ;
850
- _console . SetCursorPosition ( endOfCommandLine . X , endOfCommandLine . Y ) ;
851
- _console . Write ( Spaces ( _console . BufferWidth - endOfCommandLine . X ) ) ;
852
- menu . RestoreCursor ( ) ;
853
- }
910
+ // After replacement, the menu might be misplaced from the command line
911
+ // getting shorter or longer.
912
+ var endOfCommandLine = ConvertOffsetToPoint ( _buffer . Length ) ;
913
+ var topAdjustment = ( endOfCommandLine . Y + 1 ) - menu . Top ;
914
+
915
+ if ( topAdjustment != 0 )
916
+ {
917
+ menu . Top += topAdjustment ;
918
+ menu . DrawMenu ( null , menuSelect : true ) ;
919
+ }
920
+ if ( topAdjustment > 0 )
921
+ {
922
+ // Render did not clear the rest of the command line which flowed
923
+ // into the menu, so we must do that here.
924
+ menu . SaveCursor ( ) ;
925
+ _console . SetCursorPosition ( endOfCommandLine . X , endOfCommandLine . Y ) ;
926
+ _console . Write ( Spaces ( _console . BufferWidth - endOfCommandLine . X ) ) ;
927
+ menu . RestoreCursor ( ) ;
928
+ }
854
929
855
- if ( previousSelection != - 1 )
856
- {
857
930
if ( menu . ToolTipLines > 0 )
858
931
{
859
932
// Erase previous tooltip, taking into account if the menu moved up/down.
860
933
WriteBlankLines ( menu . Top + menu . Rows , - topAdjustment + menu . ToolTipLines ) ;
861
934
}
862
- menu . UpdateMenuSelection ( previousSelection , /*select*/ false ,
863
- /*showToolTips*/ false , Options . _emphasisColor ) ;
935
+
936
+ menu . UpdateMenuSelection (
937
+ previousSelection ,
938
+ select : false ,
939
+ showTooltips : false ,
940
+ Options . _emphasisColor ) ;
864
941
}
865
- menu . UpdateMenuSelection ( menu . CurrentSelection , /*select*/ true ,
866
- Options . ShowToolTips , Options . _emphasisColor ) ;
942
+
943
+ menu . UpdateMenuSelection (
944
+ menu . CurrentSelection ,
945
+ select : true ,
946
+ Options . ShowToolTips ,
947
+ Options . _emphasisColor ) ;
867
948
868
949
previousSelection = menu . CurrentSelection ;
869
950
}
0 commit comments