Skip to content

Commit fcb2c9d

Browse files
Add a -Chord parameter to Get-PSReadLineKeyHandler (#1298)
1 parent 8b778c6 commit fcb2c9d

File tree

5 files changed

+161
-6
lines changed

5 files changed

+161
-6
lines changed

PSReadLine/Cmdlets.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -805,26 +805,32 @@ public object GetDynamicParameters()
805805
}
806806
}
807807

808-
[Cmdlet("Get", "PSReadLineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528807")]
808+
[Cmdlet("Get", "PSReadLineKeyHandler", DefaultParameterSetName = "FullListing",
809+
HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528807")]
809810
[OutputType(typeof(KeyHandler))]
810811
public class GetKeyHandlerCommand : PSCmdlet
811812
{
812-
[Parameter]
813+
[Parameter(ParameterSetName = "FullListing")]
813814
public SwitchParameter Bound
814815
{
815816
get => _bound.GetValueOrDefault();
816817
set => _bound = value;
817818
}
818819
private SwitchParameter? _bound;
819820

820-
[Parameter]
821+
[Parameter(ParameterSetName = "FullListing")]
821822
public SwitchParameter Unbound
822823
{
823824
get => _unbound.GetValueOrDefault();
824825
set => _unbound = value;
825826
}
826827
private SwitchParameter? _unbound;
827828

829+
[Parameter(ParameterSetName = "SpecificBindings", Position = 0, Mandatory = true)]
830+
[ValidateNotNullOrEmpty]
831+
[Alias("Key")]
832+
public string[] Chord { get; set; }
833+
828834
[ExcludeFromCodeCoverage]
829835
protected override void EndProcessing()
830836
{
@@ -845,7 +851,18 @@ protected override void EndProcessing()
845851
bound = false;
846852
unbound = _unbound.Value.IsPresent;
847853
}
848-
var groups = PSConsoleReadLine.GetKeyHandlers(bound, unbound).GroupBy(k => k.Group).OrderBy(g => g.Key);
854+
855+
IEnumerable<PowerShell.KeyHandler> handlers;
856+
if (ParameterSetName.Equals("FullListing", StringComparison.OrdinalIgnoreCase))
857+
{
858+
handlers = PSConsoleReadLine.GetKeyHandlers(bound, unbound);
859+
}
860+
else
861+
{
862+
handlers = PSConsoleReadLine.GetKeyHandlers(Chord);
863+
}
864+
var groups = handlers.GroupBy(k => k.Group).OrderBy(g => g.Key);
865+
849866
foreach (var bindings in groups)
850867
{
851868
WriteObject(bindings.OrderBy(k => k.Function), true);

PSReadLine/Options.cs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,5 +399,88 @@ public static void RemoveKeyHandler(string[] key)
399399
}
400400
}
401401
}
402+
403+
/// <summary>
404+
/// Return key handlers bound to specified chords.
405+
/// </summary>
406+
/// <returns></returns>
407+
public static IEnumerable<PowerShell.KeyHandler> GetKeyHandlers(string[] Chord)
408+
{
409+
var boundFunctions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
410+
411+
if (Chord == null) yield break;
412+
413+
foreach (string Key in Chord)
414+
{
415+
ConsoleKeyInfo[] consoleKeyChord = ConsoleKeyChordConverter.Convert(Key);
416+
PSKeyInfo firstKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[0]);
417+
418+
if (_singleton._dispatchTable.TryGetValue(firstKey, out KeyHandler entry))
419+
{
420+
if (consoleKeyChord.Length == 1)
421+
{
422+
yield return new PowerShell.KeyHandler
423+
{
424+
Key = firstKey.KeyStr,
425+
Function = entry.BriefDescription,
426+
Description = entry.LongDescription,
427+
Group = GetDisplayGrouping(entry.BriefDescription),
428+
};
429+
}
430+
else
431+
{
432+
PSKeyInfo secondKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[1]);
433+
if (_singleton._chordDispatchTable.TryGetValue(firstKey, out var secondDispatchTable) &&
434+
secondDispatchTable.TryGetValue(secondKey, out entry))
435+
{
436+
yield return new PowerShell.KeyHandler
437+
{
438+
Key = firstKey.KeyStr + "," + secondKey.KeyStr,
439+
Function = entry.BriefDescription,
440+
Description = entry.LongDescription,
441+
Group = GetDisplayGrouping(entry.BriefDescription),
442+
};
443+
}
444+
}
445+
}
446+
447+
// If in Vi mode, also check Vi's command mode list.
448+
if (PSConsoleReadLine.GetOptions().EditMode == EditMode.Vi)
449+
{
450+
if (_viCmdKeyMap.TryGetValue(firstKey, out entry))
451+
{
452+
if (consoleKeyChord.Length == 1)
453+
{
454+
if (entry.BriefDescription == "Ignore") continue;
455+
yield return new PowerShell.KeyHandler
456+
{
457+
Key = '<' + firstKey.KeyStr + '>',
458+
Function = entry.BriefDescription,
459+
Description = entry.LongDescription,
460+
Group = GetDisplayGrouping(entry.BriefDescription),
461+
};
462+
}
463+
else
464+
{
465+
PSKeyInfo secondKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[1]);
466+
if (_viCmdChordTable.TryGetValue(firstKey, out var secondDispatchTable) &&
467+
secondDispatchTable.TryGetValue(secondKey, out entry))
468+
{
469+
if (entry.BriefDescription == "Ignore") continue;
470+
yield return new PowerShell.KeyHandler
471+
{
472+
Key = '<' + firstKey.KeyStr + "," + secondKey.KeyStr + '>',
473+
Function = entry.BriefDescription,
474+
Description = entry.LongDescription,
475+
Group = GetDisplayGrouping(entry.BriefDescription),
476+
};
477+
}
478+
}
479+
}
480+
}
481+
}
482+
yield break;
483+
484+
}
402485
}
403486
}

docs/Get-PSReadLineKeyHandler.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Include functions that are bound.
3737

3838
```yaml
3939
Type: switch
40-
Parameter Sets: (All)
40+
Parameter Sets: Set 1
4141
Aliases:
4242

4343
Required: False
@@ -53,7 +53,7 @@ Include functions that are unbound.
5353
5454
```yaml
5555
Type: switch
56-
Parameter Sets: (All)
56+
Parameter Sets: Set 1
5757
Aliases:
5858

5959
Required: False
@@ -63,6 +63,22 @@ Accept pipeline input: false
6363
Accept wildcard characters: False
6464
```
6565
66+
### -Chord
67+
68+
Return only functions bound to specific keys or sequences.
69+
70+
```yaml
71+
Type: String[]
72+
Parameter Sets: Set 2
73+
Aliases: Key
74+
75+
Required: True
76+
Position: 0
77+
Default value:
78+
Accept pipeline input: false
79+
Accept wildcard characters: False
80+
```
81+
6682
## INPUTS
6783
6884
### None

test/OptionsTest.VI.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ public void ViGetKeyHandlers()
2323
Assert.False(string.IsNullOrWhiteSpace(handler.Function));
2424
Assert.False(string.IsNullOrWhiteSpace(handler.Description));
2525
}
26+
27+
var handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "home" });
28+
Assert.NotEmpty(handlers);
29+
foreach (var handler in handlers)
30+
{
31+
Assert.Contains("Home", handler.Key);
32+
}
33+
34+
handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "d,0" });
35+
Assert.NotEmpty(handlers);
36+
foreach (var handler in handlers)
37+
{
38+
Assert.Equal("<d,0>", handler.Key);
39+
}
2640
}
2741
}
2842
}

test/OptionsTest.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public void ContinuationPrompt()
5858
[SkippableFact]
5959
public void GetKeyHandlers()
6060
{
61+
System.Collections.Generic.IEnumerable<Microsoft.PowerShell.KeyHandler> handlers;
62+
6163
foreach (var keymode in new[] {KeyMode.Cmd, KeyMode.Emacs})
6264
{
6365
TestSetup(keymode);
@@ -75,6 +77,29 @@ public void GetKeyHandlers()
7577
Assert.False(string.IsNullOrWhiteSpace(handler.Function));
7678
Assert.False(string.IsNullOrWhiteSpace(handler.Description));
7779
}
80+
81+
handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "home" });
82+
Assert.NotEmpty(handlers);
83+
foreach (var handler in handlers)
84+
{
85+
Assert.Equal("Home", handler.Key);
86+
}
87+
}
88+
89+
TestSetup(KeyMode.Emacs);
90+
91+
handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "ctrl+x" });
92+
Assert.NotEmpty(handlers);
93+
foreach (var handler in handlers)
94+
{
95+
Assert.Equal("Ctrl+x", handler.Key);
96+
}
97+
98+
handlers = PSConsoleReadLine.GetKeyHandlers(Chord: new string[] { "ctrl+x,ctrl+e" });
99+
Assert.NotEmpty(handlers);
100+
foreach (var handler in handlers)
101+
{
102+
Assert.Equal("Ctrl+x,Ctrl+e", handler.Key);
78103
}
79104
}
80105

0 commit comments

Comments
 (0)