diff --git a/PSReadLine/Cmdlets.cs b/PSReadLine/Cmdlets.cs
index bc89cc1f9..aa48df9d3 100644
--- a/PSReadLine/Cmdlets.cs
+++ b/PSReadLine/Cmdlets.cs
@@ -50,6 +50,12 @@ public enum ViMode
Command
}
+ public enum ViClipboardMode
+ {
+ ViRegister,
+ SystemClipboard
+ }
+
public enum HistorySaveStyle
{
SaveIncrementally,
@@ -342,6 +348,11 @@ public object ContinuationPromptColor
///
public ScriptBlock ViModeChangeHandler { get; set; }
+ ///
+ /// Which source should be used when copying and pasting in vi edit mode?
+ ///
+ public ViClipboardMode ViClipboardMode { get; set; }
+
///
/// The path to the saved history.
///
@@ -789,6 +800,14 @@ public ViModeStyle ViModeIndicator
[Parameter]
public ScriptBlock ViModeChangeHandler { get; set; }
+ [Parameter]
+ public ViClipboardMode ViClipboardMode
+ {
+ get => _viClipboardMode.GetValueOrDefault();
+ set => _viClipboardMode = value;
+ }
+ internal ViClipboardMode? _viClipboardMode;
+
[Parameter]
public PredictionSource PredictionSource
{
diff --git a/PSReadLine/Options.cs b/PSReadLine/Options.cs
index 19f366513..d8687e682 100644
--- a/PSReadLine/Options.cs
+++ b/PSReadLine/Options.cs
@@ -120,6 +120,10 @@ private void SetOptionsInternal(SetPSReadLineOption options)
}
Options.ViModeChangeHandler = options.ViModeChangeHandler;
}
+ if (options._viClipboardMode.HasValue)
+ {
+ Options.ViClipboardMode = options.ViClipboardMode;
+ }
if (options.HistorySavePath != null)
{
Options.HistorySavePath = options.HistorySavePath;
diff --git a/PSReadLine/PSReadLine.format.ps1xml b/PSReadLine/PSReadLine.format.ps1xml
index 5b20c58af..df3768676 100644
--- a/PSReadLine/PSReadLine.format.ps1xml
+++ b/PSReadLine/PSReadLine.format.ps1xml
@@ -152,6 +152,9 @@ $d = [Microsoft.PowerShell.KeyHandler]::GetGroupingDescription($_.Group)
$null -ne $_.ViModeChangeHandler
ViModeChangeHandler
+
+ ViClipboardMode
+
WordDelimiters
diff --git a/PSReadLine/ViRegister.cs b/PSReadLine/ViRegister.cs
index 48df9965f..077862946 100644
--- a/PSReadLine/ViRegister.cs
+++ b/PSReadLine/ViRegister.cs
@@ -11,7 +11,33 @@ public partial class PSConsoleReadLine
internal sealed class ViRegister
{
private readonly PSConsoleReadLine _singleton;
- private string _text;
+ private string _localText;
+ private PSConsoleReadLineOptions _options;
+ private string Text
+ {
+ get
+ {
+ if (_options?.ViClipboardMode == ViClipboardMode.SystemClipboard)
+ {
+ return Internal.Clipboard.GetText();
+ }
+ else
+ {
+ return _localText;
+ }
+ }
+ set
+ {
+ if (_options?.ViClipboardMode == ViClipboardMode.SystemClipboard)
+ {
+ Internal.Clipboard.SetText(value);
+ }
+ else
+ {
+ _localText = value;
+ }
+ }
+ }
///
/// Initialize a new instance of the class.
@@ -23,13 +49,21 @@ internal sealed class ViRegister
public ViRegister(PSConsoleReadLine singleton)
{
_singleton = singleton;
+ _options = _singleton?.Options;
+ }
+
+ internal static ViRegister CreateTestRegister(PSConsoleReadLineOptions options)
+ {
+ ViRegister register = new ViRegister(null);
+ register._options = options;
+ return register;
}
///
/// Returns whether this register is empty.
///
public bool IsEmpty
- => String.IsNullOrEmpty(_text);
+ => String.IsNullOrEmpty(Text);
///
/// Returns whether this register contains
@@ -41,7 +75,7 @@ public bool IsEmpty
/// Gets the raw text contained in the register
///
public string RawText
- => _text;
+ => Text;
///
/// Records the entire buffer in the register.
@@ -67,7 +101,7 @@ public void Record(StringBuilder buffer, int offset, int count)
System.Diagnostics.Debug.Assert(offset + count <= buffer.Length);
HasLinewiseText = false;
- _text = buffer.ToString(offset, count);
+ Text = buffer.ToString(offset, count);
}
///
@@ -77,7 +111,7 @@ public void Record(StringBuilder buffer, int offset, int count)
public void LinewiseRecord(string text)
{
HasLinewiseText = true;
- _text = text;
+ Text = text;
}
public int PasteAfter(StringBuilder buffer, int position)
@@ -89,7 +123,7 @@ public int PasteAfter(StringBuilder buffer, int position)
if (HasLinewiseText)
{
- var text = _text;
+ var text = Text;
if (text[0] != '\n')
{
@@ -127,8 +161,9 @@ public int PasteAfter(StringBuilder buffer, int position)
position += 1;
}
- InsertAt(buffer, _text, position, position);
- position += _text.Length - 1;
+ var text = Text;
+ InsertAt(buffer, text, position, position);
+ position += text.Length - 1;
return position;
}
@@ -145,7 +180,7 @@ public int PasteBefore(StringBuilder buffer, int position)
position = Math.Max(0, Math.Min(position, buffer.Length - 1));
- var text = _text;
+ var text = Text;
if (text[0] == '\n')
{
@@ -184,8 +219,9 @@ public int PasteBefore(StringBuilder buffer, int position)
}
else
{
- InsertAt(buffer, _text, position, position);
- return position + _text.Length - 1;
+ var text = Text;
+ InsertAt(buffer, text, position, position);
+ return position + text.Length - 1;
}
}
@@ -246,7 +282,7 @@ private void RecordPaste(string text, int position, int anchor)
#if DEBUG
public override string ToString()
{
- var text = _text.Replace("\n", "\\n");
+ var text = Text.Replace("\n", "\\n");
return (HasLinewiseText ? "line: " : "") + "\"" + text + "\"";
}
#endif
diff --git a/test/ViRegisterTests.cs b/test/ViRegisterTests.cs
index 15c9884da..1eac93311 100644
--- a/test/ViRegisterTests.cs
+++ b/test/ViRegisterTests.cs
@@ -1,5 +1,6 @@
using System.Text;
using Microsoft.PowerShell;
+using Microsoft.PowerShell.Internal;
using Xunit;
namespace Test
@@ -152,5 +153,51 @@ public void ViRegister_Lines_LinewisePasteAfter_Lines()
Assert.Equal("line1\nline2\nline3\n", buffer.ToString());
Assert.Equal(6, newPosition);
}
+
+ [Fact]
+ public void ViRegister_ClipboardModeViRegister()
+ {
+ PSConsoleReadLineOptions options = new PSConsoleReadLineOptions(string.Empty, false)
+ {
+ ViClipboardMode = ViClipboardMode.ViRegister
+ };
+ var register = PSConsoleReadLine.ViRegister.CreateTestRegister(options);
+
+ // system under test
+
+ Clipboard.SetText("EmptyClipboard");
+ var copyBuffer = new StringBuilder("CopiedText");
+ register.Record(copyBuffer);
+ var pasteBuffer = new StringBuilder();
+ register.PasteAfter(pasteBuffer, 0);
+
+ // assert expectations
+
+ Assert.Equal("EmptyClipboard", Clipboard.GetText());
+ Assert.Equal("CopiedText", pasteBuffer.ToString());
+ }
+
+ [Fact]
+ public void ViRegister_ClipboardModeSystemClipboard()
+ {
+ PSConsoleReadLineOptions options = new PSConsoleReadLineOptions(string.Empty, false)
+ {
+ ViClipboardMode = ViClipboardMode.SystemClipboard
+ };
+ var register = PSConsoleReadLine.ViRegister.CreateTestRegister(options);
+
+ // system under test
+
+ Clipboard.SetText("EmptyClipboard");
+ var copyBuffer = new StringBuilder("CopiedText");
+ register.Record(copyBuffer);
+ var pasteBuffer = new StringBuilder();
+ register.PasteAfter(pasteBuffer, 0);
+
+ // assert expectations
+
+ Assert.Equal("CopiedText", Clipboard.GetText());
+ Assert.Equal("CopiedText", pasteBuffer.ToString());
+ }
}
}