Skip to content

Commit bac4884

Browse files
committed
terminal: add a simple TTY-based menu system
Add a simple menu system that works over the TTY. This is useful for presenting a selection of authentication options to the user when no UI is available.
1 parent 0b0752d commit bac4884

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
using System;
4+
using System.Collections;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
9+
namespace Microsoft.Git.CredentialManager
10+
{
11+
public class TerminalMenu : IEnumerable<TerminalMenuItem>
12+
{
13+
private readonly ITerminal _terminal;
14+
private readonly IList<TerminalMenuItem> _items = new List<TerminalMenuItem>();
15+
16+
public TerminalMenu(ITerminal terminal, string title = null)
17+
{
18+
_terminal = terminal;
19+
Title = title;
20+
}
21+
22+
public string Title { get; }
23+
24+
public void Add(TerminalMenuItem item)
25+
{
26+
if (item.IsDefault && _items.Any(x => x.IsDefault))
27+
{
28+
throw new ArgumentException("A default menu item has already been added.");
29+
}
30+
31+
_items.Add(item);
32+
}
33+
34+
public int Show()
35+
{
36+
TerminalMenuItem defaultItem = _items.FirstOrDefault(x => x.IsDefault);
37+
bool hasDefault = !(defaultItem is null);
38+
39+
string title = $"{Title ?? "Select an option"}:";
40+
41+
string promptDefaultTag = hasDefault ? " (enter for default)" : string.Empty;
42+
string prompt = $"option{promptDefaultTag}";
43+
44+
while (true)
45+
{
46+
_terminal.WriteLine(title);
47+
48+
foreach (TerminalMenuItem item in _items)
49+
{
50+
string itemDefaultTag = item.IsDefault ? " (default)" : string.Empty;
51+
_terminal.WriteLine($" {item.Id}. {item.Name}{itemDefaultTag}");
52+
}
53+
54+
string optionStr = _terminal.Prompt(prompt);
55+
56+
if (string.IsNullOrWhiteSpace(optionStr))
57+
{
58+
if (hasDefault)
59+
{
60+
return defaultItem.Id;
61+
}
62+
63+
_terminal.WriteLine("No default option is configured.\n");
64+
continue;
65+
}
66+
67+
if (!int.TryParse(optionStr, out int option))
68+
{
69+
_terminal.WriteLine($"Invalid option '{optionStr}'. Expected a number.\n");
70+
continue;
71+
}
72+
73+
if (_items.All(x => x.Id != option))
74+
{
75+
_terminal.WriteLine($"Invalid option '{optionStr}'.\n");
76+
continue;
77+
}
78+
79+
return option;
80+
}
81+
}
82+
83+
public IEnumerator<TerminalMenuItem> GetEnumerator()
84+
{
85+
return _items.GetEnumerator();
86+
}
87+
88+
IEnumerator IEnumerable.GetEnumerator()
89+
{
90+
return ((IEnumerable) _items).GetEnumerator();
91+
}
92+
}
93+
94+
public class TerminalMenuItem
95+
{
96+
public TerminalMenuItem(int id, string name, bool isDefault = false)
97+
{
98+
Id = id;
99+
Name = name;
100+
IsDefault = isDefault;
101+
}
102+
103+
public int Id { get; }
104+
105+
public string Name { get; }
106+
107+
public bool IsDefault { get; }
108+
}
109+
}

0 commit comments

Comments
 (0)