Skip to content

Commit 011b028

Browse files
committed
Version 1.0.2.1
1 parent 38aa5a7 commit 011b028

File tree

70 files changed

+552
-946
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+552
-946
lines changed

Docs/ReadLine.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# ReadLine
2+
PowerCommands is using an extended version of [ReadLine](https://github.com/tonerdo/readline) published on Github by [Toni Solarin-Sodara](https://github.com/tonerdo).
3+
The code is duplicated and then altered to implement more functionality like command highlighting and some events that is described here.
4+
5+
## Description
6+
The core functionality is the same, but some code is added to suit the need for PowerCommands, the license model is still the same.
7+
8+
## Events
9+
Events related to keyboard input is exposed as static event by the ```ReadLineService``` this events is possible to add listeners to.
10+
11+
### OpenShortCutPressed
12+
Occurs when user press [`Ctrl + O`].
13+
```
14+
public DemoCommand(string identifier, PowerCommandsConfiguration configuration) : base(identifier, configuration) => ReadLineService.OpenShortCutPressed += OpenShortCutPressed;
15+
private void OpenShortCutPressed() => WriteSuccessLine("You pressed [CTRL]+[O]");
16+
```
17+
### SaveShortCutPressed
18+
Occurs when user press [`Ctrl + S`].
19+
20+
### **CmdLineTextChanged**
21+
Listen to every key input, you will get the current input not just the pressed key.
22+
23+
**Example**
24+
This is a real world example, with this command the user is guided for every input the user is doing a toolbar will help the user what to input in the next step.
25+
I have removed the Run() implementation code to make the example smaller, but you can se how the event is used.
26+
```
27+
public class AddCommand : DisplayCommandsBase
28+
{
29+
public AddCommand(string identifier, PowerCommandsConfiguration configuration) : base(identifier, configuration) => ReadLineService.CmdLineTextChanged += ReadLineService_CmdLineTextChanged;
30+
private void ReadLineService_CmdLineTextChanged(object? sender, ReadLine.Events.CmdLineTextChangedArgs e)
31+
{
32+
if(!e.CmdText.StartsWith("add")) return;
33+
var args = e.CmdText.Split(' ');
34+
var labels = new []{"Press [Space]"};
35+
switch (args.Length)
36+
{
37+
case 2:
38+
labels = new[] { "<type> (press [tab])","(url,onenote,path,file)"};
39+
break;
40+
case 3:
41+
labels = new[] { args[1],"\"<value>\""};
42+
break;
43+
case 4:
44+
labels = new []{"[Option] (press - then [tab])","--name"};
45+
break;
46+
case 5:
47+
labels = new []{"[Option]","--name","\"<value>\""};
48+
break;
49+
case 6:
50+
labels = new []{"[Option] (press - then [tab])","--tags"};
51+
break;
52+
case 7:
53+
labels = new []{"[Option]","--tags","<comma separated values>"};
54+
break;
55+
}
56+
ToolbarService.DrawToolbar(labels);
57+
}
58+
}
59+
```
60+
61+
### **CommandHighlighted**
62+
Works just like the **CmdLineTextChanged** event but triggers when a valid command has been typed by the user.
63+
64+
## ReadLine Shortcut Guide
65+
66+
| Shortcut | Comment |
67+
| ------------------------------ | --------------------------------- |
68+
| `Ctrl`+`A` / `HOME` | Beginning of line |
69+
| `Ctrl`+`B` / `` | Backward one character |
70+
| `Ctrl`+`C` | Send EOF |
71+
| `Ctrl`+`E` / `END` | End of line |
72+
| `Ctrl`+`F` / `` | Forward one character |
73+
| `Ctrl`+`H` / `Backspace` | Delete previous character |
74+
| `Tab` | Command line completion |
75+
| `Shift`+`Tab` | Backwards command line completion |
76+
| `Ctrl`+`J` / `Enter` | Line feed |
77+
| `Ctrl`+`K` | Cut text to the end of line |
78+
| `Ctrl`+`L` / `Esc` | Clear line |
79+
| `Ctrl`+`M` | Same as Enter key |
80+
| `Ctrl`+`N` / `` | Forward in history |
81+
| `Ctrl`+`P` / `` | Backward in history |
82+
| `Ctrl`+`U` | Cut text to the start of line |
83+
| `Ctrl`+`W` | Cut previous word |
84+
| `Backspace` | Delete previous character |
85+
| `Ctrl` + `D` / `Delete` | Delete succeeding character |
86+
| `Ctrl` + `` | Move cursor down one line |
87+
| `Ctrl` + `` | Move cursor up one line |
88+
89+
90+
Read more about:
91+
92+
[Dialog services](DialogService.md)
93+
94+
[Design your Command](Design_command.md)
95+
96+
[Customize](Customize.md)
97+
98+
[Back to start](https://github.com/PowerCommands/PowerCommands2022/blob/main/Docs/README.md)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ https://github.com/PowerCommands/PowerCommands2022/assets/102176789/10945ee0-947
6060

6161
[Documentation index](Docs/DocumentationIndexDB.md)
6262

63+
## Console Input
64+
[Shortcut guide and listening on keyboard events](Docs/ReadLine.md)
65+
6366
## Architecture
6467
[Design principles and guidlines](Docs/PowerCommands%20Design%20Principles%20And%20Guidlines.md)
6568

Templates/PowerCommands.zip

-24.7 KB
Binary file not shown.

Templates/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ I recommend you to use the option ```Place solution in the same directory``` som
1414

1515

1616
# What is new?
17+
## Version 1.0.2.1
18+
**Released 2023-07-24**
19+
- ```DialogService.ListDialog``` now returns a ```Dictionary<int, string>``` instead of ```List<string>``` so string value and index is returned for each selected item.
20+
- ```ChecksumManager``` now exposing it´t functions for calculating MDF checksum.
21+
- ```DialogService``` standard dialogs has some minor improvements.
22+
- ```PowerCommandsManager.RunCustomCode``` now has a parameter ```RunFlowManager runFlow```.
23+
1724
## Version 1.0.2.0
1825
**Released 2023-07-01**
1926
- Toolbar functionality moved to own ```ToolbarService``` and reworked it completely, not using timers anymore that caused problems, so it is now a more stable feature (but still a bit experimental).

Templates/src/Core/PainKiller.PowerCommands.Configuration/ENUMS/HideToollbarOption.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

Templates/src/Core/PainKiller.PowerCommands.Core/MANAGERS/TemplateManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void CreateCommand(string templateName, string commandName)
3131
_logger.Invoke($"Template not found, run following command to download current templates\npowercommand update --template");
3232
return;
3333
}
34-
var content = File.ReadAllText(filePath).Replace("namespace PainKiller.PowerCommands.MyExampleCommands.Commands.Templates;", $"namespace PainKiller.PowerCommands.{FindProjectName()}Commands.Commands;").Replace("NameCommand", $"{commandName}Command");
34+
var content = File.ReadAllText(filePath).Replace("namespace PainKiller.PowerCommands.MyExampleCommands.Commands.Templates;", $"namespace {FindProjectName()}Commands.Commands;").Replace("NameCommand", $"{commandName}Command").Replace("\"demo\"",$"\"{commandName.ToLower()}\"");
3535
var commandsFolder = FindCommandsProjectDirectory();
3636
var copyFilePath = $"{commandsFolder}\\Commands\\{commandName}Command.cs";
3737

Templates/src/Core/PainKiller.PowerCommands.Core/PainKiller.PowerCommands.Core.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
55
<LangVersion>10.0</LangVersion>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
8-
<Version>1.0.2.0</Version>
8+
<Version>1.0.2.1</Version>
99
</PropertyGroup>
1010

1111
<ItemGroup>

Templates/src/Core/PainKiller.PowerCommands.Core/SERVICES/DialogService.cs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ public static class DialogService
66
{
77
public static bool YesNoDialog(string question, string yesValue = "y", string noValue = "n")
88
{
9-
Console.Write($"\n{question} ({yesValue}/{noValue}): ");
9+
WriteHeader($"\n{question}"); ;
10+
Console.WriteLine($"({yesValue}/{noValue}):");
11+
1012
var response = Console.ReadLine();
1113
return $"{response}".Trim().ToLower() == yesValue.ToLower();
1214
}
1315
public static string QuestionAnswerDialog(string question)
1416
{
15-
Console.WriteLine($"\n{question}");
17+
WriteHeader($"{question}\n");
1618
Console.Write(ConfigurationGlobals.Prompt);
1719
var response = Console.ReadLine();
1820
return $"{response}".Trim();
@@ -23,10 +25,10 @@ public static string SecretPromptDialog(string question, int maxRetries = 3)
2325
var secret = "";
2426
while (retryCount < maxRetries)
2527
{
26-
Console.Write($"\n{question} :");
28+
WriteHeader($"\n{question} :");
2729
secret = PasswordPromptService.Service.ReadPassword();
2830
Console.WriteLine();
29-
Console.Write("Confirm: ".PadLeft(question.Length));
31+
Console.Write("Confirm: ".PadLeft(question.Length + 1));
3032
var confirm = PasswordPromptService.Service.ReadPassword();
3133
if (secret != confirm)
3234
{
@@ -38,49 +40,68 @@ public static string SecretPromptDialog(string question, int maxRetries = 3)
3840

3941
return $"{secret}".Trim();
4042
}
41-
public static List<string> ListDialog(string header, List<string> items, ConsoleColor foregroundColor = ConsoleColor.White, ConsoleColor backgroundColor = ConsoleColor.Blue)
43+
public static Dictionary<int, string> ListDialog(string header, List<string> items, bool multiSelect = false, bool autoSelectIfOnlyOneItem = true, ConsoleColor foregroundColor = ConsoleColor.White, ConsoleColor backgroundColor = ConsoleColor.Blue)
4244
{
45+
if (items.Count == 0) return new Dictionary<int, string>();
4346
Console.Clear();
44-
ConsoleService.Service.WriteHeaderLine(nameof(DialogService), header);
47+
WriteHeader($"{header}\n");
4548
var startRow = Console.CursorTop;
4649
var startForegroundColor = Console.ForegroundColor;
4750
var startBackgroundColor = Console.BackgroundColor;
4851

4952
for (int index=0; index<items.Count;index++)
5053
{
5154
var item = items[index];
52-
Console.WriteLine($" {index+1}. {item}");
55+
Console.WriteLine($"{index+1}. {item}");
5356
}
5457
var quit = " ";
5558
var input = "";
5659
var selectedItems = new Dictionary<int, string>();
57-
58-
ToolbarService.DrawToolbar(new []{"Select number, hit enter","When your done just hit enter."});
59-
while (input != quit)
60+
61+
if (items.Count == 1 && autoSelectIfOnlyOneItem)
6062
{
63+
selectedItems.Add(0, items.First());
6164
Console.WriteLine("");
6265
Console.Write(" ");
66+
ConsoleService.Service.WriteRowWithColor(1, foregroundColor, backgroundColor, $" 1. {items.First()}");
67+
return selectedItems;
68+
}
69+
70+
var label = multiSelect ? "Enter number(s) and hit enter" : "Enter a number and hit enter";
71+
while (input != quit)
72+
{
73+
Console.WriteLine("");
74+
Console.Write($"{label}>");
6375
input = ReadLineService.Service.Read();
6476
if(input.Trim() == "") break;
6577

6678
var selectedIndex = (int.TryParse(input, out var index) ? index : 1);
67-
if(selectedIndex > items.Count-1) selectedIndex = items.Count;
79+
if(selectedIndex > items.Count) selectedIndex = items.Count;
6880
var selectedItem = new { Index = selectedIndex, Value = items[selectedIndex - 1] };
69-
var itemAdded = selectedItems.TryAdd(selectedItem.Index, selectedItem.Value);
81+
var itemAdded = selectedItems.TryAdd(selectedItem.Index-1, selectedItem.Value);
7082

7183
ConsoleService.Service.ClearRow(Console.CursorTop-1);
7284
var top = Console.CursorTop - 2;
7385
Console.CursorTop = Math.Clamp(top, 0, Console.LargestWindowHeight - 1);
7486
Console.CursorLeft = 0;
7587

76-
if(itemAdded) ConsoleService.Service.WriteRowWithColor(startRow + selectedIndex - 1, foregroundColor, backgroundColor, $" {selectedIndex}. {selectedItem.Value}");
88+
if(itemAdded) ConsoleService.Service.WriteRowWithColor(startRow + selectedIndex - 1, foregroundColor, backgroundColor, $"{selectedIndex}. {selectedItem.Value}");
7789
else
7890
{
7991
selectedItems.Remove(selectedItem.Index);
80-
ConsoleService.Service.WriteRowWithColor(startRow + selectedIndex - 1, startForegroundColor, startBackgroundColor, $" {selectedIndex}. {selectedItem.Value}");
92+
ConsoleService.Service.WriteRowWithColor(startRow + selectedIndex - 1, startForegroundColor, startBackgroundColor, $"{selectedIndex}. {selectedItem.Value}");
8193
}
94+
95+
if (!multiSelect) break;
8296
}
8397
ToolbarService.ClearToolbar();
84-
return selectedItems.Select(s => s.Value).ToList();
98+
return selectedItems;
99+
}
100+
private static void WriteHeader(string text)
101+
{
102+
var originalColor = Console.ForegroundColor;
103+
Console.ForegroundColor = ConsoleColor.Cyan;
104+
Console.Write(text);
105+
Console.ForegroundColor = originalColor;
85106
}
86107
}

Templates/src/Core/PainKiller.PowerCommands.Core/SERVICES/ToolbarService.cs

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,69 @@
11
using PainKiller.PowerCommands.Configuration.Enums;
22
using System.Drawing;
3+
using Microsoft.Extensions.Logging;
34
using PainKiller.PowerCommands.ReadLine;
45

56
namespace $safeprojectname$.Services;
67

78
public static class ToolbarService
89
{
9-
private static string[]? Labels = null;
10+
private static string[]? _labels = null;
1011
public static void DrawToolbar(string[] labels, ConsoleColor[]? consoleColors = null)
1112
{
12-
if(Labels != null) ClearToolbar();
13-
Labels = labels;
14-
var colors = consoleColors ?? new[] { ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray,ConsoleColor.Red,ConsoleColor.DarkBlue,ConsoleColor.DarkGreen,ConsoleColor.Blue,ConsoleColor.Cyan,ConsoleColor.Magenta,ConsoleColor.DarkYellow,ConsoleColor.DarkBlue,ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray,ConsoleColor.Red,ConsoleColor.DarkBlue,ConsoleColor.DarkGreen,ConsoleColor.Blue,ConsoleColor.Cyan,ConsoleColor.Magenta,ConsoleColor.DarkYellow,ConsoleColor.DarkBlue,ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray,ConsoleColor.Red,ConsoleColor.DarkBlue,ConsoleColor.DarkGreen,ConsoleColor.Blue,ConsoleColor.Cyan,ConsoleColor.Magenta,ConsoleColor.DarkYellow,ConsoleColor.DarkBlue,ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray,ConsoleColor.Red,ConsoleColor.DarkBlue,ConsoleColor.DarkGreen,ConsoleColor.Blue,ConsoleColor.Cyan,ConsoleColor.Magenta,ConsoleColor.DarkYellow,ConsoleColor.DarkBlue };
15-
colors = colors.Reverse().ToArray();
16-
var originalPosition = new Point(x: Console.CursorLeft, y: Console.CursorTop);
17-
var colorIndex = 0;
18-
var width = 0;
19-
var startBackgroundColor = Console.BackgroundColor;
13+
try
14+
{
15+
if (labels.Length == 0) return;
16+
ClearToolbar();
17+
18+
_labels = labels;
19+
var colors = consoleColors ?? new[]
20+
{
21+
ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray, ConsoleColor.Red, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.Blue, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.DarkYellow, ConsoleColor.DarkBlue, ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray, ConsoleColor.Red, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.Blue, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.DarkYellow, ConsoleColor.DarkBlue, ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray, ConsoleColor.Red, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.Blue, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.DarkYellow, ConsoleColor.DarkBlue, ConsoleColor.Green, ConsoleColor.DarkRed, ConsoleColor.DarkMagenta, ConsoleColor.DarkYellow, ConsoleColor.DarkGray, ConsoleColor.Red, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.Blue, ConsoleColor.Cyan, ConsoleColor.Magenta, ConsoleColor.DarkYellow, ConsoleColor.DarkBlue
22+
};
23+
colors = colors.Reverse().ToArray();
24+
var originalPosition = new Point(x: Console.CursorLeft, y: Console.CursorTop);
25+
var colorIndex = 0;
26+
var width = 0;
27+
var startBackgroundColor = Console.BackgroundColor;
2028

21-
foreach (var label in labels.Reverse().Take(colors.Length))
29+
foreach (var label in labels.Reverse().Take(colors.Length))
30+
{
31+
var color = colors[colorIndex++];
32+
width += label.Length + 1;
33+
Console.SetCursorPosition(Math.Clamp(Console.WindowWidth - width, 0, Console.WindowWidth), Math.Clamp(Console.WindowHeight - 2, 0, Console.WindowHeight));
34+
Console.ForegroundColor = ConsoleColor.White;
35+
Console.BackgroundColor = color;
36+
Console.Write(label);
37+
Console.BackgroundColor = startBackgroundColor;
38+
Console.Write(" ");
39+
}
40+
41+
Console.ResetColor();
42+
Console.SetCursorPosition(originalPosition.X, originalPosition.Y);
43+
}
44+
catch (Exception e)
2245
{
23-
var color = colors[colorIndex++];
24-
width += label.Length + 1;
25-
Console.SetCursorPosition(Math.Clamp(Console.WindowWidth - width, 0, Console.WindowWidth), Math.Clamp(Console.WindowHeight - 2, 0, Console.WindowHeight));
26-
Console.ForegroundColor = ConsoleColor.White;
27-
Console.BackgroundColor = color;
28-
Console.Write(label);
29-
Console.BackgroundColor = startBackgroundColor;
30-
Console.Write(" ");
46+
ClearToolbar();
47+
IPowerCommandServices.DefaultInstance?.Logger.LogError(e.Message);
3148
}
32-
Console.ResetColor();
33-
Console.SetCursorPosition(originalPosition.X, originalPosition.Y);
49+
3450
}
3551
public static void ClearToolbar()
3652
{
37-
if(Labels.Length == 0) return;
38-
var originalPosition = new Point(x: Console.CursorLeft, y: Console.CursorTop);
39-
var width = 0;
40-
foreach (var label in Labels) width += label.Length+1;
41-
Console.SetCursorPosition( Math.Clamp(Console.WindowWidth - width, 0, Console.WindowWidth), Math.Clamp(Console.WindowHeight-2, 0, Console.WindowHeight));
42-
Console.Write("".PadLeft(width,' '));
43-
Console.SetCursorPosition(originalPosition.X, originalPosition.Y);
53+
try
54+
{
55+
if(_labels == null || _labels.Length == 0) return;
56+
var originalPosition = new Point(x: Console.CursorLeft, y: Console.CursorTop);
57+
var width = 0;
58+
foreach (var label in _labels) width += label.Length+1;
59+
Console.SetCursorPosition( Math.Clamp(Console.WindowWidth - width, 0, Console.WindowWidth), Math.Clamp(Console.WindowHeight-2, 0, Console.WindowHeight));
60+
Console.Write("".PadLeft(width,' '));
61+
Console.SetCursorPosition(originalPosition.X, originalPosition.Y);
62+
}
63+
catch (Exception e)
64+
{
65+
IPowerCommandServices.DefaultInstance?.Logger.LogError(e.Message);
66+
}
4467
}
4568

4669
private static ToolbarConfiguration? _configuration = null;

Templates/src/Core/PainKiller.PowerCommands.ReadLine/DOMAINOBJECTS/KeyHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ public KeyHandler(IConsole console, List<string> history, IAutoCompleteHandler a
9797
{
9898
if (IsInAutoCompleteMode()) PreviousAutoComplete();
9999
};
100+
_keyActions["ControlO"] = ReadLineService.OnOpenShortCutPressed;
101+
_keyActions["ControlS"] = ReadLineService.OnSaveShortCutPressed;
100102
}
101103

102104
private void MoveCursorLeft()

0 commit comments

Comments
 (0)