Skip to content

Commit 197a3fd

Browse files
springcompdaxian-dbw
authored andcommitted
In VI mode, moving left or right should stick cursor on logical line (#1120)
1 parent 175d42e commit 197a3fd

File tree

5 files changed

+108
-16
lines changed

5 files changed

+108
-16
lines changed

PSReadLine/KeyBindings.vi.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ private void SetDefaultViBindings()
5858
{ Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit" ) },
5959
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
6060
{ Keys.Escape, MakeKeyHandler(ViCommandMode, "ViCommandMode") },
61-
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
62-
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
61+
{ Keys.LeftArrow, MakeKeyHandler(ViBackwardChar, "ViBackwardChar") },
62+
{ Keys.RightArrow, MakeKeyHandler(ViForwardChar, "ViForwardChar") },
6363
{ Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") },
6464
{ Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") },
6565
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
@@ -101,17 +101,17 @@ private void SetDefaultViBindings()
101101
{ Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit") },
102102
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
103103
{ Keys.Escape, MakeKeyHandler(Ding, "Ignore") },
104-
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
105-
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
106-
{ Keys.Space, MakeKeyHandler(ForwardChar, "ForwardChar") },
104+
{ Keys.LeftArrow, MakeKeyHandler(ViBackwardChar, "ViBackwardChar") },
105+
{ Keys.RightArrow, MakeKeyHandler(ViForwardChar, "ViForwardChar") },
106+
{ Keys.Space, MakeKeyHandler(ViForwardChar, "ViForwardChar") },
107107
{ Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") },
108108
{ Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") },
109109
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
110110
{ Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") },
111111
{ Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
112112
{ Keys.End, MakeKeyHandler(MoveToEndOfLine, "MoveToEndOfLine") },
113113
{ Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") },
114-
{ Keys.Backspace, MakeKeyHandler(BackwardChar, "BackwardChar") },
114+
{ Keys.Backspace, MakeKeyHandler(ViBackwardChar, "ViBackwardChar") },
115115
{ Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
116116
{ Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") },
117117
{ Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") },
@@ -131,16 +131,16 @@ private void SetDefaultViBindings()
131131
{ Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") },
132132
{ Keys.A, MakeKeyHandler(ViInsertWithAppend, "ViInsertWithAppend") },
133133
{ Keys.B, MakeKeyHandler(ViBackwardWord, "ViBackwardWord") },
134-
{ Keys.C, MakeKeyHandler(ViChord, "ChordFirstKey") },
135-
{ Keys.D, MakeKeyHandler(ViChord, "ChordFirstKey") },
134+
{ Keys.C, MakeKeyHandler(ViChord, "ChordFirstKey") },
135+
{ Keys.D, MakeKeyHandler(ViChord, "ChordFirstKey") },
136136
{ Keys.E, MakeKeyHandler(NextWordEnd, "NextWordEnd") },
137137
{ Keys.F, MakeKeyHandler(SearchChar, "SearchChar") },
138-
{ Keys.G, MakeKeyHandler(ViChord, "ChordFirstKey") },
139-
{ Keys.H, MakeKeyHandler(BackwardChar, "BackwardChar") },
138+
{ Keys.G, MakeKeyHandler(ViChord, "ChordFirstKey") },
139+
{ Keys.H, MakeKeyHandler(ViBackwardChar, "ViBackwardChar") },
140140
{ Keys.I, MakeKeyHandler(ViInsertMode, "ViInsertMode") },
141141
{ Keys.J, MakeKeyHandler(NextHistory, "NextHistory") },
142142
{ Keys.K, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
143-
{ Keys.L, MakeKeyHandler(ForwardChar, "ForwardChar") },
143+
{ Keys.L, MakeKeyHandler(ViForwardChar, "ViForwardChar") },
144144
{ Keys.M, MakeKeyHandler(Ding, "Ignore") },
145145
{ Keys.N, MakeKeyHandler(RepeatSearch, "RepeatSearch") },
146146
{ Keys.O, MakeKeyHandler(ViAppendLine, "ViAppendLine") },
@@ -153,7 +153,7 @@ private void SetDefaultViBindings()
153153
{ Keys.V, MakeKeyHandler(ViEditVisually, "ViEditVisually") },
154154
{ Keys.W, MakeKeyHandler(ViNextWord, "ViNextWord") },
155155
{ Keys.X, MakeKeyHandler(DeleteChar, "DeleteChar") },
156-
{ Keys.Y, MakeKeyHandler(ViChord, "ChordFirstKey") },
156+
{ Keys.Y, MakeKeyHandler(ViChord, "ChordFirstKey") },
157157
{ Keys.Z, MakeKeyHandler(Ding, "Ignore") },
158158
{ Keys.ucA, MakeKeyHandler(ViInsertAtEnd, "ViInsertAtEnd") },
159159
{ Keys.ucB, MakeKeyHandler(ViBackwardGlob, "ViBackwardGlob") },

PSReadLine/Movement.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,54 @@ public static void BackwardChar(ConsoleKeyInfo? key = null, object arg = null)
7676
}
7777
}
7878

79+
/// <summary>
80+
/// Moves the cursor one character to the right on a single logical line.
81+
/// </summary>
82+
private static void ViForwardChar(ConsoleKeyInfo? key = null, object arg = null)
83+
{
84+
if (TryGetArgAsInt(arg, out var numericArg, 1))
85+
{
86+
ViOffsetCursorPosition(+ numericArg);
87+
}
88+
}
89+
90+
/// <summary>
91+
/// Move the cursor one character to the left on a single logical line.
92+
/// </summary>
93+
private static void ViBackwardChar(ConsoleKeyInfo? key = null, object arg = null)
94+
{
95+
if (TryGetArgAsInt(arg, out var numericArg, 1))
96+
{
97+
ViOffsetCursorPosition(- numericArg);
98+
}
99+
}
100+
101+
/// <summary>
102+
/// Moves the cursor to the left or right a certain number of characters.
103+
/// If the count is negative, moves the cursor in the left direction.
104+
/// </summary>
105+
private static void ViOffsetCursorPosition(int count)
106+
{
107+
if (count < 0)
108+
{
109+
var start = GetBeginningOfLinePos(_singleton._current);
110+
var newCurrent = Math.Max(start, _singleton._current + count);
111+
if (_singleton._current != newCurrent)
112+
{
113+
_singleton.MoveCursor(newCurrent);
114+
}
115+
}
116+
else
117+
{
118+
var end = GetEndOfLogicalLinePos(_singleton._current);
119+
var newCurrent = Math.Min(end, _singleton._current + count);
120+
if (_singleton._current != newCurrent)
121+
{
122+
_singleton.MoveCursor(newCurrent);
123+
}
124+
}
125+
}
126+
79127
private void MoveToLine(int lineOffset)
80128
{
81129
// Behavior description:

PSReadLine/ReadLine.vi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ public static void ViCommandMode(ConsoleKeyInfo? key = null, object arg = null)
461461
}
462462
_singleton._dispatchTable = _viCmdKeyMap;
463463
_singleton._chordDispatchTable = _viCmdChordTable;
464-
BackwardChar();
464+
ViBackwardChar();
465465
_singleton.ViIndicateCommandMode();
466466
}
467467

test/BasicEditingTest.VI.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ public void Defect796()
123123
TestSetup(KeyMode.Vi);
124124

125125
Test("\"\n\n\"", Keys(
126-
_.DQuote, _.Enter, _.Escape, CheckThat(() => AssertCursorTopIs(0)),
127-
'j', CheckThat(() => AssertCursorTopIs(1)),
126+
_.DQuote, _.Enter, _.Escape, CheckThat(() => AssertCursorTopIs(1)),
128127
'o', CheckThat(() => AssertCursorTopIs(2)),
129128
_.DQuote
130129
));

test/MovementTest.VI.Multiline.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,51 @@ namespace Test
55
{
66
public partial class ReadLine
77
{
8+
[SkippableFact]
9+
public void ViBackwardChar()
10+
{
11+
TestSetup(KeyMode.Vi);
12+
13+
const string buffer = "\"\nline2\nline3\n\"";
14+
15+
var continuationPrefixLength = PSConsoleReadLineOptions.DefaultContinuationPrompt.Length;
16+
17+
Test(buffer, Keys(
18+
_.DQuote, _.Enter,
19+
"line2", _.Enter,
20+
"line3", _.Enter,
21+
_.DQuote,
22+
_.Escape,
23+
_.k, CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0)),
24+
// move left
25+
_.h, CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0)),
26+
_.l, CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 1)),
27+
"2h", CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0))
28+
));
29+
}
30+
31+
[SkippableFact]
32+
public void ViForwardChar()
33+
{
34+
TestSetup(KeyMode.Vi);
35+
36+
const string buffer = "\"\nline2\nline3\n\"";
37+
38+
var continuationPrefixLength = PSConsoleReadLineOptions.DefaultContinuationPrompt.Length;
39+
40+
Test(buffer, Keys(
41+
_.DQuote, _.Enter,
42+
"line2", _.Enter,
43+
"line3", _.Enter,
44+
_.DQuote,
45+
_.Escape,
46+
_.k, _.k, CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 0)),
47+
// move right
48+
_.l, CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 1)),
49+
"10l", CheckThat(() => AssertCursorLeftIs(continuationPrefixLength + 4))
50+
));
51+
}
52+
853
[SkippableFact]
954
public void ViMoveToFirstLogicalLineThenJumpToLastLogicalLine()
1055
{
@@ -115,4 +160,4 @@ private void ViJumpMustDing(string expectedResult, params object[] keys)
115160
TestMustDing(expectedResult, Keys(keys));
116161
}
117162
}
118-
}
163+
}

0 commit comments

Comments
 (0)