Skip to content

Commit 7910041

Browse files
committed
Copy/paste single line on clipboard
1 parent 37c665a commit 7910041

File tree

5 files changed

+100
-8
lines changed

5 files changed

+100
-8
lines changed

Syndiesis/Controls/Editor/CodeEditor.axaml.cs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ namespace Syndiesis.Controls;
1717
/// range of text, inserting new lines, copying and pasting text.
1818
/// </summary>
1919
/// <remarks>
20-
/// It is not meant to provide support for autocompletion, indentation preferences,
21-
/// multiple carets, etc. Those features are outside of the scope of this program.
22-
/// Highlighting is not yet implemented but is in the works.
20+
/// It is not meant to provide support for features like autocompletion, or more
21+
/// advanced IDE features. Those features are outside of the scope of this program.
2322
/// </remarks>
2423
public partial class CodeEditor : UserControl
2524
{
@@ -907,25 +906,45 @@ private void SelectAll()
907906

908907
private async Task CutSelectionToClipboardAsync()
909908
{
910-
var selection = _editor.GetCurrentSelectionString();
911-
if (string.IsNullOrEmpty(selection))
909+
var content = _editor.GetCurrentSelectionString();
910+
if (string.IsNullOrEmpty(content))
911+
{
912+
await CopyCurrentLineToClipboard();
913+
_editor.RemoveCurrentLine();
912914
return;
915+
}
913916

914917
_editor.DeleteCurrentSelection();
915-
await this.SetClipboardTextAsync(selection)
918+
await this.SetClipboardTextAsync(content)
916919
.ConfigureAwait(false);
917920
}
918921

919922
private async Task CopySelectionToClipboardAsync()
920923
{
921924
var selection = _editor.GetCurrentSelectionString();
922925
if (string.IsNullOrEmpty(selection))
926+
{
927+
await CopyCurrentLineToClipboard();
923928
return;
929+
}
924930

925931
await this.SetClipboardTextAsync(selection)
926932
.ConfigureAwait(false);
927933
}
928934

935+
private async Task CopyCurrentLineToClipboard()
936+
{
937+
var content = GetSingleLineClipboardContent();
938+
var data = CodeEditorDataObject.ForSingleLine(content);
939+
await this.SetClipboardDataAsync(data)
940+
.ConfigureAwait(false);
941+
}
942+
943+
private string GetSingleLineClipboardContent()
944+
{
945+
return _editor.GetCurrentLineContent() + MultilineStringEditor.DefaultNewLine;
946+
}
947+
929948
private readonly AsyncUsableLock _pasteLock = new();
930949

931950
private async Task PasteClipboardTextAsync()
@@ -939,7 +958,15 @@ private async Task PasteClipboardTextAsync()
939958
if (pasteText is null)
940959
return;
941960

942-
_editor.InsertText(pasteText);
961+
bool hasSingleLine = await this.HasSingleLineClipboardText();
962+
if (hasSingleLine)
963+
{
964+
_editor.InsertLine(pasteText);
965+
}
966+
else
967+
{
968+
_editor.InsertText(pasteText);
969+
}
943970
QueueUpdateVisibleText();
944971
}
945972
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Avalonia.Input;
2+
3+
namespace Syndiesis.Utilities;
4+
5+
public class CodeEditorDataObject : DataObject
6+
{
7+
public void SetLine(string line)
8+
{
9+
Set(DataFormats.Text, line);
10+
Set(Formats.CodeEditor, Formats.CodeEditor);
11+
}
12+
13+
public static CodeEditorDataObject ForSingleLine(string line)
14+
{
15+
var result = new CodeEditorDataObject();
16+
result.SetLine(line);
17+
return result;
18+
}
19+
20+
public static class Formats
21+
{
22+
public const string CodeEditor = "CodeEditor";
23+
}
24+
}

Syndiesis/Utilities/ControlExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Avalonia.Controls;
2+
using Avalonia.Input;
23
using Avalonia.Input.Platform;
34
using System.Threading.Tasks;
45

@@ -46,4 +47,23 @@ public static async Task SetClipboardTextAsync(this Control control, string? val
4647

4748
await clipboard.SetTextAsync(value);
4849
}
50+
51+
public static async Task SetClipboardDataAsync(this Control control, IDataObject value)
52+
{
53+
var clipboard = control.Clipboard();
54+
if (clipboard is null)
55+
return;
56+
57+
await clipboard.SetDataObjectAsync(value);
58+
}
59+
60+
public static async Task<bool> HasSingleLineClipboardText(this Control control)
61+
{
62+
var clipboard = control.Clipboard();
63+
if (clipboard is null)
64+
return false;
65+
66+
var data = await clipboard.GetDataAsync(CodeEditorDataObject.Formats.CodeEditor);
67+
return data is not null;
68+
}
4969
}

Syndiesis/Utilities/CursoredStringEditor.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,18 @@ public string GetCurrentSelectionString()
389389
return _editor.SectionString(_selectionSpan.SelectionPositionSpan);
390390
}
391391

392+
public string GetCurrentLineContent()
393+
{
394+
return _editor.LineAt(CursorLineIndex);
395+
}
396+
397+
public void RemoveCurrentLine()
398+
{
399+
_editor.RemoveLine(CursorLineIndex);
400+
PlaceCursorCharacterIndexAfterVerticalMovement(CursorCharacterIndex);
401+
TriggerCodeChanged();
402+
}
403+
392404
public bool DeleteCurrentSelection()
393405
{
394406
if (!_isSelectingText || !_selectionSpan.HasSelection)
@@ -572,6 +584,15 @@ public void InsertText(string? text)
572584
TriggerCodeChanged();
573585
}
574586

587+
public void InsertLine(string text)
588+
{
589+
DeleteCurrentSelection();
590+
591+
_editor.InsertAt(CursorLineIndex, 0, text);
592+
MoveCursorDown();
593+
TriggerCodeChanged();
594+
}
595+
575596
private LinePosition LeftmostContiguousCommonCategory()
576597
{
577598
// we assume that the caller has sanitized the positions

Syndiesis/Utilities/MultilineStringEditor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Syndiesis.Utilities;
99

1010
public sealed class MultilineStringEditor
1111
{
12-
private const string DefaultNewLine = "\r\n";
12+
public const string DefaultNewLine = "\r\n";
1313

1414
private readonly List<string> _lines = new();
1515

0 commit comments

Comments
 (0)