Browse Source

Very questionable refactor

Equbuxu 3 years ago
parent
commit
c8f3793651

+ 1 - 0
Custom.ruleset

@@ -29,6 +29,7 @@
     <Rule Id="SA1122" Action="None" />
     <Rule Id="SA1124" Action="None" />
     <Rule Id="SA1128" Action="None" />
+    <Rule Id="SA1129" Action="None" />
     <Rule Id="SA1130" Action="None" />
     <Rule Id="SA1132" Action="None" />
     <Rule Id="SA1135" Action="None" />

+ 1 - 0
PixiEditor/PixiEditor.csproj

@@ -204,6 +204,7 @@
 			<NoWarn>NU1701</NoWarn>
 		</PackageReference>
 		<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
+		<PackageReference Include="OneOf" Version="3.0.216" />
 		<PackageReference Include="PixiEditor.ColorPicker" Version="3.2.0" />
 		<PackageReference Include="PixiEditor.Parser" Version="2.1.0.2" />
 		<PackageReference Include="PixiEditor.Parser.Skia" Version="2.1.0" />

+ 0 - 250
PixiEditor/ViewModels/CommandSearchViewModel.cs

@@ -1,250 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Commands;
-using PixiEditor.Models.Commands.Search;
-using SkiaSharp;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Text.RegularExpressions;
-using PixiEditor.Models.DataHolders;
-
-namespace PixiEditor.ViewModels
-{
-    public class CommandSearchViewModel : NotifyableObject
-    {
-        private string searchTerm;
-        private SearchResult selectedCommand;
-        private bool invalidColor;
-
-        public string SearchTerm
-        {
-            get => searchTerm;
-            set
-            {
-                if (SetProperty(ref searchTerm, value))
-                {
-                    UpdateSearchResults();
-                }
-            }
-        }
-
-        public SearchResult SelectedResult
-        {
-            get => selectedCommand;
-            set
-            {
-                if (SetProperty(ref selectedCommand, value, out var oldValue))
-                {
-                    if (oldValue != null)
-                    {
-                        oldValue.IsSelected = false;
-                    }
-
-                    if (value != null)
-                    {
-                        value.IsSelected = true;
-                    }
-                }
-            }
-        }
-
-        public bool InvalidColor
-        {
-            get => invalidColor;
-            set => SetProperty(ref invalidColor, value);
-        }
-        
-        public ObservableCollection<SearchResult> Results { get; } = new();
-
-        public CommandSearchViewModel()
-        {
-            UpdateSearchResults();
-        }
-
-        private void UpdateSearchResults()
-        {
-            Results.Clear();
-
-            var recentlyOpened = HandleRecentlyOpened();
-            
-            if (string.IsNullOrWhiteSpace(SearchTerm))
-            {
-                foreach (var result in recentlyOpened)
-                {
-                    Results.Add(result);
-                }
-
-                SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
-                InvalidColor = false;
-                return;
-            }
-
-            var filePath = SearchTerm.Trim(' ', '"', '\'');
-
-            if (filePath.StartsWith("~"))
-            {
-                filePath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), filePath[1..]);
-            }
-
-            HandleFile(filePath);
-            HandleColor();
-            HandleCommands();
-
-            foreach (var result in recentlyOpened)
-            {
-                Results.Add(result);
-            }
-
-            SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
-        }
-
-        private void HandleColor()
-        {
-            if (SearchTerm.StartsWith('#'))
-            {
-                InvalidColor = !SKColor.TryParse(SearchTerm, out var color);
-                
-                if (!InvalidColor)
-                {
-                    Results.Add(new ColorSearchResult(color)
-                    {
-                        SearchTerm = searchTerm
-                    });
-                }
-            }
-            else if (SearchTerm.StartsWith("rgb") || searchTerm.StartsWith("rgba"))
-            {
-                Match match = Regex.Match(SearchTerm, @"rgba?\(? *(?<r>\d{1,3}) *, *(?<g>\d{1,3}) *, *(?<b>\d{1,3})(?: *, *(?<a>\d{1,3}))?");
-
-                if (match.Success)
-                {
-                    ParseRGB(match);
-                }
-                else if (SearchTerm.StartsWith("rgb(") || SearchTerm.StartsWith("rgba("))
-                {
-                    InvalidColor = true;
-                }
-                else
-                {
-                    InvalidColor = false;
-                }
-            }
-            else
-            {
-                InvalidColor = false;
-            }
-
-            void ParseRGB(Match match)
-            {
-                bool invalid = !(
-                    byte.TryParse(match.Groups["r"].ValueSpan, out var r) &
-                    byte.TryParse(match.Groups["g"].ValueSpan, out var g) &
-                    byte.TryParse(match.Groups["b"].ValueSpan, out var b)
-                );
-
-                var aText = match.Groups["a"].Value;
-                
-                if (string.IsNullOrEmpty(aText) || !byte.TryParse(aText, out var a))
-                {
-                    a = 255;
-                }
-                else
-                {
-                    invalid = true;
-                }
-
-                InvalidColor = invalid;
-                
-                if (!InvalidColor)
-                {
-                    Results.Add(new ColorSearchResult(new SKColor(r, g, b, a))
-                    {
-                        SearchTerm = searchTerm
-                    });
-                }
-            }
-        }
-
-        private void HandleCommands()
-        {
-            foreach (var command in CommandController.Current.Commands
-                         .Where(x => x.Description.Contains(SearchTerm, StringComparison.OrdinalIgnoreCase))
-                         .OrderByDescending(x =>
-                             x.Description.Contains($" {SearchTerm} ", StringComparison.OrdinalIgnoreCase))
-                         .Take(12))
-            {
-                Results.Add(
-                    new CommandSearchResult(command)
-                    {
-                        SearchTerm = searchTerm,
-                        Match = Match(command.Description)
-                    });
-            }
-        }
-        
-        private IEnumerable<FileSearchResult> HandleRecentlyOpened()
-        {
-            IEnumerable<RecentlyOpenedDocument> enumerable = ViewModelMain.Current.FileSubViewModel.RecentlyOpened;
-
-            if (!string.IsNullOrWhiteSpace(SearchTerm))
-            {
-                enumerable = enumerable.Where(x => x.FilePath.Contains(searchTerm, StringComparison.OrdinalIgnoreCase));
-            }
-
-            foreach (var file in enumerable)
-            {
-                yield return new FileSearchResult(file.FilePath)
-                {
-                    SearchTerm = searchTerm,
-                    Match = Match(file.FilePath)
-                };
-            }
-        }
-
-        private void HandleFile(string filePath)
-        {
-            if (!Path.IsPathFullyQualified(filePath))
-            {
-                return;
-            }
-
-            GetDirectory(filePath, out var directory, out var name);
-            var files = Directory.EnumerateFiles(directory)
-                .Where(x => SupportedFilesHelper.IsExtensionSupported(Path.GetExtension(x)));
-
-            if (name is not null or "")
-            {
-                files = files.Where(x => x.Contains(name, StringComparison.OrdinalIgnoreCase));
-            }
-
-            foreach (var file in files.Select(x => Path.GetFullPath(x)))
-            {
-                Results.Add(
-                    new FileSearchResult(file)
-                    {
-                        SearchTerm = name,
-                        Match = Match($".../{Path.GetFileName(file)}", name)
-                    });
-            }
-        }
-
-        private Match Match(string text) => Match(text, SearchTerm);
-
-        private Match Match(string text, string searchTerm) =>
-            Regex.Match(text, $"(.*)({Regex.Escape(searchTerm ?? string.Empty)})(.*)", RegexOptions.IgnoreCase);
-
-        private bool GetDirectory(string path, out string directory, out string file)
-        {
-            if (Directory.Exists(path))
-            {
-                directory = path;
-                file = string.Empty;
-                return true;
-            }
-
-            directory = Path.GetDirectoryName(path);
-            file = Path.GetFileName(path);
-
-            return Directory.Exists(directory);
-        }
-    }
-}

+ 104 - 156
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControl.xaml

@@ -1,21 +1,16 @@
-<UserControl
-    x:Class="PixiEditor.Views.UserControls.CommandSearch.CommandSearchControl"
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:local="clr-namespace:PixiEditor.Views.UserControls.CommandSearch"
-    xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-    xmlns:behaves="clr-namespace:PixiEditor.Helpers.Behaviours"
-    xmlns:cmdssearch="clr-namespace:PixiEditor.Models.Commands.Search"
-    xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
-    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
-    xmlns:system="clr-namespace:System;assembly=System.Runtime"
-    mc:Ignorable="d"
-    Foreground="White"
-    d:DesignHeight="450"
-    d:DesignWidth="600"
-    x:Name="uc">
+<UserControl x:Class="PixiEditor.Views.UserControls.CommandSearch.CommandSearchControl"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls.CommandSearch"
+             xmlns:behaves="clr-namespace:PixiEditor.Helpers.Behaviours"
+             xmlns:cmdssearch="clr-namespace:PixiEditor.Models.Commands.Search"
+             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+             mc:Ignorable="d"
+             Foreground="White"
+             d:DesignHeight="450" d:DesignWidth="600"
+             x:Name="uc">
     <Grid x:Name="mainGrid">
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto" />
@@ -23,20 +18,15 @@
             <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
 
-        <TextBox
-            Text="{Binding SearchTerm, ElementName=uc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
-            FontSize="18"
-            Padding="5"
-            x:Name="textBox">
+        <TextBox Text="{Binding SearchTerm, Mode=TwoWay, ElementName=uc, UpdateSourceTrigger=PropertyChanged}" FontSize="18"
+                 Padding="5"
+                 x:Name="textBox">
             <i:Interaction.Behaviors>
-                <behaves:TextBoxFocusBehavior
-                    SelectOnMouseClick="True" />
+                <behaves:TextBoxFocusBehavior SelectOnMouseClick="True" />
                 <behaves:GlobalShortcutFocusBehavior />
             </i:Interaction.Behaviors>
             <TextBox.Style>
-                <Style
-                    TargetType="TextBox"
-                    BasedOn="{StaticResource DarkTextBoxStyle}">
+                <Style TargetType="TextBox" BasedOn="{StaticResource DarkTextBoxStyle}">
                     <Style.Resources>
                         <Style TargetType="Border">
                             <Setter Property="CornerRadius" Value="5,5,0,0" />
@@ -45,135 +35,93 @@
                 </Style>
             </TextBox.Style>
         </TextBox>
-        <Border
-            Grid.Row="1"
-            BorderThickness="1,0,1,0"
-            BorderBrush="{StaticResource BrighterAccentColor}"
-            Background="{StaticResource AccentColor}">
-            <ScrollViewer
-                VerticalScrollBarVisibility="Auto"
-                HorizontalScrollBarVisibility="Disabled">
-                <ItemsControl
-                    ItemsSource="{Binding Results, ElementName=uc}"
-                    MinWidth="400">
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate DataType="cmdssearch:SearchResult">
-                            <Button
-                                Padding="5"
-                                Height="40"
-                                BorderThickness="0"
-                                Background="Transparent"
-                                Command="{Binding ExecuteCommand}"
-                                CommandParameter="{Binding}"
-                                MouseMove="Button_MouseMove">
-                                <Button.Style>
-                                    <Style TargetType="Button">
-                                        <Setter Property="Template">
-                                            <Setter.Value>
-                                                <ControlTemplate TargetType="Button">
-                                                    <Border>
-                                                        <Border.Style>
-                                                            <Style TargetType="Border">
-                                                                <Style.Triggers>
-                                                                    <DataTrigger
-                                                                        Binding="{Binding IsSelected, Mode=TwoWay}"
-                                                                        Value="False">
-                                                                        <Setter
-                                                                            Property="Background"
-                                                                            Value="Transparent" />
-                                                                    </DataTrigger>
-                                                                    <DataTrigger
-                                                                        Binding="{Binding IsSelected, Mode=TwoWay}"
-                                                                        Value="True">
-                                                                        <Setter
-                                                                            Property="Background"
-                                                                            Value="{StaticResource BrighterAccentColor}" />
-                                                                    </DataTrigger>
-                                                                    <DataTrigger
-                                                                        Binding="{Binding CanExecute}"
-                                                                        Value="False">
-                                                                        <Setter
-                                                                            Property="Background"
-                                                                            Value="Transparent" />
-                                                                    </DataTrigger>
-                                                                </Style.Triggers>
-                                                            </Style>
-                                                        </Border.Style>
-                                                        <ContentPresenter />
-                                                    </Border>
-                                                </ControlTemplate>
-                                            </Setter.Value>
-                                        </Setter>
-                                    </Style>
-                                </Button.Style>
-                                <Button.Resources>
-                                    <Style
-                                        TargetType="TextBlock">
-                                        <Setter
-                                            Property="FontSize"
-                                            Value="16" />
-                                        <Style.Triggers>
-                                            <DataTrigger
-                                                Binding="{Binding CanExecute}"
-                                                Value="True">
-                                                <Setter
-                                                    Property="Foreground"
-                                                    Value="White" />
-                                            </DataTrigger>
-                                            <DataTrigger
-                                                Binding="{Binding CanExecute}"
-                                                Value="False">
-                                                <Setter
-                                                    Property="Foreground"
-                                                    Value="Gray" />
-                                            </DataTrigger>
-                                        </Style.Triggers>
-                                    </Style>
-                                </Button.Resources>
-                                <Grid
-                                    VerticalAlignment="Center"
-                                    x:Name="dp"
-                                    Margin="5,0,10,0">
-                                    <Grid.ColumnDefinitions>
-                                        <ColumnDefinition />
-                                        <ColumnDefinition
-                                            Width="Auto" />
-                                    </Grid.ColumnDefinitions>
-                                    <StackPanel Orientation="Horizontal">
-                                        <Border
-                                            Width="25"
-                                            Margin="0,0,5,0"
-                                            Padding="1">
-                                            <Image
-                                                HorizontalAlignment="Center"
-                                                Source="{Binding Icon}" />
-                                        </Border>
-                                        <TextBlock
-                                            VerticalAlignment="Center"
-                                            behaves:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}" />
-                                    </StackPanel>
-                                    <TextBlock
-                                        Grid.Column="1"
-                                        VerticalAlignment="Center"
-                                        HorizontalAlignment="Right"
-                                        Text="{Binding Shortcut}" />
-                                </Grid>
-                            </Button>
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </ScrollViewer>
+        <Border Grid.Row="1" BorderThickness="1,0,1,0" BorderBrush="{StaticResource BrighterAccentColor}"
+                Background="{StaticResource AccentColor}">
+            <Grid>
+                <TextBlock Text="{Binding Warnings, ElementName=uc}" TextAlignment="Center" Foreground="Gray" Margin="0,5,0,0"
+                           Visibility="{Binding HasWarnings, Converter={BoolToVisibilityConverter}, ElementName=uc}"/>
+                <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
+                    <ItemsControl ItemsSource="{Binding Results, ElementName=uc}" MinWidth="400">
+                        <ItemsControl.ItemTemplate>
+                            <DataTemplate DataType="cmdssearch:SearchResult">
+                                <Button Padding="5" Height="40" BorderThickness="0" Background="Transparent"
+                                        Command="{Binding ExecuteCommand}"
+                                        CommandParameter="{Binding}"
+                                        MouseMove="Button_MouseMove">
+                                    <Button.Style>
+                                        <Style TargetType="Button">
+                                            <Setter Property="Template">
+                                                <Setter.Value>
+                                                    <ControlTemplate TargetType="Button">
+                                                        <Border>
+                                                            <Border.Style>
+                                                                <Style TargetType="Border">
+                                                                    <Style.Triggers>
+                                                                        <DataTrigger
+                                                                            Binding="{Binding IsSelected, Mode=TwoWay}"
+                                                                            Value="False">
+                                                                            <Setter Property="Background"
+                                                                                Value="Transparent" />
+                                                                        </DataTrigger>
+                                                                        <DataTrigger
+                                                                            Binding="{Binding IsSelected, Mode=TwoWay}"
+                                                                            Value="True">
+                                                                            <Setter Property="Background"
+                                                                                Value="{StaticResource BrighterAccentColor}" />
+                                                                        </DataTrigger>
+                                                                        <DataTrigger Binding="{Binding CanExecute}"
+                                                                            Value="False">
+                                                                            <Setter Property="Background"
+                                                                                Value="Transparent" />
+                                                                        </DataTrigger>
+                                                                    </Style.Triggers>
+                                                                </Style>
+                                                            </Border.Style>
+                                                            <ContentPresenter />
+                                                        </Border>
+                                                    </ControlTemplate>
+                                                </Setter.Value>
+                                            </Setter>
+                                        </Style>
+                                    </Button.Style>
+                                    <Button.Resources>
+                                        <Style TargetType="TextBlock">
+                                            <Setter Property="FontSize" Value="16" />
+                                            <Style.Triggers>
+                                                <DataTrigger Binding="{Binding CanExecute}" Value="True">
+                                                    <Setter Property="Foreground" Value="White" />
+                                                </DataTrigger>
+                                                <DataTrigger Binding="{Binding CanExecute}" Value="False">
+                                                    <Setter Property="Foreground" Value="Gray" />
+                                                </DataTrigger>
+                                            </Style.Triggers>
+                                        </Style>
+                                    </Button.Resources>
+                                    <Grid VerticalAlignment="Center" x:Name="dp" Margin="5,0,10,0">
+                                        <Grid.ColumnDefinitions>
+                                            <ColumnDefinition />
+                                            <ColumnDefinition Width="Auto" />
+                                        </Grid.ColumnDefinitions>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Border Width="25" Margin="0,0,5,0" Padding="1">
+                                                <Image HorizontalAlignment="Center" Source="{Binding Icon}" />
+                                            </Border>
+                                            <TextBlock VerticalAlignment="Center"
+                                                       behaves:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}" />
+                                        </StackPanel>
+                                        <TextBlock Grid.Column="1" VerticalAlignment="Center"
+                                                   HorizontalAlignment="Right" Text="{Binding Shortcut}" />
+                                    </Grid>
+                                </Button>
+                            </DataTemplate>
+                        </ItemsControl.ItemTemplate>
+                    </ItemsControl>
+                </ScrollViewer>
+            </Grid>
         </Border>
-        <Border
-            Grid.Row="2"
-            BorderThickness="1"
-            BorderBrush="{StaticResource BrighterAccentColor}"
-            CornerRadius="0,0,5,5"
-            Background="{StaticResource AccentColor}">
-            <TextBlock
-                Margin="5"
-                FontSize="16"
-                Text="{Binding SelectedResult.Description, ElementName=uc, FallbackValue=''}" />
+        <Border Grid.Row="2" BorderThickness="1" BorderBrush="{StaticResource BrighterAccentColor}"
+                CornerRadius="0,0,5,5" Background="{StaticResource AccentColor}">
+            <TextBlock Margin="5" FontSize="16" Text="{Binding SelectedResult.Description, ElementName=uc, FallbackValue=''}" />
         </Border>
     </Grid>
 </UserControl>

+ 24 - 2
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControl.xaml.cs

@@ -4,6 +4,7 @@ using PixiEditor.Models.Commands.Search;
 using PixiEditor.Models.DataHolders;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
+using System.Text;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
@@ -22,6 +23,20 @@ public partial class CommandSearchControl : UserControl, INotifyPropertyChanged
         set => SetValue(SearchTermProperty, value);
     }
 
+    private string warnings = "";
+    public string Warnings
+    {
+        get => warnings;
+        set
+        {
+            warnings = value;
+            PropertyChanged?.Invoke(this, new(nameof(Warnings)));
+            PropertyChanged?.Invoke(this, new(nameof(HasWarnings)));
+        }
+    }
+
+    public bool HasWarnings => Warnings != string.Empty;
+
     public event PropertyChangedEventHandler? PropertyChanged;
 
     private SearchResult? selectedResult;
@@ -58,9 +73,14 @@ public partial class CommandSearchControl : UserControl, INotifyPropertyChanged
     private void UpdateSearchResults()
     {
         Results.Clear();
-        List<SearchResult> newResults = CommandSearchControlHelper.ConstructSearchResults(SearchTerm);
+        (List<SearchResult> newResults, List<string> warnings) = CommandSearchControlHelper.ConstructSearchResults(SearchTerm);
         foreach (var result in newResults)
             Results.Add(result);
+        Warnings = warnings.Aggregate(new StringBuilder(), static (builder, item) =>
+        {
+            builder.AppendLine(item);
+            return builder;
+        }).ToString();
         SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
     }
 
@@ -124,6 +144,8 @@ public partial class CommandSearchControl : UserControl, INotifyPropertyChanged
 
     private static void OnSearchTermChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
-        ((CommandSearchControl)d).UpdateSearchResults();
+        CommandSearchControl control = ((CommandSearchControl)d);
+        control.UpdateSearchResults();
+        control.PropertyChanged?.Invoke(control, new PropertyChangedEventArgs(nameof(control.SearchTerm)));
     }
 }

+ 115 - 14
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControlHelper.cs

@@ -1,40 +1,50 @@
-using System.Text.RegularExpressions;
+using OneOf;
+using OneOf.Types;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Commands;
 using PixiEditor.Models.Commands.Search;
 using PixiEditor.ViewModels;
 using SkiaSharp;
+using System.IO;
+using System.Text.RegularExpressions;
 
 namespace PixiEditor.Views.UserControls.CommandSearch;
 
 #nullable enable
 internal static class CommandSearchControlHelper
 {
-    public static List<SearchResult> ConstructSearchResults(string query)
+    public static (List<SearchResult> results, List<string> warnings) ConstructSearchResults(string query)
     {
+        List<SearchResult> newResults = new();
+        List<string> warnings = new();
+
+        warnings.Add("haha warning");
+
         if (string.IsNullOrWhiteSpace(query))
         {
             // show all recently opened
-            return ViewModelMain.Current.FileSubViewModel.RecentlyOpened
+            newResults.AddRange(ViewModelMain.Current.FileSubViewModel.RecentlyOpened
                 .Select(file => (SearchResult)new FileSearchResult(file.FilePath)
                 {
                     SearchTerm = query
-                }).ToList();
+                }));
+            return (newResults, warnings);
         }
 
         var controller = CommandController.Current;
-        List<SearchResult> newResults = new();
 
         // add matching colors
-        if (query.StartsWith('#'))
-        {
-            if (SKColor.TryParse(query, out SKColor color))
+        MaybeParseColor(query).Switch(
+            (SKColor color) =>
             {
                 newResults.Add(new ColorSearchResult(color)
                 {
                     SearchTerm = query
                 });
-            }
-        }
+            },
+            (Error _) => warnings.Add("Invalid color"),
+            static (None _) => { }
+            );
 
         // add matching commands
         newResults.AddRange(
@@ -45,9 +55,12 @@ internal static class CommandSearchControlHelper
                 .Select(command => new CommandSearchResult(command)
                 {
                     SearchTerm = query,
-                    Match = Match(command.Description)
+                    Match = Match(command.Description, query)
                 }));
 
+        // add matching files
+        newResults.AddRange(MaybeParseFilePaths(query));
+
         // add matching recent files
         newResults.AddRange(
             ViewModelMain.Current.FileSubViewModel.RecentlyOpened
@@ -55,11 +68,99 @@ internal static class CommandSearchControlHelper
                 .Select(file => new FileSearchResult(file.FilePath)
                 {
                     SearchTerm = query,
-                    Match = Match(file.FilePath)
+                    Match = Match(file.FilePath, query)
                 }));
 
-        Match Match(string text) => Regex.Match(text, $"(.*)({Regex.Escape(query)})(.*)", RegexOptions.IgnoreCase);
+        return (newResults, warnings);
+    }
+
+    private static Match Match(string text, string searchTerm) =>
+            Regex.Match(text, $"(.*)({Regex.Escape(searchTerm ?? string.Empty)})(.*)", RegexOptions.IgnoreCase);
+
+    private static IEnumerable<SearchResult> MaybeParseFilePaths(string query)
+    {
+        var filePath = query.Trim(' ', '"', '\'');
+
+        if (filePath.StartsWith("~"))
+            filePath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), filePath[1..]);
+
+        if (!Path.IsPathFullyQualified(filePath))
+            return Enumerable.Empty<SearchResult>();
+
+        GetDirectory(filePath, out var directory, out var name);
+        var files = Directory.EnumerateFiles(directory)
+            .Where(x => SupportedFilesHelper.IsExtensionSupported(Path.GetExtension(x)));
+
+        if (name is not (null or ""))
+        {
+            files = files.Where(x => x.Contains(name, StringComparison.OrdinalIgnoreCase));
+        }
+
+        return files
+            .Select(static file => Path.GetFullPath(file))
+            .Select(path => new FileSearchResult(path)
+            {
+                SearchTerm = name,
+                Match = Match($".../{Path.GetFileName(path)}", name ?? "")
+            });
+    }
+
+    private static bool GetDirectory(string path, out string directory, out string file)
+    {
+        if (Directory.Exists(path))
+        {
+            directory = path;
+            file = string.Empty;
+            return true;
+        }
+
+        directory = Path.GetDirectoryName(path) ?? @"C:\";
+        file = Path.GetFileName(path);
+
+        return Directory.Exists(directory);
+    }
+
+    private static OneOf<SKColor, Error, None> MaybeParseColor(string query)
+    {
+        if (query.StartsWith('#'))
+        {
+            if (!SKColor.TryParse(query, out var color))
+                return new Error();
+            return color;
+        }
+        else if (query.StartsWith("rgb") || query.StartsWith("rgba"))
+        {
+            Match match = Regex.Match(query, @"rgba?\(? *(?<r>\d{1,3}) *, *(?<g>\d{1,3}) *, *(?<b>\d{1,3})(?: *, *(?<a>\d{1,3}))?");
+
+            if (match.Success)
+            {
+                var maybeColor = ParseRGB(match);
+                return maybeColor is null ? new Error() : maybeColor.Value;
+            }
+            else if (query.StartsWith("rgb(") || query.StartsWith("rgba("))
+            {
+                return new Error();
+            }
+        }
+        return new None();
+    }
+
+    private static SKColor? ParseRGB(Match match)
+    {
+        bool invalid = !(
+            byte.TryParse(match.Groups["r"].ValueSpan, out var r) &
+            byte.TryParse(match.Groups["g"].ValueSpan, out var g) &
+            byte.TryParse(match.Groups["b"].ValueSpan, out var b)
+        );
+
+        if (invalid)
+            return null;
+
+        var aText = match.Groups["a"].Value;
+        byte a = 255;
+        if (!string.IsNullOrEmpty(aText) && !byte.TryParse(aText, out a))
+            return null;
 
-        return newResults;
+        return new SKColor(r, g, b, a);
     }
 }

+ 0 - 134
PixiEditor/Views/UserControls/CommandSearchControl.xaml

@@ -1,134 +0,0 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.CommandSearchControl"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-             xmlns:local="clr-namespace:PixiEditor.Views.UserControls"
-             xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-             xmlns:behaves="clr-namespace:PixiEditor.Helpers.Behaviours"
-             xmlns:cmdssearch="clr-namespace:PixiEditor.Models.Commands.Search"
-             xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
-             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
-             mc:Ignorable="d"
-             Foreground="White"
-             d:DesignHeight="450" d:DesignWidth="600"
-             x:Name="uc">
-    <Grid DataContext="{DynamicResource viewModel}" x:Name="mainGrid">
-        <Grid.Resources>
-            <ResourceDictionary>
-                <vm:CommandSearchViewModel x:Key="viewModel" />
-            </ResourceDictionary>
-        </Grid.Resources>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="*" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-
-        <TextBox Text="{Binding SearchTerm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="18"
-                 Padding="5"
-                 x:Name="textBox">
-            <i:Interaction.Behaviors>
-                <behaves:TextBoxFocusBehavior SelectOnMouseClick="True" />
-                <behaves:GlobalShortcutFocusBehavior />
-            </i:Interaction.Behaviors>
-            <TextBox.Style>
-                <Style TargetType="TextBox" BasedOn="{StaticResource DarkTextBoxStyle}">
-                    <Style.Resources>
-                        <Style TargetType="Border">
-                            <Setter Property="CornerRadius" Value="5,5,0,0" />
-                        </Style>
-                    </Style.Resources>
-                </Style>
-            </TextBox.Style>
-        </TextBox>
-        <Border Grid.Row="1" BorderThickness="1,0,1,0" BorderBrush="{StaticResource BrighterAccentColor}"
-                Background="{StaticResource AccentColor}">
-            <Grid>
-                <TextBlock Text="Invalid color" TextAlignment="Center" Foreground="Gray" Margin="0,5,0,0"
-                           Visibility="{Binding InvalidColor, Converter={BoolToVisibilityConverter}}"/>
-                <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
-                    <ItemsControl ItemsSource="{Binding Results}" MinWidth="400">
-                        <ItemsControl.ItemTemplate>
-                            <DataTemplate DataType="cmdssearch:SearchResult">
-                                <Button Padding="5" Height="40" BorderThickness="0" Background="Transparent"
-                                        Command="{Binding ExecuteCommand}"
-                                        CommandParameter="{Binding}"
-                                        MouseMove="Button_MouseMove">
-                                    <Button.Style>
-                                        <Style TargetType="Button">
-                                            <Setter Property="Template">
-                                                <Setter.Value>
-                                                    <ControlTemplate TargetType="Button">
-                                                        <Border>
-                                                            <Border.Style>
-                                                                <Style TargetType="Border">
-                                                                    <Style.Triggers>
-                                                                        <DataTrigger
-                                                                            Binding="{Binding IsSelected, Mode=TwoWay}"
-                                                                            Value="False">
-                                                                            <Setter Property="Background"
-                                                                                Value="Transparent" />
-                                                                        </DataTrigger>
-                                                                        <DataTrigger
-                                                                            Binding="{Binding IsSelected, Mode=TwoWay}"
-                                                                            Value="True">
-                                                                            <Setter Property="Background"
-                                                                                Value="{StaticResource BrighterAccentColor}" />
-                                                                        </DataTrigger>
-                                                                        <DataTrigger Binding="{Binding CanExecute}"
-                                                                            Value="False">
-                                                                            <Setter Property="Background"
-                                                                                Value="Transparent" />
-                                                                        </DataTrigger>
-                                                                    </Style.Triggers>
-                                                                </Style>
-                                                            </Border.Style>
-                                                            <ContentPresenter />
-                                                        </Border>
-                                                    </ControlTemplate>
-                                                </Setter.Value>
-                                            </Setter>
-                                        </Style>
-                                    </Button.Style>
-                                    <Button.Resources>
-                                        <Style TargetType="TextBlock">
-                                            <Setter Property="FontSize" Value="16" />
-                                            <Style.Triggers>
-                                                <DataTrigger Binding="{Binding CanExecute}" Value="True">
-                                                    <Setter Property="Foreground" Value="White" />
-                                                </DataTrigger>
-                                                <DataTrigger Binding="{Binding CanExecute}" Value="False">
-                                                    <Setter Property="Foreground" Value="Gray" />
-                                                </DataTrigger>
-                                            </Style.Triggers>
-                                        </Style>
-                                    </Button.Resources>
-                                    <Grid VerticalAlignment="Center" x:Name="dp" Margin="5,0,10,0">
-                                        <Grid.ColumnDefinitions>
-                                            <ColumnDefinition />
-                                            <ColumnDefinition Width="Auto" />
-                                        </Grid.ColumnDefinitions>
-                                        <StackPanel Orientation="Horizontal">
-                                            <Border Width="25" Margin="0,0,5,0" Padding="1">
-                                                <Image HorizontalAlignment="Center" Source="{Binding Icon}" />
-                                            </Border>
-                                            <TextBlock VerticalAlignment="Center"
-                                                       behaves:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}" />
-                                        </StackPanel>
-                                        <TextBlock Grid.Column="1" VerticalAlignment="Center"
-                                                   HorizontalAlignment="Right" Text="{Binding Shortcut}" />
-                                    </Grid>
-                                </Button>
-                            </DataTemplate>
-                        </ItemsControl.ItemTemplate>
-                    </ItemsControl>
-                </ScrollViewer>
-            </Grid>
-        </Border>
-        <Border Grid.Row="2" BorderThickness="1" BorderBrush="{StaticResource BrighterAccentColor}"
-                CornerRadius="0,0,5,5" Background="{StaticResource AccentColor}">
-            <TextBlock Margin="5" FontSize="16" Text="{Binding SelectedResult.Description}" />
-        </Border>
-    </Grid>
-</UserControl>