Enabling StyleCop for folder plugin (#5844)

This commit is contained in:
Clint Rutkas
2020-08-10 13:28:22 -07:00
committed by GitHub
parent 013ffe1626
commit 7bfd0823db
9 changed files with 614 additions and 563 deletions

View File

@@ -1,147 +1,142 @@
using System; // Copyright (c) Microsoft Corporation
using System.Collections.Generic; // The Microsoft Corporation licenses this file to you under the MIT license.
using System.Diagnostics; // See the LICENSE file in the project root for more information.
using System.IO;
using System.Threading.Tasks; using System;
using System.Windows; using System.Collections.Generic;
using Wox.Infrastructure.Logger; using System.Diagnostics;
using Wox.Infrastructure.Image; using System.IO;
using Wox.Plugin.SharedCommands;
using Wox.Plugin;
using System.Reflection; using System.Reflection;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Wox.Infrastructure; using Wox.Infrastructure;
using Wox.Infrastructure.Logger;
using Wox.Plugin;
namespace Microsoft.Plugin.Folder namespace Microsoft.Plugin.Folder
{ {
internal class ContextMenuLoader : IContextMenu internal class ContextMenuLoader : IContextMenu
{ {
private readonly PluginInitContext _context; private readonly PluginInitContext _context;
public ContextMenuLoader(PluginInitContext context) public ContextMenuLoader(PluginInitContext context)
{ {
_context = context; _context = context;
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exception")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exception")]
public List<ContextMenuResult> LoadContextMenus(Result selectedResult) public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{ {
var contextMenus = new List<ContextMenuResult>(); var contextMenus = new List<ContextMenuResult>();
if (selectedResult.ContextData is SearchResult record) if (selectedResult.ContextData is SearchResult record)
{ {
if (record.Type == ResultType.File) if (record.Type == ResultType.File)
{ {
contextMenus.Add(CreateOpenContainingFolderResult(record)); contextMenus.Add(CreateOpenContainingFolderResult(record));
} }
var icoPath = (record.Type == ResultType.File) ? Main.FileImagePath : Main.FolderImagePath; var icoPath = (record.Type == ResultType.File) ? Main.FileImagePath : Main.FolderImagePath;
contextMenus.Add(new ContextMenuResult contextMenus.Add(new ContextMenuResult
{ {
PluginName = Assembly.GetExecutingAssembly().GetName().Name, PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = _context.API.GetTranslation("Microsoft_plugin_folder_copy_path"), Title = _context.API.GetTranslation("Microsoft_plugin_folder_copy_path"),
Glyph = "\xE8C8", Glyph = "\xE8C8",
FontFamily = "Segoe MDL2 Assets", FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.C, AcceleratorKey = Key.C,
AcceleratorModifiers = ModifierKeys.Control, AcceleratorModifiers = ModifierKeys.Control,
Action = (context) => Action = (context) =>
{ {
try try
{ {
Clipboard.SetText(record.FullPath); Clipboard.SetText(record.FullPath);
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
var message = "Fail to set text in clipboard"; var message = "Fail to set text in clipboard";
LogException(message, e); LogException(message, e);
_context.API.ShowMsg(message); _context.API.ShowMsg(message);
return false; return false;
} }
} },
}); });
contextMenus.Add(new ContextMenuResult contextMenus.Add(new ContextMenuResult
{ {
PluginName = Assembly.GetExecutingAssembly().GetName().Name, PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = _context.API.GetTranslation("Microsoft_plugin_folder_open_in_console"), Title = _context.API.GetTranslation("Microsoft_plugin_folder_open_in_console"),
Glyph = "\xE756", Glyph = "\xE756",
FontFamily = "Segoe MDL2 Assets", FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.C, AcceleratorKey = Key.C,
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift, AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
Action = (context) => Action = (context) =>
{ {
try try
{ {
if (record.Type == ResultType.File) if (record.Type == ResultType.File)
{ {
Helper.OpenInConsole(Path.GetDirectoryName(record.FullPath)); Helper.OpenInConsole(Path.GetDirectoryName(record.FullPath));
} }
else else
{ {
Helper.OpenInConsole(record.FullPath); Helper.OpenInConsole(record.FullPath);
} }
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
Log.Exception($"|Microsoft.Plugin.Folder.ContextMenuLoader.LoadContextMenus| Failed to open {record.FullPath} in console, {e.Message}", e); Log.Exception($"|Microsoft.Plugin.Folder.ContextMenuLoader.LoadContextMenus| Failed to open {record.FullPath} in console, {e.Message}", e);
return false; return false;
} }
} },
}); });
} }
return contextMenus; return contextMenus;
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exception")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive, and instead log the exception")]
private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record) private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record)
{ {
return new ContextMenuResult return new ContextMenuResult
{ {
PluginName = Assembly.GetExecutingAssembly().GetName().Name, PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = _context.API.GetTranslation("Microsoft_plugin_folder_open_containing_folder"), Title = _context.API.GetTranslation("Microsoft_plugin_folder_open_containing_folder"),
Glyph = "\xE838", Glyph = "\xE838",
FontFamily = "Segoe MDL2 Assets", FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.E, AcceleratorKey = Key.E,
AcceleratorModifiers = (ModifierKeys.Control | ModifierKeys.Shift), AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
Action = _ => Action = _ =>
{ {
try try
{ {
Process.Start("explorer.exe", $" /select,\"{record.FullPath}\""); Process.Start("explorer.exe", $" /select,\"{record.FullPath}\"");
} }
catch (Exception e) catch (Exception e)
{ {
var message = $"Fail to open file at {record.FullPath}"; var message = $"Fail to open file at {record.FullPath}";
LogException(message, e); LogException(message, e);
_context.API.ShowMsg(message); _context.API.ShowMsg(message);
return false; return false;
} }
return true; return true;
} },
}; };
} }
public static void LogException(string message, Exception e) public static void LogException(string message, Exception e)
{ {
Log.Exception($"|Microsoft.Plugin.Folder.ContextMenu|{message}", e); Log.Exception($"|Microsoft.Plugin.Folder.ContextMenu|{message}", e);
} }
} }
public class SearchResult public enum ResultType
{ {
public string FullPath { get; set; } Volume,
public ResultType Type { get; set; } Folder,
} File,
}
public enum ResultType }
{
Volume,
Folder,
File
}
}

View File

@@ -1,4 +1,8 @@
using System; // Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;

View File

@@ -11,8 +11,8 @@
<RowDefinition Height="50"/> <RowDefinition Height="50"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListView x:Name="lbxFolders" Grid.Row="0" AllowDrop="True" <ListView x:Name="lbxFolders" Grid.Row="0" AllowDrop="True"
Drop="lbxFolders_Drop" Drop="LbxFolders_Drop"
DragEnter="lbxFolders_DragEnter"> DragEnter="LbxFolders_DragEnter">
<ListView.View> <ListView.View>
<GridView> <GridView>
<GridViewColumn Header="{DynamicResource wox_plugin_folder_folder_path}" Width="180"> <GridViewColumn Header="{DynamicResource wox_plugin_folder_folder_path}" Width="180">
@@ -26,9 +26,9 @@
</ListView.View> </ListView.View>
</ListView> </ListView>
<StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal"> <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal">
<Button x:Name="btnDelete" Click="btnDelete_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_delete}"/> <Button x:Name="btnDelete" Click="BtnDelete_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_delete}"/>
<Button x:Name="btnEdit" Click="btnEdit_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_edit}"/> <Button x:Name="btnEdit" Click="BtnEdit_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_edit}"/>
<Button x:Name="btnAdd" Click="btnAdd_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_add}"/> <Button x:Name="btnAdd" Click="BtnAdd_Click" Width="100" Margin="10" Content="{DynamicResource wox_plugin_folder_add}"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,127 +1,127 @@
using System; // Copyright (c) Microsoft Corporation
using System.Collections.Generic; // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Forms; using System.Windows.Forms;
using Wox.Plugin; using Wox.Plugin;
using DataFormats = System.Windows.DataFormats; using DataFormats = System.Windows.DataFormats;
using DragDropEffects = System.Windows.DragDropEffects; using DragDropEffects = System.Windows.DragDropEffects;
using DragEventArgs = System.Windows.DragEventArgs; using DragEventArgs = System.Windows.DragEventArgs;
using MessageBox = System.Windows.MessageBox; using MessageBox = System.Windows.MessageBox;
namespace Microsoft.Plugin.Folder namespace Microsoft.Plugin.Folder
{ {
public partial class FileSystemSettings
public partial class FileSystemSettings {
{ private IPublicAPI _woxAPI;
private IPublicAPI woxAPI; private FolderSettings _settings;
private FolderSettings _settings;
public FileSystemSettings(IPublicAPI woxAPI, FolderSettings settings)
public FileSystemSettings(IPublicAPI woxAPI, FolderSettings settings) {
{ _woxAPI = woxAPI;
this.woxAPI = woxAPI; InitializeComponent();
InitializeComponent(); _settings = settings ?? throw new ArgumentNullException(paramName: nameof(settings));
_settings = settings ?? throw new ArgumentNullException(paramName:nameof(settings)); lbxFolders.ItemsSource = _settings.FolderLinks;
lbxFolders.ItemsSource = _settings.FolderLinks; }
}
private void BtnDelete_Click(object sender, RoutedEventArgs e)
private void btnDelete_Click(object sender, RoutedEventArgs e) {
{ if (lbxFolders.SelectedItem is FolderLink selectedFolder)
var selectedFolder = lbxFolders.SelectedItem as FolderLink; {
if (selectedFolder != null) string msg = string.Format(CultureInfo.InvariantCulture, _woxAPI.GetTranslation("wox_plugin_folder_delete_folder_link"), selectedFolder.Path);
{
string msg = string.Format(CultureInfo.InvariantCulture, woxAPI.GetTranslation("wox_plugin_folder_delete_folder_link"), selectedFolder.Path); if (MessageBox.Show(msg, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
if (MessageBox.Show(msg, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes) _settings.FolderLinks.Remove(selectedFolder);
{ lbxFolders.Items.Refresh();
_settings.FolderLinks.Remove(selectedFolder); }
lbxFolders.Items.Refresh(); }
} else
} {
else string warning = _woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning");
{ MessageBox.Show(warning);
string warning = woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning"); }
MessageBox.Show(warning); }
}
} private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
private void btnEdit_Click(object sender, RoutedEventArgs e) if (lbxFolders.SelectedItem is FolderLink selectedFolder)
{ {
var selectedFolder = lbxFolders.SelectedItem as FolderLink;
if (selectedFolder != null)
{
using (var folderBrowserDialog = new FolderBrowserDialog()) using (var folderBrowserDialog = new FolderBrowserDialog())
{ {
folderBrowserDialog.SelectedPath = selectedFolder.Path; folderBrowserDialog.SelectedPath = selectedFolder.Path;
if (folderBrowserDialog.ShowDialog() == DialogResult.OK) if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{ {
var link = _settings.FolderLinks.First(x => x.Path == selectedFolder.Path); var link = _settings.FolderLinks.First(x => x.Path == selectedFolder.Path);
link.Path = folderBrowserDialog.SelectedPath; link.Path = folderBrowserDialog.SelectedPath;
} }
lbxFolders.Items.Refresh(); lbxFolders.Items.Refresh();
} }
} }
else else
{ {
string warning = woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning"); string warning = _woxAPI.GetTranslation("wox_plugin_folder_select_folder_link_warning");
MessageBox.Show(warning); MessageBox.Show(warning);
} }
} }
private void btnAdd_Click(object sender, RoutedEventArgs e) private void BtnAdd_Click(object sender, RoutedEventArgs e)
{ {
using (var folderBrowserDialog = new FolderBrowserDialog()) using (var folderBrowserDialog = new FolderBrowserDialog())
{ {
if (folderBrowserDialog.ShowDialog() == DialogResult.OK) if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{ {
var newFolder = new FolderLink var newFolder = new FolderLink
{ {
Path = folderBrowserDialog.SelectedPath Path = folderBrowserDialog.SelectedPath,
}; };
_settings.FolderLinks.Add(newFolder); _settings.FolderLinks.Add(newFolder);
} }
lbxFolders.Items.Refresh(); lbxFolders.Items.Refresh();
} }
} }
private void lbxFolders_Drop(object sender, DragEventArgs e) private void LbxFolders_Drop(object sender, DragEventArgs e)
{ {
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (files != null && files.Any()) if (files != null && files.Any())
{ {
foreach (string s in files) foreach (string s in files)
{ {
if (Directory.Exists(s)) if (Directory.Exists(s))
{ {
var newFolder = new FolderLink var newFolder = new FolderLink
{ {
Path = s Path = s,
}; };
_settings.FolderLinks.Add(newFolder); _settings.FolderLinks.Add(newFolder);
} }
lbxFolders.Items.Refresh(); lbxFolders.Items.Refresh();
} }
} }
} }
private void lbxFolders_DragEnter(object sender, DragEventArgs e) private void LbxFolders_DragEnter(object sender, DragEventArgs e)
{ {
if (e.Data.GetDataPresent(DataFormats.FileDrop)) if (e.Data.GetDataPresent(DataFormats.FileDrop))
{ {
e.Effects = DragDropEffects.Link; e.Effects = DragDropEffects.Link;
} }
else else
{ {
e.Effects = DragDropEffects.None; e.Effects = DragDropEffects.None;
} }
} }
} }
} }

View File

@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Microsoft.Plugin.Folder
{
public class FolderSettings
{
[JsonProperty]
public List<FolderLink> FolderLinks { get; } = new List<FolderLink>();
}
}

View File

@@ -1,317 +1,328 @@
using Microsoft.PowerToys.Settings.UI.Lib; // Copyright (c) Microsoft Corporation
using System; // The Microsoft Corporation licenses this file to you under the MIT license.
using System.Collections.Generic; // See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using Wox.Infrastructure; using Microsoft.PowerToys.Settings.UI.Lib;
using Wox.Infrastructure.Storage; using Wox.Infrastructure;
using Wox.Plugin; using Wox.Infrastructure.Storage;
using Wox.Plugin;
namespace Microsoft.Plugin.Folder
{ namespace Microsoft.Plugin.Folder
public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable, IContextMenu {
{ public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable, IContextMenu
public const string FolderImagePath = "Images\\folder.dark.png"; {
public const string FileImagePath = "Images\\file.dark.png"; public const string FolderImagePath = "Images\\folder.dark.png";
public const string DeleteFileFolderImagePath = "Images\\delete.dark.png"; public const string FileImagePath = "Images\\file.dark.png";
public const string CopyImagePath = "Images\\copy.dark.png"; public const string DeleteFileFolderImagePath = "Images\\delete.dark.png";
public const string CopyImagePath = "Images\\copy.dark.png";
private const string _fileExplorerProgramName = "explorer";
private static List<string> _driverNames; private const string _fileExplorerProgramName = "explorer";
private PluginInitContext _context;
private readonly FolderSettings _settings;
private readonly FolderSettings _settings; private readonly PluginJsonStorage<FolderSettings> _storage;
private readonly PluginJsonStorage<FolderSettings> _storage;
private IContextMenu _contextMenuLoader; private static List<string> _driverNames;
private PluginInitContext _context;
public Main()
{ private IContextMenu _contextMenuLoader;
_storage = new PluginJsonStorage<FolderSettings>();
_settings = _storage.Load(); public Main()
} {
_storage = new PluginJsonStorage<FolderSettings>();
public void Save() _settings = _storage.Load();
{
_storage.Save();
}
public Control CreateSettingPanel()
{
return new FileSystemSettings(_context.API, _settings);
}
public void Init(PluginInitContext context)
{
_context = context;
_contextMenuLoader = new ContextMenuLoader(context);
InitialDriverList();
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")] public void Save()
public List<Result> Query(Query query) {
{ _storage.Save();
if(query == null) }
{
throw new ArgumentNullException(paramName: nameof(query)); public Control CreateSettingPanel()
} {
return new FileSystemSettings(_context.API, _settings);
var results = GetUserFolderResults(query); }
string search = query.Search.ToLower(CultureInfo.InvariantCulture); public void Init(PluginInitContext context)
if (!IsDriveOrSharedFolder(search)) {
return results; _context = context;
_contextMenuLoader = new ContextMenuLoader(context);
results.AddRange(QueryInternal_Directory_Exists(query)); InitialDriverList();
// todo why was this hack here?
foreach (var result in results)
{
result.Score += 10;
}
return results;
}
private static bool IsDriveOrSharedFolder(string search)
{
if (search.StartsWith(@"\\", StringComparison.InvariantCulture))
{ // share folder
return true;
}
if (_driverNames != null && _driverNames.Any(search.StartsWith))
{ // normal drive letter
return true;
}
if (_driverNames == null && search.Length > 2 && char.IsLetter(search[0]) && search[1] == ':')
{ // when we don't have the drive letters we can try...
return true; // we don't know so let's give it the possibility
}
return false;
}
private static Result CreateFolderResult(string title, string subtitle, string path, Query query)
{
return new Result
{
Title = title,
IcoPath = path,
SubTitle = "Folder: " + subtitle,
QueryTextDisplay = path,
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path },
Action = c =>
{
Process.Start(_fileExplorerProgramName, path);
return true;
}
};
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")]
private List<Result> GetUserFolderResults(Query query) public List<Result> Query(Query query)
{ {
if(query == null) if (query == null)
{ {
throw new ArgumentNullException(paramName: nameof(query)); throw new ArgumentNullException(paramName: nameof(query));
} }
string search = query.Search.ToLower(CultureInfo.InvariantCulture); var results = GetUserFolderResults(query);
var userFolderLinks = _settings.FolderLinks.Where(
x => x.Nickname.StartsWith(search, StringComparison.OrdinalIgnoreCase)); string search = query.Search.ToLower(CultureInfo.InvariantCulture);
var results = userFolderLinks.Select(item => if (!IsDriveOrSharedFolder(search))
CreateFolderResult(item.Nickname, item.Path, item.Path, query)).ToList(); {
return results; return results;
}
results.AddRange(QueryInternal_Directory_Exists(query));
// todo why was this hack here?
foreach (var result in results)
{
result.Score += 10;
}
return results;
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")] private static bool IsDriveOrSharedFolder(string search)
private static void InitialDriverList() {
{ if (search.StartsWith(@"\\", StringComparison.InvariantCulture))
if (_driverNames == null) { // share folder
{ return true;
_driverNames = new List<string>(); }
var allDrives = DriveInfo.GetDrives();
foreach (DriveInfo driver in allDrives) if (_driverNames != null && _driverNames.Any(search.StartsWith))
{ { // normal drive letter
_driverNames.Add(driver.Name.ToLower(CultureInfo.InvariantCulture).TrimEnd('\\')); return true;
} }
}
} if (_driverNames == null && search.Length > 2 && char.IsLetter(search[0]) && search[1] == ':')
{ // when we don't have the drive letters we can try...
private static readonly char[] _specialSearchChars = new char[] return true; // we don't know so let's give it the possibility
{ }
'?', '*', '>'
return false;
}
private static Result CreateFolderResult(string title, string subtitle, string path, Query query)
{
return new Result
{
Title = title,
IcoPath = path,
SubTitle = "Folder: " + subtitle,
QueryTextDisplay = path,
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path },
Action = c =>
{
Process.Start(_fileExplorerProgramName, path);
return true;
},
};
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")]
private List<Result> GetUserFolderResults(Query query)
{
if (query == null)
{
throw new ArgumentNullException(paramName: nameof(query));
}
string search = query.Search.ToLower(CultureInfo.InvariantCulture);
var userFolderLinks = _settings.FolderLinks.Where(
x => x.Nickname.StartsWith(search, StringComparison.OrdinalIgnoreCase));
var results = userFolderLinks.Select(item =>
CreateFolderResult(item.Nickname, item.Path, item.Path, query)).ToList();
return results;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")]
private static void InitialDriverList()
{
if (_driverNames == null)
{
_driverNames = new List<string>();
var allDrives = DriveInfo.GetDrives();
foreach (DriveInfo driver in allDrives)
{
_driverNames.Add(driver.Name.ToLower(CultureInfo.InvariantCulture).TrimEnd('\\'));
}
}
}
private static readonly char[] _specialSearchChars = new char[]
{
'?', '*', '>',
}; };
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Do not want to change the behavior of the application, but want to enforce static analysis")]
private static List<Result> QueryInternal_Directory_Exists(Query query) private static List<Result> QueryInternal_Directory_Exists(Query query)
{ {
var search = query.Search; var search = query.Search;
var results = new List<Result>(); var results = new List<Result>();
var hasSpecial = search.IndexOfAny(_specialSearchChars) >= 0; var hasSpecial = search.IndexOfAny(_specialSearchChars) >= 0;
string incompleteName = ""; string incompleteName = string.Empty;
if (hasSpecial || !Directory.Exists(search + "\\")) if (hasSpecial || !Directory.Exists(search + "\\"))
{ {
// if folder doesn't exist, we want to take the last part and use it afterwards to help the user // if folder doesn't exist, we want to take the last part and use it afterwards to help the user
// find the right folder. // find the right folder.
int index = search.LastIndexOf('\\'); int index = search.LastIndexOf('\\');
if (index > 0 && index < (search.Length - 1)) if (index > 0 && index < (search.Length - 1))
{ {
incompleteName = search.Substring(index + 1).ToLower(CultureInfo.InvariantCulture); incompleteName = search.Substring(index + 1).ToLower(CultureInfo.InvariantCulture);
search = search.Substring(0, index + 1); search = search.Substring(0, index + 1);
if (!Directory.Exists(search)) if (!Directory.Exists(search))
{ {
return results; return results;
} }
} }
else else
{ {
return results; return results;
} }
} }
else else
{ {
// folder exist, add \ at the end of doesn't exist // folder exist, add \ at the end of doesn't exist
if (!search.EndsWith("\\", StringComparison.InvariantCulture)) if (!search.EndsWith("\\", StringComparison.InvariantCulture))
{ {
search += "\\"; search += "\\";
} }
} }
results.Add(CreateOpenCurrentFolderResult( search)); results.Add(CreateOpenCurrentFolderResult(search));
var searchOption = SearchOption.TopDirectoryOnly; var searchOption = SearchOption.TopDirectoryOnly;
incompleteName += "*"; incompleteName += "*";
// give the ability to search all folder when starting with > // give the ability to search all folder when starting with >
if (incompleteName.StartsWith(">", StringComparison.InvariantCulture)) if (incompleteName.StartsWith(">", StringComparison.InvariantCulture))
{ {
searchOption = SearchOption.AllDirectories; searchOption = SearchOption.AllDirectories;
// match everything before and after search term using supported wildcard '*', ie. *searchterm* // match everything before and after search term using supported wildcard '*', ie. *searchterm*
incompleteName = "*" + incompleteName.Substring(1); incompleteName = "*" + incompleteName.Substring(1);
} }
var folderList = new List<Result>(); var folderList = new List<Result>();
var fileList = new List<Result>(); var fileList = new List<Result>();
try try
{ {
// search folder and add results // search folder and add results
var directoryInfo = new DirectoryInfo(search); var directoryInfo = new DirectoryInfo(search);
var fileSystemInfos = directoryInfo.GetFileSystemInfos(incompleteName, searchOption); var fileSystemInfos = directoryInfo.GetFileSystemInfos(incompleteName, searchOption);
foreach (var fileSystemInfo in fileSystemInfos) foreach (var fileSystemInfo in fileSystemInfos)
{ {
if ((fileSystemInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) continue; if ((fileSystemInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
{
if (fileSystemInfo is DirectoryInfo) continue;
{ }
var folderSubtitleString = fileSystemInfo.FullName;
if (fileSystemInfo is DirectoryInfo)
folderList.Add(CreateFolderResult(fileSystemInfo.Name, folderSubtitleString, fileSystemInfo.FullName, query)); {
} var folderSubtitleString = fileSystemInfo.FullName;
else
{ folderList.Add(CreateFolderResult(fileSystemInfo.Name, folderSubtitleString, fileSystemInfo.FullName, query));
fileList.Add(CreateFileResult(fileSystemInfo.FullName, query)); }
} else
} {
} fileList.Add(CreateFileResult(fileSystemInfo.FullName, query));
catch (Exception e) }
{ }
if (e is UnauthorizedAccessException || e is ArgumentException) }
{ catch (Exception e)
results.Add(new Result { Title = e.Message, Score = 501 }); {
if (e is UnauthorizedAccessException || e is ArgumentException)
return results; {
} results.Add(new Result { Title = e.Message, Score = 501 });
throw; return results;
} }
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection. throw;
return results.Concat(folderList.OrderBy(x => x.Title)).Concat(fileList.OrderBy(x => x.Title)).ToList(); }
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
return results.Concat(folderList.OrderBy(x => x.Title)).Concat(fileList.OrderBy(x => x.Title)).ToList();
} }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alve and instead inform the user of the error")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alve and instead inform the user of the error")]
private static Result CreateFileResult(string filePath, Query query) private static Result CreateFileResult(string filePath, Query query)
{ {
var result = new Result var result = new Result
{ {
Title = Path.GetFileName(filePath), Title = Path.GetFileName(filePath),
SubTitle = "Folder: " + filePath, SubTitle = "Folder: " + filePath,
IcoPath = filePath, IcoPath = filePath,
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, Path.GetFileName(filePath)).MatchData, TitleHighlightData = StringMatcher.FuzzySearch(query.Search, Path.GetFileName(filePath)).MatchData,
Action = c => Action = c =>
{ {
try try
{ {
Process.Start(_fileExplorerProgramName, filePath); Process.Start(_fileExplorerProgramName, filePath);
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show(ex.Message, "Could not start " + filePath); MessageBox.Show(ex.Message, "Could not start " + filePath);
} }
return true; return true;
}, },
ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath } ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath },
}; };
return result; return result;
} }
private static Result CreateOpenCurrentFolderResult(string search) private static Result CreateOpenCurrentFolderResult(string search)
{ {
var firstResult = "Open " + search; var firstResult = "Open " + search;
var folderName = search.TrimEnd('\\').Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None).Last(); var folderName = search.TrimEnd('\\').Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None).Last();
var sanitizedPath = Regex.Replace(search, @"[\/\\]+", "\\"); var sanitizedPath = Regex.Replace(search, @"[\/\\]+", "\\");
// A network path must start with \\ // A network path must start with \\
if (sanitizedPath.StartsWith("\\", StringComparison.InvariantCulture)) if (sanitizedPath.StartsWith("\\", StringComparison.InvariantCulture))
{ {
sanitizedPath = sanitizedPath.Insert(0, "\\"); sanitizedPath = sanitizedPath.Insert(0, "\\");
} }
return new Result return new Result
{ {
Title = firstResult, Title = firstResult,
QueryTextDisplay = search, QueryTextDisplay = search,
SubTitle = $"Folder: Use > to search within the directory. Use * to search for file extensions. Or use both >*.", SubTitle = $"Folder: Use > to search within the directory. Use * to search for file extensions. Or use both >*.",
IcoPath = search, IcoPath = search,
Score = 500, Score = 500,
Action = c => Action = c =>
{ {
Process.Start(_fileExplorerProgramName, sanitizedPath); Process.Start(_fileExplorerProgramName, sanitizedPath);
return true; return true;
} },
}; };
} }
public string GetTranslatedPluginTitle() public string GetTranslatedPluginTitle()
{ {
return _context.API.GetTranslation("wox_plugin_folder_plugin_name"); return _context.API.GetTranslation("wox_plugin_folder_plugin_name");
} }
public string GetTranslatedPluginDescription() public string GetTranslatedPluginDescription()
{ {
return _context.API.GetTranslation("wox_plugin_folder_plugin_description"); return _context.API.GetTranslation("wox_plugin_folder_plugin_description");
} }
public List<ContextMenuResult> LoadContextMenus(Result selectedResult) public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
{ {
return _contextMenuLoader.LoadContextMenus(selectedResult); return _contextMenuLoader.LoadContextMenus(selectedResult);
} }
public void UpdateSettings(PowerLauncherSettings settings) public void UpdateSettings(PowerLauncherSettings settings)
{ {
}
} }
} }
}

View File

@@ -135,5 +135,19 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using Wox.Infrastructure;
using Wox.Infrastructure.Logger;
using Wox.Plugin;
namespace Microsoft.Plugin.Folder
{
public class SearchResult
{
public string FullPath { get; set; }
public ResultType Type { get; set; }
}
}

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Wox.Infrastructure.Storage;
namespace Microsoft.Plugin.Folder
{
public class FolderSettings
{
[JsonProperty]
public List<FolderLink> FolderLinks { get;} = new List<FolderLink>();
}
}