@@ -56,5 +56,69 @@ public void MoveToLastLine(ConsoleKeyInfo? key = null, object arg = null)
5656
5757 _singleton . MoveCursor ( position ) ;
5858 }
59+
60+ private void ViMoveToLine ( int lineOffset )
61+ {
62+ // When moving up or down in a buffer in VI mode
63+ // the cursor wants to be positioned at a desired column number, which is:
64+ // - either a specified column number, the 0-based offset from the start of the logical line.
65+ // - or the end of the line
66+ //
67+ // Only one of those desired position is available at any given time.
68+ //
69+ // If the desired column number is specified, the cursor will be positioned at
70+ // the specified offset in the target logical line, or at the end of the line as appropriate.
71+ // The fact that a logical line is shorter than the desired column number *does not*
72+ // change its value. If a subsequent move to another logical line is performed, the
73+ // desired column number will take effect.
74+ //
75+ // If the desired column number is the end of the line, the cursor will be positioned at
76+ // the end of the target logical line.
77+
78+ const int endOfLine = int . MaxValue ;
79+
80+ _moveToLineCommandCount += 1 ;
81+
82+ // if this is the first "move to line" command
83+ // record the desired column number from the current position
84+ // on the logical line
85+
86+ if ( _moveToLineCommandCount == 1 && _moveToLineDesiredColumn == - 1 )
87+ {
88+ var startOfLine = GetBeginningOfLinePos ( _current ) ;
89+ _moveToLineDesiredColumn = _current - startOfLine ;
90+ }
91+
92+ // Nothing needs to be done when:
93+ // - actually not moving the line, or
94+ // - moving the line down when it's at the end of the last logical line.
95+ if ( lineOffset == 0 || ( lineOffset > 0 && _current == _buffer . Length ) )
96+ {
97+ return ;
98+ }
99+
100+ int targetLineOffset ;
101+
102+ var currentLineIndex = _singleton . GetLogicalLineNumber ( ) - 1 ;
103+
104+ if ( lineOffset < 0 )
105+ {
106+ targetLineOffset = Math . Max ( 0 , currentLineIndex + lineOffset ) ;
107+ }
108+ else
109+ {
110+ var lastLineIndex = _singleton . GetLogicalLineCount ( ) - 1 ;
111+ targetLineOffset = Math . Min ( lastLineIndex , currentLineIndex + lineOffset ) ;
112+ }
113+
114+ var startOfTargetLinePos = GetBeginningOfNthLinePos ( targetLineOffset ) ;
115+ var endOfTargetLinePos = GetEndOfLogicalLinePos ( startOfTargetLinePos ) ;
116+
117+ var newCurrent = _moveToLineDesiredColumn == endOfLine
118+ ? endOfTargetLinePos
119+ : Math . Min ( startOfTargetLinePos + _moveToLineDesiredColumn , endOfTargetLinePos ) ;
120+
121+ MoveCursor ( newCurrent ) ;
122+ }
59123 }
60124}
0 commit comments