mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-12-30 12:25:48 +08:00
Use file scoped namespace declarations
This commit is contained in:
committed by
Phil Scott
parent
1dbaf50935
commit
ec1188b837
@@ -4,117 +4,116 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
namespace Spectre.Console;
|
||||
|
||||
internal sealed class ListPrompt<T>
|
||||
where T : notnull
|
||||
{
|
||||
internal sealed class ListPrompt<T>
|
||||
where T : notnull
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly IListPromptStrategy<T> _strategy;
|
||||
|
||||
public ListPrompt(IAnsiConsole console, IListPromptStrategy<T> strategy)
|
||||
{
|
||||
private readonly IAnsiConsole _console;
|
||||
private readonly IListPromptStrategy<T> _strategy;
|
||||
|
||||
public ListPrompt(IAnsiConsole console, IListPromptStrategy<T> strategy)
|
||||
{
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_strategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
|
||||
}
|
||||
|
||||
public async Task<ListPromptState<T>> Show(
|
||||
ListPromptTree<T> tree,
|
||||
CancellationToken cancellationToken,
|
||||
int requestedPageSize = 15)
|
||||
{
|
||||
if (tree is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tree));
|
||||
}
|
||||
|
||||
if (!_console.Profile.Capabilities.Interactive)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Cannot show selection prompt since the current " +
|
||||
"terminal isn't interactive.");
|
||||
}
|
||||
|
||||
if (!_console.Profile.Capabilities.Ansi)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Cannot show selection prompt since the current " +
|
||||
"terminal does not support ANSI escape sequences.");
|
||||
}
|
||||
|
||||
var nodes = tree.Traverse().ToList();
|
||||
var state = new ListPromptState<T>(nodes, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize));
|
||||
var hook = new ListPromptRenderHook<T>(_console, () => BuildRenderable(state));
|
||||
|
||||
using (new RenderHookScope(_console, hook))
|
||||
{
|
||||
_console.Cursor.Hide();
|
||||
hook.Refresh();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var rawKey = await _console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false);
|
||||
if (rawKey == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = rawKey.Value;
|
||||
var result = _strategy.HandleInput(key, state);
|
||||
if (result == ListPromptInputResult.Submit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (state.Update(key.Key) || result == ListPromptInputResult.Refresh)
|
||||
{
|
||||
hook.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hook.Clear();
|
||||
_console.Cursor.Show();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private IRenderable BuildRenderable(ListPromptState<T> state)
|
||||
{
|
||||
var pageSize = state.PageSize;
|
||||
var middleOfList = pageSize / 2;
|
||||
|
||||
var skip = 0;
|
||||
var take = state.ItemCount;
|
||||
var cursorIndex = state.Index;
|
||||
|
||||
var scrollable = state.ItemCount > pageSize;
|
||||
if (scrollable)
|
||||
{
|
||||
skip = Math.Max(0, state.Index - middleOfList);
|
||||
take = Math.Min(pageSize, state.ItemCount - skip);
|
||||
|
||||
if (state.ItemCount - state.Index < middleOfList)
|
||||
{
|
||||
// Pointer should be below the end of the list
|
||||
var diff = middleOfList - (state.ItemCount - state.Index);
|
||||
skip -= diff;
|
||||
take += diff;
|
||||
cursorIndex = middleOfList + diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take skip into account
|
||||
cursorIndex -= skip;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the renderable
|
||||
return _strategy.Render(
|
||||
_console,
|
||||
scrollable, cursorIndex,
|
||||
state.Items.Skip(skip).Take(take)
|
||||
.Select((node, index) => (index, node)));
|
||||
}
|
||||
_console = console ?? throw new ArgumentNullException(nameof(console));
|
||||
_strategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ListPromptState<T>> Show(
|
||||
ListPromptTree<T> tree,
|
||||
CancellationToken cancellationToken,
|
||||
int requestedPageSize = 15)
|
||||
{
|
||||
if (tree is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tree));
|
||||
}
|
||||
|
||||
if (!_console.Profile.Capabilities.Interactive)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Cannot show selection prompt since the current " +
|
||||
"terminal isn't interactive.");
|
||||
}
|
||||
|
||||
if (!_console.Profile.Capabilities.Ansi)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"Cannot show selection prompt since the current " +
|
||||
"terminal does not support ANSI escape sequences.");
|
||||
}
|
||||
|
||||
var nodes = tree.Traverse().ToList();
|
||||
var state = new ListPromptState<T>(nodes, _strategy.CalculatePageSize(_console, nodes.Count, requestedPageSize));
|
||||
var hook = new ListPromptRenderHook<T>(_console, () => BuildRenderable(state));
|
||||
|
||||
using (new RenderHookScope(_console, hook))
|
||||
{
|
||||
_console.Cursor.Hide();
|
||||
hook.Refresh();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var rawKey = await _console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false);
|
||||
if (rawKey == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = rawKey.Value;
|
||||
var result = _strategy.HandleInput(key, state);
|
||||
if (result == ListPromptInputResult.Submit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (state.Update(key.Key) || result == ListPromptInputResult.Refresh)
|
||||
{
|
||||
hook.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hook.Clear();
|
||||
_console.Cursor.Show();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private IRenderable BuildRenderable(ListPromptState<T> state)
|
||||
{
|
||||
var pageSize = state.PageSize;
|
||||
var middleOfList = pageSize / 2;
|
||||
|
||||
var skip = 0;
|
||||
var take = state.ItemCount;
|
||||
var cursorIndex = state.Index;
|
||||
|
||||
var scrollable = state.ItemCount > pageSize;
|
||||
if (scrollable)
|
||||
{
|
||||
skip = Math.Max(0, state.Index - middleOfList);
|
||||
take = Math.Min(pageSize, state.ItemCount - skip);
|
||||
|
||||
if (state.ItemCount - state.Index < middleOfList)
|
||||
{
|
||||
// Pointer should be below the end of the list
|
||||
var diff = middleOfList - (state.ItemCount - state.Index);
|
||||
skip -= diff;
|
||||
take += diff;
|
||||
cursorIndex = middleOfList + diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take skip into account
|
||||
cursorIndex -= skip;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the renderable
|
||||
return _strategy.Render(
|
||||
_console,
|
||||
scrollable, cursorIndex,
|
||||
state.Items.Skip(skip).Take(take)
|
||||
.Select((node, index) => (index, node)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user