mirror of
https://github.com/Stone-Red-Code/ClipCMD.git
synced 2026-09-04 17:06:09 +02:00
Implement most features the old app had
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
|
||||
xmlns:local="using:ClipCmd"
|
||||
x:Class="ClipCmd.App"
|
||||
RequestedThemeVariant="Default">
|
||||
@@ -16,6 +17,7 @@
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<dialogHostAvalonia:DialogHostStyles />
|
||||
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -37,6 +37,7 @@ public partial class App : Application
|
||||
desktop.MainWindow.Closing += (sender, e) =>
|
||||
{
|
||||
Settings.SaveSettings();
|
||||
clipCmdCommandHandler.SaveCommands();
|
||||
};
|
||||
|
||||
clipCmdCommandHandler.Start();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
||||
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.6" />
|
||||
<PackageReference Include="DialogHost.Avalonia" Version="0.7.7" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.8.0" />
|
||||
@@ -30,4 +31,10 @@
|
||||
<PackageReference Include="SharpHook" Version="5.3.3" />
|
||||
<PackageReference Include="Speckle.Material.Icons.Avalonia" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Views\InputDialogView.axaml.cs">
|
||||
<DependentUpon>InputDialogView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -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 = "<Pending>")]
|
||||
// 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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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<string, ClipCmdCommand> commands = new();
|
||||
private string lastText = string.Empty;
|
||||
public AvaloniaDictionary<string, ClipCmdCommand> 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<string, ClipCmdCommand> command in JsonSerializer.Deserialize<ConcurrentDictionary<string, ClipCmdCommand>>(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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<EditorMessageViewModel> 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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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<ClipCmdCommandItemViewModel> 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
|
||||
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ClipCmd.Views.EditorWindow"
|
||||
x:DataType="vm:EditorViewModel"
|
||||
Title="{Binding Title}"
|
||||
Width="800" Height="450"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Loaded="Window_Loaded">
|
||||
<Grid RowDefinitions="3* Auto 1*">
|
||||
<AvaloniaEdit:TextEditor Name="Editor" ShowLineNumbers="True" FontFamily="Cascadia Code,Consolas,Menlo,Monospace" />
|
||||
<Separator Grid.Row="1" Margin="0" />
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<ItemsControl ItemsSource="{Binding Messages}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Label Content="{Binding Message}" Foreground="{Binding Color}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -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<TextEditor>("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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
|
||||
xmlns:i="https://github.com/projektanker/icons.avalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="ClipCmd.Views.InputDialogView"
|
||||
x:DataType="vm:InputDialogViewModel"
|
||||
MinWidth="300"
|
||||
MinHeight="100"
|
||||
Background="{DynamicResource SemiColorBackground0}">
|
||||
|
||||
<UserControl.Styles>
|
||||
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
|
||||
</UserControl.Styles>
|
||||
|
||||
<StackPanel Spacing="10">
|
||||
<Label Content="{Binding Title}" />
|
||||
<TextBox VerticalContentAlignment="Center" Text="{Binding Value}" />
|
||||
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="Ok" Width="80" HorizontalContentAlignment="Center" Command="{Binding OkCommand}" />
|
||||
<Button Content="Cancel" Width="80" HorizontalContentAlignment="Center" Command="{Binding CancelCommand}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace ClipCmd.Views;
|
||||
|
||||
public partial class InputDialogView : UserControl
|
||||
{
|
||||
public InputDialogView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -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}">
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
@@ -18,47 +19,85 @@
|
||||
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
|
||||
</UserControl.Styles>
|
||||
|
||||
<Grid RowDefinitions="Auto Auto Auto Auto Auto Auto" ColumnDefinitions="Auto * Auto" Margin="10">
|
||||
<dialogHost:DialogHost CloseOnClickAway="False" DisableOpeningAnimation="True" Background="{DynamicResource SemiColorBackground0}">
|
||||
<dialogHost:DialogHost.DialogContent>
|
||||
<!-- put your dialog content here-->
|
||||
</dialogHost:DialogHost.DialogContent>
|
||||
|
||||
<Grid RowDefinitions="Auto * Auto" VerticalAlignment="Stretch">
|
||||
<TextBox Grid.Row="0" MaxLength="5" InnerLeftContent="Prefix:" Watermark="none" Text="{Binding Prefix}" />
|
||||
<TextBox Grid.Row="2" MaxLength="5" InnerLeftContent="Suffix:" Watermark="none" Text="{Binding Suffix}" />
|
||||
</Grid>
|
||||
<Grid RowDefinitions="Auto Auto Auto *" ColumnDefinitions="Auto * Auto" Margin="10">
|
||||
|
||||
<Label Grid.Column="1" Content="ClipCMD" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" />
|
||||
<Grid RowDefinitions="Auto * Auto * Auto" VerticalAlignment="Stretch">
|
||||
<TextBox Grid.Row="0" MaxLength="5" InnerLeftContent="Prefix:" Watermark="none" Text="{Binding Prefix}" />
|
||||
<TextBox Grid.Row="2" MaxLength="5" InnerLeftContent="Suffix:" Watermark="none" Text="{Binding Suffix}" />
|
||||
<TextBox Grid.Row="4" MaxLength="2" InnerLeftContent="Args seperator:" Text="{Binding CommandArgsSeperator}" />
|
||||
</Grid>
|
||||
|
||||
<Grid RowDefinitions="Auto Auto Auto Auto Auto" ColumnDefinitions="100 20 100" Grid.Column="2">
|
||||
<Label Content="Mode" />
|
||||
<RadioButton Grid.Row="1" VerticalAlignment="Center" Content="Clipboard" IsChecked="{Binding ClipboardModeEnabled}" />
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Content="Auto Paste" IsEnabled="{Binding ClipboardModeEnabled}" IsChecked="{Binding AutoPaste}" />
|
||||
<Separator Grid.Row="2" Grid.ColumnSpan="3" VerticalAlignment="Center" />
|
||||
<RadioButton Grid.Row="3" VerticalAlignment="Center" Content="Auto Type" IsChecked="{Binding AutoTypeModeEnabled}" />
|
||||
<NumericUpDown Grid.Row="3" Grid.Column="2" Increment="1" Minimum="0" Maximum="1000" VerticalAlignment="Center" IsEnabled="{Binding AutoTypeModeEnabled}" Value="{Binding AutoTypeDelay}" />
|
||||
</Grid>
|
||||
<Label Grid.Column="1" Content="ClipCMD" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" />
|
||||
|
||||
<Separator Grid.Row="1" Grid.ColumnSpan="3" VerticalAlignment="Center" Margin="0 10" />
|
||||
<Grid RowDefinitions="Auto Auto Auto Auto Auto" ColumnDefinitions="100 20 100" Grid.Column="2">
|
||||
<Label Content="Mode" />
|
||||
<RadioButton Grid.Row="1" VerticalAlignment="Center" Content="Clipboard" IsChecked="{Binding ClipboardModeEnabled}" />
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Content="Auto Paste" IsEnabled="{Binding ClipboardModeEnabled}" IsChecked="{Binding AutoPaste}" />
|
||||
<Separator Grid.Row="2" Grid.ColumnSpan="3" VerticalAlignment="Center" />
|
||||
<RadioButton Grid.Row="3" VerticalAlignment="Center" Content="Auto Type" IsChecked="{Binding AutoTypeModeEnabled}" />
|
||||
<NumericUpDown Grid.Row="3" Grid.Column="2" Increment="1" Minimum="1" Maximum="1000" VerticalAlignment="Center" IsEnabled="{Binding AutoTypeModeEnabled}" Value="{Binding AutoTypeDelay, FallbackValue=1, TargetNullValue=1}" />
|
||||
</Grid>
|
||||
|
||||
<Button Grid.Column="0" Grid.Row="2">
|
||||
<StackPanel Spacing="4" Orientation="Horizontal">
|
||||
<i:Icon Value="fa-plus" />
|
||||
<TextBlock>Add Command</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Separator Grid.Row="1" Grid.ColumnSpan="3" VerticalAlignment="Center" Margin="0 10" />
|
||||
|
||||
<Grid ColumnDefinitions="* 20 *" Grid.Column="2" Grid.Row="2">
|
||||
<Button>
|
||||
<Button Grid.Column="0" Grid.Row="2" Command="{Binding AddCommand}">
|
||||
<StackPanel Spacing="4" Orientation="Horizontal">
|
||||
<i:Icon Value="fa-file-upload" />
|
||||
<TextBlock>Import</TextBlock>
|
||||
<i:Icon Value="fa-plus" />
|
||||
<TextBlock>Add Command</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Column="2">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<i:Icon Value="fa-file-download" />
|
||||
<TextBlock>Export</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Grid ColumnDefinitions="* 20 *" Grid.Column="2" Grid.Row="2">
|
||||
<Button>
|
||||
<StackPanel Spacing="4" Orientation="Horizontal">
|
||||
<i:Icon Value="fa-file-upload" />
|
||||
<TextBlock>Import</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Column="2">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<i:Icon Value="fa-file-download" />
|
||||
<TextBlock>Export</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="3" VerticalScrollBarVisibility="Auto" Margin="0 20 0 0" Theme="{DynamicResource StaticScrollViewer}">
|
||||
<ItemsControl ItemsSource="{Binding Commands}">
|
||||
<!--Use a StackPanel to display all the modules-->
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="10" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
<!--This defines the layout for each item (i.e. each module)-->
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border CornerRadius="3" Background="{DynamicResource SemiColorBackground1}" Padding="10 10">
|
||||
<Grid ColumnDefinitions="* 45 10 45 10 45">
|
||||
<Label Content="{Binding Name}" VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1" Command="{Binding RenameCommand}" HorizontalAlignment="Stretch">
|
||||
<i:Icon Value="fa-edit" />
|
||||
</Button>
|
||||
<Button Grid.Column="3" Command="{Binding EditCommand}" HorizontalAlignment="Stretch">
|
||||
<i:Icon Value="fa-code" />
|
||||
</Button>
|
||||
<Button Grid.Column="5" Command="{Binding RemoveCommand}" HorizontalAlignment="Stretch">
|
||||
<i:Icon Value="fa-trash" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</dialogHost:DialogHost>
|
||||
</UserControl>
|
||||
@@ -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");
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -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">
|
||||
|
||||
<views:MainView />
|
||||
</Window>
|
||||
Reference in New Issue
Block a user