diff --git a/src/ClipCMD/App.axaml b/src/ClipCMD/App.axaml
index a15550a..0d29022 100644
--- a/src/ClipCMD/App.axaml
+++ b/src/ClipCMD/App.axaml
@@ -1,5 +1,6 @@
@@ -16,6 +17,7 @@
+
\ No newline at end of file
diff --git a/src/ClipCMD/App.axaml.cs b/src/ClipCMD/App.axaml.cs
index b35fbd5..fea6b25 100644
--- a/src/ClipCMD/App.axaml.cs
+++ b/src/ClipCMD/App.axaml.cs
@@ -37,6 +37,7 @@ public partial class App : Application
desktop.MainWindow.Closing += (sender, e) =>
{
Settings.SaveSettings();
+ clipCmdCommandHandler.SaveCommands();
};
clipCmdCommandHandler.Start();
diff --git a/src/ClipCMD/ClipCmd.csproj b/src/ClipCMD/ClipCmd.csproj
index f800838..30ab02a 100644
--- a/src/ClipCMD/ClipCmd.csproj
+++ b/src/ClipCMD/ClipCmd.csproj
@@ -19,6 +19,7 @@
+
@@ -30,4 +31,10 @@
+
+
+
+ InputDialogView.axaml
+
+
diff --git a/src/ClipCMD/GlobalSuppressions.cs b/src/ClipCMD/GlobalSuppressions.cs
index 924b2cd..adae0f4 100644
--- a/src/ClipCMD/GlobalSuppressions.cs
+++ b/src/ClipCMD/GlobalSuppressions.cs
@@ -1,4 +1,7 @@
-// This file is used by Code Analysis to maintain SuppressMessage
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "")]
+// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
\ No newline at end of file
diff --git a/src/ClipCMD/Models/ClipCmdCommand.cs b/src/ClipCMD/Models/ClipCmdCommand.cs
index ea58fbe..1d609f3 100644
--- a/src/ClipCMD/Models/ClipCmdCommand.cs
+++ b/src/ClipCMD/Models/ClipCmdCommand.cs
@@ -1,6 +1,6 @@
namespace ClipCmd.Models;
-internal class ClipCmdCommand
+public class ClipCmdCommand(string script)
{
- public string Script { get; set; } = string.Empty;
+ public string Script { get; set; } = script;
}
\ No newline at end of file
diff --git a/src/ClipCMD/Models/Settings.cs b/src/ClipCMD/Models/Settings.cs
index d351d61..cca274b 100644
--- a/src/ClipCMD/Models/Settings.cs
+++ b/src/ClipCMD/Models/Settings.cs
@@ -13,7 +13,7 @@ public class Settings
public bool AutoPaste { get; set; } = true;
- public int AutoTypeDelay { get; set; }
+ public int AutoTypeDelay { get; set; } = 100;
public ClipCmdMode Mode { get; set; }
@@ -21,6 +21,8 @@ public class Settings
public string Suffix { get; set; } = "";
+ public string CommandArgsSeperator { get; set; } = ":";
+
public static void SaveSettings()
{
if (!Directory.Exists(Configuration.ApplicationDataPath))
diff --git a/src/ClipCMD/Utilities/ClipCmdCommandHandler.cs b/src/ClipCMD/Utilities/ClipCmdCommandHandler.cs
index db95667..129d910 100644
--- a/src/ClipCMD/Utilities/ClipCmdCommandHandler.cs
+++ b/src/ClipCMD/Utilities/ClipCmdCommandHandler.cs
@@ -1,4 +1,5 @@
-using Avalonia.Controls;
+using Avalonia.Collections;
+using Avalonia.Controls;
using Avalonia.Input.Platform;
using ClipCmd.Models;
@@ -7,8 +8,12 @@ using SharpHook;
using SharpHook.Native;
using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Management.Automation;
using System.Text;
+using System.Text.Json;
using System.Threading.Tasks;
namespace ClipCmd.Utilities;
@@ -17,13 +22,15 @@ public class ClipCmdCommandHandler(Window window)
{
private readonly IClipboard clipboard = window.Clipboard!;
private readonly EventSimulator simulator = new EventSimulator();
- private readonly ConcurrentDictionary commands = new();
private string lastText = string.Empty;
+ public AvaloniaDictionary Commands { get; } = [];
public void Start()
{
_ = new TaskFactory().StartNew(async () =>
{
+ LoadCommands();
+
while (true)
{
await Run();
@@ -32,6 +39,33 @@ public class ClipCmdCommandHandler(Window window)
}, TaskCreationOptions.LongRunning);
}
+ public void ClearCommands()
+ {
+ Commands.Clear();
+ }
+
+ public void SaveCommands()
+ {
+ string json = JsonSerializer.Serialize(Commands);
+ File.WriteAllText(Configuration.CommandsPath, json);
+ }
+
+ public void LoadCommands()
+ {
+ if (!File.Exists(Configuration.CommandsPath))
+ {
+ return;
+ }
+
+ string json = File.ReadAllText(Configuration.CommandsPath);
+ Commands.Clear();
+
+ foreach (KeyValuePair command in JsonSerializer.Deserialize>(json) ?? new())
+ {
+ Commands[command.Key] = command.Value;
+ }
+ }
+
private async Task Run()
{
string? text = await clipboard.GetTextAsync();
@@ -48,14 +82,18 @@ public class ClipCmdCommandHandler(Window window)
return;
}
- string commandName = text[Settings.Current.Prefix.Length..^Settings.Current.Suffix.Length];
+ string input = text[Settings.Current.Prefix.Length..^Settings.Current.Suffix.Length].Replace(Settings.Current.CommandArgsSeperator + Settings.Current.CommandArgsSeperator, "\0");
+ string[] parts = input.Split(Settings.Current.CommandArgsSeperator);
+ string commandName = parts[0].Replace("\0", Settings.Current.CommandArgsSeperator);
+ string[] parameters = parts.Skip(1).Select(p => p.Replace("\0", Settings.Current.CommandArgsSeperator)).ToArray();
StringBuilder outText = new StringBuilder();
- if (commands.TryGetValue(commandName, out ClipCmdCommand? command))
+ if (Commands.TryGetValue(commandName, out ClipCmdCommand? command))
{
PowerShell powerShell = PowerShell.Create();
_ = powerShell.AddScript(command.Script);
+ _ = powerShell.AddParameters(parameters);
foreach (PSObject commandResult in await powerShell.InvokeAsync())
{
@@ -66,6 +104,10 @@ public class ClipCmdCommandHandler(Window window)
{
return;
}
+ else if (commandName == "list")
+ {
+ _ = outText.AppendLine($"Commands: {string.Join(", ", Commands.Keys)}");
+ }
else
{
_ = outText.AppendLine("Command not found!");
@@ -90,6 +132,12 @@ public class ClipCmdCommandHandler(Window window)
{
foreach (char c in outText.ToString().TrimEnd())
{
+ if (c == '\n')
+ {
+ _ = simulator.SimulateKeyPress(KeyCode.VcEnter);
+ continue;
+ }
+
_ = simulator.SimulateTextEntry(c.ToString());
await Task.Delay(Settings.Current.AutoTypeDelay);
}
diff --git a/src/ClipCMD/Utilities/Configuration.cs b/src/ClipCMD/Utilities/Configuration.cs
index d1f7c37..825cca1 100644
--- a/src/ClipCMD/Utilities/Configuration.cs
+++ b/src/ClipCMD/Utilities/Configuration.cs
@@ -21,4 +21,6 @@ internal static class Configuration
public static string SettingsFilePath => Path.Combine(ApplicationDataPath, "settings.json");
public static string LogFilePath => Path.Combine(ApplicationDataPath, $"ClipCMD.log");
+
+ public static string CommandsPath => Path.Combine(ApplicationDataPath, "commands.json");
}
\ No newline at end of file
diff --git a/src/ClipCMD/ViewModels/ClipCmdCommandItemViewModel.cs b/src/ClipCMD/ViewModels/ClipCmdCommandItemViewModel.cs
new file mode 100644
index 0000000..7530c94
--- /dev/null
+++ b/src/ClipCMD/ViewModels/ClipCmdCommandItemViewModel.cs
@@ -0,0 +1,73 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+
+using ClipCmd.Models;
+using ClipCmd.Utilities;
+using ClipCmd.Views;
+
+using DialogHostAvalonia;
+
+using ReactiveUI;
+
+using System.Collections.Generic;
+using System.Windows.Input;
+
+namespace ClipCmd.ViewModels;
+
+public class ClipCmdCommandItemViewModel(string name, ClipCmdCommandHandler clipCmdCommandHandler)
+{
+ public string Name { get; } = name;
+
+ public ICommand RemoveCommand => ReactiveCommand.Create(Remove);
+
+ public ICommand RenameCommand => ReactiveCommand.Create(Rename);
+
+ public ICommand EditCommand => ReactiveCommand.Create(Edit);
+
+ private void Remove()
+ {
+ _ = clipCmdCommandHandler.Commands.Remove(Name);
+ clipCmdCommandHandler.SaveCommands();
+ }
+
+ private async void Rename()
+ {
+ string? newName = await DialogHost.Show(new InputDialogViewModel("Edit command name:", Name)) as string;
+ newName = newName?.Trim();
+
+ if (!clipCmdCommandHandler.Commands.Remove(Name, out ClipCmdCommand? clipCmdCommand))
+ {
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(newName))
+ {
+ clipCmdCommandHandler.Commands.Add(Name, clipCmdCommand);
+ return;
+ }
+
+ int counter = 0;
+ string originalName = newName;
+
+ while (clipCmdCommandHandler.Commands.ContainsKey(newName))
+ {
+ newName = $"{originalName} ({++counter})";
+ }
+
+ clipCmdCommandHandler.Commands.Add(newName, clipCmdCommand);
+ clipCmdCommandHandler.SaveCommands();
+ }
+
+ private async void Edit()
+ {
+ Avalonia.Controls.Window? mainWindow = Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop ? desktop.MainWindow : null;
+
+ EditorWindow editorWindow = new EditorWindow
+ {
+ DataContext = new EditorViewModel(Name, clipCmdCommandHandler)
+ };
+
+ await editorWindow.ShowDialog(mainWindow!);
+ clipCmdCommandHandler.SaveCommands();
+ }
+}
\ No newline at end of file
diff --git a/src/ClipCMD/ViewModels/EditorMessageViewModel.cs b/src/ClipCMD/ViewModels/EditorMessageViewModel.cs
new file mode 100644
index 0000000..cd70b7c
--- /dev/null
+++ b/src/ClipCMD/ViewModels/EditorMessageViewModel.cs
@@ -0,0 +1,10 @@
+using Avalonia.Media;
+
+namespace ClipCmd.ViewModels;
+
+internal class EditorMessageViewModel(string message, IBrush color)
+{
+ public string Message { get; } = message;
+
+ public IBrush Color { get; } = color;
+}
\ No newline at end of file
diff --git a/src/ClipCMD/ViewModels/EditorViewModel.cs b/src/ClipCMD/ViewModels/EditorViewModel.cs
new file mode 100644
index 0000000..30aa479
--- /dev/null
+++ b/src/ClipCMD/ViewModels/EditorViewModel.cs
@@ -0,0 +1,35 @@
+using ClipCmd.Utilities;
+
+using System.Collections.ObjectModel;
+
+namespace ClipCmd.ViewModels;
+
+internal class EditorViewModel : ViewModelBase
+{
+ private readonly ClipCmdCommandHandler clipCmdCommandHandler;
+
+ public string Title => $"ClipCMD Editor - {Name}";
+
+ public string Name { get; }
+
+ public string Script
+ {
+ get => clipCmdCommandHandler.Commands[Name].Script;
+ set => clipCmdCommandHandler.Commands[Name].Script = value;
+ }
+
+ public ObservableCollection Messages { get; } = [];
+
+ public EditorViewModel(string name, ClipCmdCommandHandler clipCmdCommandHandler)
+ {
+ Name = name;
+ this.clipCmdCommandHandler = clipCmdCommandHandler;
+ }
+
+ // Only used for the designer
+ public EditorViewModel()
+ {
+ Name = "Test";
+ clipCmdCommandHandler = new ClipCmdCommandHandler(new());
+ }
+}
\ No newline at end of file
diff --git a/src/ClipCMD/ViewModels/InputDialogViewModel.cs b/src/ClipCMD/ViewModels/InputDialogViewModel.cs
new file mode 100644
index 0000000..1d44928
--- /dev/null
+++ b/src/ClipCMD/ViewModels/InputDialogViewModel.cs
@@ -0,0 +1,18 @@
+using DialogHostAvalonia;
+
+using ReactiveUI;
+
+using System.Windows.Input;
+
+namespace ClipCmd.ViewModels;
+
+internal class InputDialogViewModel(string title, string defaultValue = "") : ViewModelBase
+{
+ public string Title { get; set; } = title;
+
+ public string Value { get; set; } = defaultValue;
+
+ public ICommand OkCommand => ReactiveCommand.Create(() => DialogHost.GetDialogSession(null)!.Close(Value));
+
+ public ICommand CancelCommand => ReactiveCommand.Create(() => DialogHost.GetDialogSession(null)!.Close(null));
+}
\ No newline at end of file
diff --git a/src/ClipCMD/ViewModels/MainViewModel.cs b/src/ClipCMD/ViewModels/MainViewModel.cs
index b3b010f..9362d0b 100644
--- a/src/ClipCMD/ViewModels/MainViewModel.cs
+++ b/src/ClipCMD/ViewModels/MainViewModel.cs
@@ -1,12 +1,22 @@
using ClipCmd.Models;
using ClipCmd.Utilities;
+using DialogHostAvalonia;
+
using ReactiveUI;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Input;
+
namespace ClipCmd.ViewModels;
public class MainViewModel : ViewModelBase
{
+ private readonly ClipCmdCommandHandler clipCmdCommandHandler;
+
+ public List Commands => [.. clipCmdCommandHandler.Commands.Keys.Select(x => new ClipCmdCommandItemViewModel(x, clipCmdCommandHandler))];
+
public bool AutoTypeModeEnabled
{
get => Settings.Current.Mode == ClipCmdMode.AutoType;
@@ -31,12 +41,12 @@ public class MainViewModel : ViewModelBase
}
}
- public int AutoTypeDelay
+ public int? AutoTypeDelay
{
get => Settings.Current.AutoTypeDelay;
set
{
- Settings.Current.AutoTypeDelay = value;
+ Settings.Current.AutoTypeDelay = value ?? 1;
this.RaisePropertyChanged();
}
}
@@ -71,11 +81,65 @@ public class MainViewModel : ViewModelBase
}
}
- public MainViewModel(ClipCmdCommandHandler clipCmdCommandHandler)
+ public string CommandArgsSeperator
{
+ get => Settings.Current.CommandArgsSeperator;
+ set
+ {
+ value = value.Replace(Settings.Current.CommandArgsSeperator, string.Empty);
+
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ value = Settings.Current.CommandArgsSeperator;
+ }
+
+ if (value.Length > 1)
+ {
+ value = value[..1];
+ }
+
+ Settings.Current.CommandArgsSeperator = value;
+ this.RaisePropertyChanged();
+ }
}
+ public ICommand AddCommand => ReactiveCommand.Create(Add);
+
+ public MainViewModel(ClipCmdCommandHandler clipCmdCommandHandler)
+ {
+ this.clipCmdCommandHandler = clipCmdCommandHandler;
+
+ clipCmdCommandHandler.Commands.CollectionChanged += (sender, e) =>
+ {
+ this.RaisePropertyChanged(nameof(Commands));
+ };
+ }
+
+ // Only used for the designer
public MainViewModel()
{
+ clipCmdCommandHandler = new ClipCmdCommandHandler(new());
+ }
+
+ private async void Add()
+ {
+ string? name = await DialogHost.Show(new InputDialogViewModel("Enter command name:")) as string;
+ name = name?.Trim();
+
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ return;
+ }
+
+ int counter = 0;
+ string originalName = name;
+
+ while (clipCmdCommandHandler.Commands.ContainsKey(name))
+ {
+ name = $"{originalName} ({++counter})";
+ }
+
+ clipCmdCommandHandler.Commands.Add(name, new ClipCmdCommand(@$"Write-Output ""{name} command"""));
+ clipCmdCommandHandler.SaveCommands();
}
}
\ No newline at end of file
diff --git a/src/ClipCMD/Views/EditorWindow.axaml b/src/ClipCMD/Views/EditorWindow.axaml
new file mode 100644
index 0000000..fc5b5ce
--- /dev/null
+++ b/src/ClipCMD/Views/EditorWindow.axaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ClipCMD/Views/EditorWindow.axaml.cs b/src/ClipCMD/Views/EditorWindow.axaml.cs
new file mode 100644
index 0000000..c2483af
--- /dev/null
+++ b/src/ClipCMD/Views/EditorWindow.axaml.cs
@@ -0,0 +1,65 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+
+using AvaloniaEdit;
+using AvaloniaEdit.TextMate;
+
+using ClipCmd.ViewModels;
+
+using System;
+using System.Diagnostics;
+using System.Management.Automation.Language;
+
+using TextMateSharp.Grammars;
+
+namespace ClipCmd.Views;
+
+public partial class EditorWindow : Window
+{
+ public EditorWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void Window_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+ EditorViewModel editorViewModel = DataContext as EditorViewModel ?? throw new InvalidOperationException("DataContext is not EditorViewModel");
+
+ TextEditor textEditor = this.FindControl("Editor")!;
+
+ textEditor.Text = editorViewModel.Script;
+
+ textEditor.TextChanged += (s, e) =>
+ {
+ editorViewModel.Script = textEditor.Text;
+ CheckScript(editorViewModel);
+ };
+
+ RegistryOptions registryOptions = new RegistryOptions(ThemeName.DarkPlus);
+ TextMate.Installation _textMateInstallation = textEditor.InstallTextMate(registryOptions);
+
+ _textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions.GetLanguageByExtension(".ps1").Id));
+
+ CheckScript(editorViewModel);
+ }
+
+ private void CheckScript(EditorViewModel editorViewModel)
+ {
+ _ = Parser.ParseInput(editorViewModel.Script, out _, out ParseError[] parseErrors);
+
+ editorViewModel.Messages.Clear();
+
+ if (parseErrors.Length > 0)
+ {
+ foreach (ParseError parseError in parseErrors)
+ {
+ Debug.WriteLine(parseError.Message + " at line " + parseError.Extent.StartLineNumber + " and column " + parseError.Extent.StartColumnNumber);
+ editorViewModel.Messages.Add(new($"Error: {parseError.Message} at line {parseError.Extent.StartLineNumber} and column {parseError.Extent.StartColumnNumber}", Brushes.Red));
+ }
+ }
+ else
+ {
+ editorViewModel.Messages.Add(new("No errors", Brushes.Green));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ClipCMD/Views/InputDialogView.axaml b/src/ClipCMD/Views/InputDialogView.axaml
new file mode 100644
index 0000000..9f45648
--- /dev/null
+++ b/src/ClipCMD/Views/InputDialogView.axaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ClipCMD/Views/InputDialogView.axaml.cs b/src/ClipCMD/Views/InputDialogView.axaml.cs
new file mode 100644
index 0000000..f4e2b03
--- /dev/null
+++ b/src/ClipCMD/Views/InputDialogView.axaml.cs
@@ -0,0 +1,11 @@
+using Avalonia.Controls;
+
+namespace ClipCmd.Views;
+
+public partial class InputDialogView : UserControl
+{
+ public InputDialogView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/ClipCMD/Views/MainView.axaml b/src/ClipCMD/Views/MainView.axaml
index a6fa839..28a2e0e 100644
--- a/src/ClipCMD/Views/MainView.axaml
+++ b/src/ClipCMD/Views/MainView.axaml
@@ -5,9 +5,10 @@
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
xmlns:i="https://github.com/projektanker/icons.avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
x:Class="ClipCmd.Views.MainView"
x:DataType="vm:MainViewModel"
- Loaded="UserControl_Loaded" Background="{DynamicResource SemiColorBackground0}">
+ Background="{DynamicResource SemiColorBackground0}">
@@ -18,47 +19,85 @@
-
+
+
+
+
-
-
-
-
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
-
+
-
-
-
+
\ No newline at end of file
diff --git a/src/ClipCMD/Views/MainView.axaml.cs b/src/ClipCMD/Views/MainView.axaml.cs
index a525946..de75bce 100644
--- a/src/ClipCMD/Views/MainView.axaml.cs
+++ b/src/ClipCMD/Views/MainView.axaml.cs
@@ -1,13 +1,5 @@
using Avalonia.Controls;
-using AvaloniaEdit;
-using AvaloniaEdit.TextMate;
-
-using System.Diagnostics;
-using System.Management.Automation.Language;
-
-using TextMateSharp.Grammars;
-
namespace ClipCmd.Views;
public partial class MainView : UserControl
@@ -16,32 +8,4 @@ public partial class MainView : UserControl
{
InitializeComponent();
}
-
- private void UserControl_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
- {
- return;
- //First of all you need to have a reference for your TextEditor for it to be used inside AvaloniaEdit.TextMate project.
- TextEditor? textEditor = this.FindControl("TextEditor");
-
- textEditor.TextChanged += (s, e) =>
- {
- _ = Parser.ParseInput(textEditor.Text, out _, out ParseError[] parseErrors);
-
- if (parseErrors.Length > 0)
- {
- foreach (ParseError parseError in parseErrors)
- {
- Debug.WriteLine(parseError.Message + " at line " + parseError.Extent.StartLineNumber + " and column " + parseError.Extent.StartColumnNumber);
- }
- }
- };
- RegistryOptions registryOptions = new RegistryOptions(ThemeName.DarkPlus);
-
- //Initial setup of TextMate.
- TextMate.Installation _textMateInstallation = textEditor.InstallTextMate(registryOptions);
-
- //Here we are getting the language by the extension and right after that we are initializing grammar with this language.
- //And that's all 😀, you are ready to use AvaloniaEdit with syntax highlighting!
- _textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions.GetLanguageByExtension(".ps1").Id));
- }
}
\ No newline at end of file
diff --git a/src/ClipCMD/Views/MainWindow.axaml b/src/ClipCMD/Views/MainWindow.axaml
index 4993950..4e81e1c 100644
--- a/src/ClipCMD/Views/MainWindow.axaml
+++ b/src/ClipCMD/Views/MainWindow.axaml
@@ -3,10 +3,12 @@
xmlns:vm="using:ClipCmd.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:views="clr-namespace:ClipCmd.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ClipCmd.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="ClipCmd" Width="800" Height="450">
+
\ No newline at end of file