예제 #1
0
    /// <inheritdoc/>
    ListPromptInputResult IListPromptStrategy <T> .HandleInput(ConsoleKeyInfo key, ListPromptState <T> state)
    {
        if (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Spacebar)
        {
            // Selecting a non leaf in "leaf mode" is not allowed
            if (state.Current.IsGroup && Mode == SelectionMode.Leaf)
            {
                return(ListPromptInputResult.None);
            }

            return(ListPromptInputResult.Submit);
        }

        return(ListPromptInputResult.None);
    }
    /// <inheritdoc/>
    ListPromptInputResult IListPromptStrategy <T> .HandleInput(ConsoleKeyInfo key, ListPromptState <T> state)
    {
        if (key.Key == ConsoleKey.Enter)
        {
            if (Required && state.Items.None(x => x.IsSelected))
            {
                // Selection not permitted
                return(ListPromptInputResult.None);
            }

            // Submit
            return(ListPromptInputResult.Submit);
        }

        if (key.Key == ConsoleKey.Spacebar)
        {
            var current = state.Items[state.Index];
            var select  = !current.IsSelected;

            if (Mode == SelectionMode.Leaf)
            {
                // Select the node and all its children
                foreach (var item in current.Traverse(includeSelf: true))
                {
                    item.IsSelected = select;
                }

                // Visit every parent and evaluate if its selection
                // status need to be updated
                var parent = current.Parent;
                while (parent != null)
                {
                    parent.IsSelected = parent.Traverse(includeSelf: false).All(x => x.IsSelected);
                    parent            = parent.Parent;
                }
            }
            else
            {
                current.IsSelected = !current.IsSelected;
            }

            // Refresh the list
            return(ListPromptInputResult.Refresh);
        }

        return(ListPromptInputResult.None);
    }
예제 #3
0
    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))));
    }
예제 #4
0
    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);
    }