Skip to content

Commit 277b071

Browse files
committed
Fix that ViFindBrace doesn't search for brace when current char is not a brace
1 parent e266ca6 commit 277b071

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

PSReadLine/Movement.vi.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,28 @@ private int ViFindBrace(int i)
254254
case ')':
255255
return ViFindBackward(i, '(', withoutPassing: ')');
256256
default:
257-
return i;
257+
ReadOnlySpan<char> parenthese = stackalloc char[] { '{', '}', '(', ')', '[', ']' };
258+
int nextParen = i;
259+
// find next of any kind of paren
260+
for (; nextParen < _buffer.Length; nextParen++)
261+
for (int idx = 0; idx < parenthese.Length; idx++)
262+
if (parenthese[idx] == _buffer[nextParen]) goto Outer;
263+
264+
Outer:
265+
int match = _buffer[nextParen] switch
266+
{
267+
// if next is opening, find forward
268+
'{' => ViFindForward(nextParen, '}', withoutPassing: '{'),
269+
'[' => ViFindForward(nextParen, ']', withoutPassing: '['),
270+
'(' => ViFindForward(nextParen, ')', withoutPassing: '('),
271+
// if next is closing, find backward
272+
'}' => ViFindBackward(nextParen, '{', withoutPassing: '}'),
273+
']' => ViFindBackward(nextParen, '[', withoutPassing: ']'),
274+
')' => ViFindBackward(nextParen, '(', withoutPassing: ')'),
275+
_ => nextParen
276+
};
277+
278+
return match == nextParen ? i : match;
258279
}
259280
}
260281

test/MovementTest.VI.cs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Xunit;
1+
using System.Collections.Generic;
2+
using Xunit;
23

34
namespace Test
45
{
@@ -370,7 +371,7 @@ public void ViGlobMovement_EmptyBuffer_Defect1195()
370371
TestSetup(KeyMode.Vi);
371372

372373
TestMustDing("", Keys(
373-
_.Escape, "W"
374+
_.Escape, "W"
374375
));
375376
}
376377

@@ -454,6 +455,53 @@ public void ViGotoBrace()
454455
));
455456
}
456457

458+
// tests when cursor not on any paren
459+
foreach (var (opening, closing) in new[] { ('(', ')'), ('{', '}'), ('[', ']') })
460+
{
461+
// closing paren with backward match
462+
string input1 = $"0{opening}2{opening}4foo{closing}";
463+
Test(input1, Keys(
464+
input1,
465+
CheckThat(() => AssertCursorLeftIs(9)),
466+
_.Escape, CheckThat(() => AssertCursorLeftIs(8)),
467+
"0ff", CheckThat(() => AssertCursorLeftIs(5)),
468+
_.Percent, CheckThat(() => AssertCursorLeftIs(3)),
469+
_.Percent, CheckThat(() => AssertCursorLeftIs(8))
470+
));
471+
472+
// closing paren without backward match
473+
string input2 = $"0]2)4foo{closing}";
474+
Test(input2, Keys(
475+
input2,
476+
CheckThat(() => AssertCursorLeftIs(9)),
477+
_.Escape, CheckThat(() => AssertCursorLeftIs(8)),
478+
"0ff", CheckThat(() => AssertCursorLeftIs(5)),
479+
_.Percent, CheckThat(() => AssertCursorLeftIs(5)), // stay still
480+
_.Percent, CheckThat(() => AssertCursorLeftIs(5))
481+
));
482+
483+
// opening paren with forward match
484+
string input3 = $"0{opening}2foo6{closing}";
485+
Test(input3, Keys(
486+
input3,
487+
CheckThat(() => AssertCursorLeftIs(8)),
488+
_.Escape, CheckThat(() => AssertCursorLeftIs(7)),
489+
"0ff", CheckThat(() => AssertCursorLeftIs(3)),
490+
_.Percent, CheckThat(() => AssertCursorLeftIs(1)),
491+
_.Percent, CheckThat(() => AssertCursorLeftIs(7))
492+
));
493+
// opening paren without forward match
494+
string input4 = $"0)2]4foo{opening}(";
495+
Test(input4, Keys(
496+
input4,
497+
CheckThat(() => AssertCursorLeftIs(10)),
498+
_.Escape, CheckThat(() => AssertCursorLeftIs(9)),
499+
"0ff", CheckThat(() => AssertCursorLeftIs(5)),
500+
_.Percent, CheckThat(() => AssertCursorLeftIs(5)), // stay still
501+
_.Percent, CheckThat(() => AssertCursorLeftIs(5))
502+
));
503+
}
504+
457505
// <%> with empty text buffer should work fine.
458506
Test("", Keys(
459507
_.Escape, _.Percent,

0 commit comments

Comments
 (0)