Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vi-mode] Add ViClipboardMode Option to Support Copying and Pasting to System Clipboard #3769

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions PSReadLine/Cmdlets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ public enum ViMode
Command
}

public enum ViClipboardMode
{
ViRegister,
SystemClipboard
}

public enum HistorySaveStyle
{
SaveIncrementally,
Expand Down Expand Up @@ -342,6 +348,11 @@ public object ContinuationPromptColor
/// </summary>
public ScriptBlock ViModeChangeHandler { get; set; }

/// <summary>
/// Which source should be used when copying and pasting in vi edit mode?
/// </summary>
public ViClipboardMode ViClipboardMode { get; set; }

/// <summary>
/// The path to the saved history.
/// </summary>
Expand Down Expand Up @@ -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
{
Expand Down
4 changes: 4 additions & 0 deletions PSReadLine/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions PSReadLine/PSReadLine.format.ps1xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ $d = [Microsoft.PowerShell.KeyHandler]::GetGroupingDescription($_.Group)
<ItemSelectionCondition><ScriptBlock>$null -ne $_.ViModeChangeHandler</ScriptBlock></ItemSelectionCondition>
<PropertyName>ViModeChangeHandler</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ViClipboardMode</PropertyName>
</ListItem>
<ListItem>
<PropertyName>WordDelimiters</PropertyName>
</ListItem>
Expand Down
60 changes: 48 additions & 12 deletions PSReadLine/ViRegister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

/// <summary>
/// Initialize a new instance of the <see cref="ViRegister" /> class.
Expand All @@ -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;
}

/// <summary>
/// Returns whether this register is empty.
/// </summary>
public bool IsEmpty
=> String.IsNullOrEmpty(_text);
=> String.IsNullOrEmpty(Text);

/// <summary>
/// Returns whether this register contains
Expand All @@ -41,7 +75,7 @@ public bool IsEmpty
/// Gets the raw text contained in the register
/// </summary>
public string RawText
=> _text;
=> Text;

/// <summary>
/// Records the entire buffer in the register.
Expand All @@ -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);
}

/// <summary>
Expand All @@ -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)
Expand All @@ -89,7 +123,7 @@ public int PasteAfter(StringBuilder buffer, int position)

if (HasLinewiseText)
{
var text = _text;
var text = Text;

if (text[0] != '\n')
{
Expand Down Expand Up @@ -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;
}
Expand All @@ -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')
{
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions test/ViRegisterTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Internal;
using Xunit;

namespace Test
Expand Down Expand Up @@ -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());
}
}
}