Skip to content

Commit d38c962

Browse files
Add the ability to change Vi cmd mode dispatch tables.
1 parent 2f781a1 commit d38c962

File tree

6 files changed

+136
-21
lines changed

6 files changed

+136
-21
lines changed

PSReadLine/Cmdlets.cs

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public enum ViModeStyle
5252
Prompt,
5353
Cursor
5454
}
55+
56+
public enum ViMode
57+
{
58+
Insert,
59+
Command
60+
}
5561
#endregion vi
5662

5763
public enum HistorySaveStyle
@@ -590,15 +596,48 @@ protected override void EndProcessing()
590596
}
591597
}
592598

593-
[Cmdlet("Set", "PSReadlineKeyHandler", HelpUri = "http://go.microsoft.com/fwlink/?LinkId=528810")]
594-
public class SetPSReadlineKeyHandlerCommand : PSCmdlet, IDynamicParameters
599+
public class ChangePSReadlineKeyHandlerCommand : PSCmdlet
595600
{
596601
[Parameter(Position = 0, Mandatory = true)]
597602
[Alias("Key")]
598603
[ValidateNotNullOrEmpty]
599604
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
600605
public string[] Chord { get; set; }
601606

607+
[Parameter]
608+
public ViMode ViMode { get; set; }
609+
610+
[ExcludeFromCodeCoverage]
611+
protected IDisposable UseRequestedDispatchTables()
612+
{
613+
bool inViMode = PSConsoleReadLine.GetOptions().EditMode == EditMode.Vi;
614+
bool viModeParamPresent = MyInvocation.BoundParameters.ContainsKey("ViMode");
615+
616+
if (inViMode || viModeParamPresent)
617+
{
618+
if (!inViMode)
619+
{
620+
// "-ViMode" must have been specified explicitly. Well, okay... we can
621+
// modify the Vi tables... but isn't that an odd thing to do from
622+
// not-vi mode?
623+
WriteWarning(PSReadLineResources.NotInViMode);
624+
}
625+
626+
if (ViMode == ViMode.Insert) // default if -ViMode not specified
627+
return PSConsoleReadLine.UseViInsertModeTables();
628+
else if (ViMode == ViMode.Command)
629+
return PSConsoleReadLine.UseViCommandModeTables();
630+
else
631+
System.Diagnostics.Debug.Fail("unexpected ViMode");
632+
}
633+
634+
return null;
635+
}
636+
}
637+
638+
[Cmdlet("Set", "PSReadlineKeyHandler", HelpUri = "http://go.microsoft.com/fwlink/?LinkId=528810")]
639+
public class SetPSReadlineKeyHandlerCommand : ChangePSReadlineKeyHandlerCommand, IDynamicParameters
640+
{
602641
[Parameter(Position = 1, Mandatory = true, ParameterSetName = "ScriptBlock")]
603642
[ValidateNotNull]
604643
public ScriptBlock ScriptBlock { get; set; }
@@ -616,18 +655,21 @@ public class SetPSReadlineKeyHandlerCommand : PSCmdlet, IDynamicParameters
616655
[ExcludeFromCodeCoverage]
617656
protected override void EndProcessing()
618657
{
619-
if (ParameterSetName.Equals(FunctionParameterSet))
620-
{
621-
var function = (string)_dynamicParameters.Value[FunctionParameter].Value;
622-
var keyHandler = (Action<ConsoleKeyInfo?, object>)
623-
Delegate.CreateDelegate(typeof (Action<ConsoleKeyInfo?, object>),
624-
typeof (PSConsoleReadLine).GetMethod(function));
625-
BriefDescription = function;
626-
PSConsoleReadLine.SetKeyHandler(Chord, keyHandler, BriefDescription, Description);
627-
}
628-
else
658+
using (UseRequestedDispatchTables())
629659
{
630-
PSConsoleReadLine.SetKeyHandler(Chord, ScriptBlock, BriefDescription, Description);
660+
if (ParameterSetName.Equals(FunctionParameterSet))
661+
{
662+
var function = (string)_dynamicParameters.Value[FunctionParameter].Value;
663+
var keyHandler = (Action<ConsoleKeyInfo?, object>)
664+
Delegate.CreateDelegate(typeof (Action<ConsoleKeyInfo?, object>),
665+
typeof (PSConsoleReadLine).GetMethod(function));
666+
BriefDescription = function;
667+
PSConsoleReadLine.SetKeyHandler(Chord, keyHandler, BriefDescription, Description);
668+
}
669+
else
670+
{
671+
PSConsoleReadLine.SetKeyHandler(Chord, ScriptBlock, BriefDescription, Description);
672+
}
631673
}
632674
}
633675

@@ -713,18 +755,15 @@ protected override void EndProcessing()
713755
}
714756

715757
[Cmdlet("Remove", "PSReadlineKeyHandler", HelpUri = "http://go.microsoft.com/fwlink/?LinkId=528809")]
716-
public class RemoveKeyHandlerCommand : PSCmdlet
758+
public class RemoveKeyHandlerCommand : ChangePSReadlineKeyHandlerCommand
717759
{
718-
[Parameter(Position = 0, Mandatory = true)]
719-
[Alias("Key")]
720-
[ValidateNotNullOrEmpty]
721-
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
722-
public string[] Chord { get; set; }
723-
724760
[ExcludeFromCodeCoverage]
725761
protected override void EndProcessing()
726762
{
727-
PSConsoleReadLine.RemoveKeyHandler(Chord);
763+
using (UseRequestedDispatchTables())
764+
{
765+
PSConsoleReadLine.RemoveKeyHandler(Chord);
766+
}
728767
}
729768
}
730769

PSReadLine/Disposable.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
3+
namespace Microsoft.PowerShell
4+
{
5+
internal sealed class Disposable : IDisposable
6+
{
7+
private Action m_onDispose;
8+
9+
public Disposable(Action onDispose)
10+
{
11+
if (onDispose == null)
12+
throw new ArgumentNullException("onDispose");
13+
14+
m_onDispose = onDispose;
15+
}
16+
17+
public void Dispose()
18+
{
19+
if (m_onDispose != null)
20+
{
21+
m_onDispose();
22+
m_onDispose = null;
23+
}
24+
}
25+
}
26+
}
27+

PSReadLine/PSReadLine.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
<Compile Include="ConsoleBufferBuilder.cs" />
5858
<Compile Include="ConsoleKeyChordConverter.cs" />
5959
<Compile Include="ConsoleLib.cs" />
60+
<Compile Include="Disposable.cs" />
6061
<Compile Include="History.cs" />
6162
<Compile Include="HistoryQueue.cs" />
6263
<Compile Include="KeyBindings.cs" />

PSReadLine/PSReadLineResources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PSReadLine/PSReadLineResources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,4 +717,7 @@ If there are other parse errors, unresolved commands, or incorrect parameters, s
717717
<data name="ViJoinLinesDescription" xml:space="preserve">
718718
<value>Joins the current multi-line edit mode line with the next.</value>
719719
</data>
720+
<data name="NotInViMode" xml:space="preserve">
721+
<value>The -ViMode parameter was used, but the current EditMode is not Vi.</value>
722+
</data>
720723
</root>

PSReadLine/ReadLine.vi.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,42 @@ public static void ViInsertMode(ConsoleKeyInfo? key = null, object arg = null)
511511
_singleton.ViIndicateInsertMode();
512512
}
513513

514+
/// <summary>
515+
/// Temporarily swap in Vi-Command dispatch tables. Used for setting handlers.
516+
/// </summary>
517+
internal static IDisposable UseViCommandModeTables()
518+
{
519+
var oldDispatchTable = _singleton._dispatchTable;
520+
var oldChordDispatchTable = _singleton._chordDispatchTable;
521+
522+
_singleton._dispatchTable = _viCmdKeyMap;
523+
_singleton._chordDispatchTable = _viCmdChordTable;
524+
525+
return new Disposable( () =>
526+
{
527+
_singleton._dispatchTable = oldDispatchTable;
528+
_singleton._chordDispatchTable = oldChordDispatchTable;
529+
} );
530+
}
531+
532+
/// <summary>
533+
/// Temporarily swap in Vi-Insert dispatch tables. Used for setting handlers.
534+
/// </summary>
535+
internal static IDisposable UseViInsertModeTables()
536+
{
537+
var oldDispatchTable = _singleton._dispatchTable;
538+
var oldChordDispatchTable = _singleton._chordDispatchTable;
539+
540+
_singleton._dispatchTable = _viInsKeyMap;
541+
_singleton._chordDispatchTable = _viInsChordTable;
542+
543+
return new Disposable( () =>
544+
{
545+
_singleton._dispatchTable = oldDispatchTable;
546+
_singleton._chordDispatchTable = oldChordDispatchTable;
547+
} );
548+
}
549+
514550
private void ViIndicateCommandMode()
515551
{
516552
if (_options.ViModeIndicator == ViModeStyle.Cursor)

0 commit comments

Comments
 (0)