mirror of
https://github.com/spectreconsole/spectre.console.git
synced 2025-10-25 15:19:23 +00:00
Support J and K for navigating list prompts (#1877)
This commit is contained in:
@@ -63,6 +63,7 @@ internal sealed class ListPromptState<T>
|
||||
switch (keyInfo.Key)
|
||||
{
|
||||
case ConsoleKey.UpArrow:
|
||||
case ConsoleKey.K:
|
||||
if (currentLeafIndex > 0)
|
||||
{
|
||||
index = _leafIndexes[currentLeafIndex - 1];
|
||||
@@ -75,6 +76,7 @@ internal sealed class ListPromptState<T>
|
||||
break;
|
||||
|
||||
case ConsoleKey.DownArrow:
|
||||
case ConsoleKey.J:
|
||||
if (currentLeafIndex < _leafIndexes.Count - 1)
|
||||
{
|
||||
index = _leafIndexes[currentLeafIndex + 1];
|
||||
@@ -117,8 +119,8 @@ internal sealed class ListPromptState<T>
|
||||
{
|
||||
index = keyInfo.Key switch
|
||||
{
|
||||
ConsoleKey.UpArrow => Index - 1,
|
||||
ConsoleKey.DownArrow => Index + 1,
|
||||
ConsoleKey.UpArrow or ConsoleKey.K => Index - 1,
|
||||
ConsoleKey.DownArrow or ConsoleKey.J => Index + 1,
|
||||
ConsoleKey.Home => 0,
|
||||
ConsoleKey.End => ItemCount - 1,
|
||||
ConsoleKey.PageUp => Index - PageSize,
|
||||
|
||||
@@ -77,4 +77,35 @@ public sealed class InteractiveCommandTests
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Output.EndsWith("[Apple;Apricot;Spectre Console]");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InteractiveCommand_WithMockedUserInputs_VimMotions_ProducesExpectedOutput()
|
||||
{
|
||||
// Given
|
||||
TestConsole console = new();
|
||||
console.Interactive();
|
||||
|
||||
// Your mocked inputs must always end with "Enter" for each prompt!
|
||||
|
||||
// Multi selection prompt: Choose first option
|
||||
console.Input.PushKey(ConsoleKey.Spacebar);
|
||||
console.Input.PushKey(ConsoleKey.Enter);
|
||||
|
||||
// Selection prompt: Choose second option
|
||||
console.Input.PushKey(ConsoleKey.J);
|
||||
console.Input.PushKey(ConsoleKey.Enter);
|
||||
|
||||
// Ask text prompt: Enter name
|
||||
console.Input.PushTextWithEnter("Spectre Console");
|
||||
|
||||
var app = new CommandAppTester(null, new CommandAppTesterSettings(), console);
|
||||
app.SetDefaultCommand<InteractiveCommand>();
|
||||
|
||||
// When
|
||||
var result = app.Run();
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Output.EndsWith("[Apple;Apricot;Spectre Console]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,35 @@ public sealed class ListPromptStateTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void Should_Increase_Index(bool wrap)
|
||||
[InlineData(ConsoleKey.UpArrow)]
|
||||
[InlineData(ConsoleKey.K)]
|
||||
public void Should_Decrease_Index(ConsoleKey key)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(100, 10, false, false);
|
||||
state.Update(ConsoleKey.End.ToConsoleKeyInfo());
|
||||
var index = state.Index;
|
||||
|
||||
// When
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// Then
|
||||
state.Index.ShouldBe(index - 1);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(ConsoleKey.DownArrow, true)]
|
||||
[InlineData(ConsoleKey.DownArrow, false)]
|
||||
[InlineData(ConsoleKey.J, true)]
|
||||
[InlineData(ConsoleKey.J, false)]
|
||||
public void Should_Increase_Index(ConsoleKey key, bool wrap)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(100, 10, wrap, false);
|
||||
var index = state.Index;
|
||||
|
||||
// When
|
||||
state.Update(ConsoleKey.DownArrow.ToConsoleKeyInfo());
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// Then
|
||||
state.Index.ShouldBe(index + 1);
|
||||
@@ -52,42 +71,48 @@ public sealed class ListPromptStateTests
|
||||
state.Index.ShouldBe(99);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Clamp_Index_If_No_Wrap()
|
||||
[Theory]
|
||||
[InlineData(ConsoleKey.DownArrow)]
|
||||
[InlineData(ConsoleKey.J)]
|
||||
public void Should_Clamp_Index_If_No_Wrap(ConsoleKey key)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(100, 10, false, false);
|
||||
state.Update(ConsoleKey.End.ToConsoleKeyInfo());
|
||||
|
||||
// When
|
||||
state.Update(ConsoleKey.DownArrow.ToConsoleKeyInfo());
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// Then
|
||||
state.Index.ShouldBe(99);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Wrap_Index_If_Wrap()
|
||||
[Theory]
|
||||
[InlineData(ConsoleKey.DownArrow)]
|
||||
[InlineData(ConsoleKey.J)]
|
||||
public void Should_Wrap_Index_If_Wrap(ConsoleKey key)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(100, 10, true, false);
|
||||
state.Update(ConsoleKey.End.ToConsoleKeyInfo());
|
||||
|
||||
// When
|
||||
state.Update(ConsoleKey.DownArrow.ToConsoleKeyInfo());
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// Then
|
||||
state.Index.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Wrap_Index_If_Wrap_And_Down()
|
||||
[Theory]
|
||||
[InlineData(ConsoleKey.UpArrow)]
|
||||
[InlineData(ConsoleKey.K)]
|
||||
public void Should_Wrap_Index_If_Wrap_And_Down(ConsoleKey key)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(100, 10, true, false);
|
||||
|
||||
// When
|
||||
state.Update(ConsoleKey.UpArrow.ToConsoleKeyInfo());
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// Then
|
||||
state.Index.ShouldBe(99);
|
||||
@@ -106,13 +131,15 @@ public sealed class ListPromptStateTests
|
||||
state.Index.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Wrap_Index_If_Wrap_And_Offset_And_Page_Down()
|
||||
[Theory]
|
||||
[InlineData(ConsoleKey.UpArrow)]
|
||||
[InlineData(ConsoleKey.K)]
|
||||
public void Should_Wrap_Index_If_Wrap_And_Offset_And_Page_Down(ConsoleKey key)
|
||||
{
|
||||
// Given
|
||||
var state = CreateListPromptState(10, 100, true, false);
|
||||
state.Update(ConsoleKey.End.ToConsoleKeyInfo());
|
||||
state.Update(ConsoleKey.UpArrow.ToConsoleKeyInfo());
|
||||
state.Update(key.ToConsoleKeyInfo());
|
||||
|
||||
// When
|
||||
state.Update(ConsoleKey.PageDown.ToConsoleKeyInfo());
|
||||
|
||||
Reference in New Issue
Block a user