Merge branch 'master' into spelling

This commit is contained in:
Clint Rutkas
2020-11-02 09:57:48 -08:00
committed by GitHub
245 changed files with 2177 additions and 1210 deletions

View File

@@ -225,6 +225,9 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.IO.Abstractions">
<Version>12.2.5</Version>
</PackageReference>
<PackageReference Include="System.Windows.Interactivity.WPF">
<Version>2.0.20525</Version>
</PackageReference>

View File

@@ -66,6 +66,7 @@ namespace ColorPicker.Helpers
saturation = Math.Round(saturation * 100);
lightness = Math.Round(lightness * 100);
// Using InvariantCulture since this is used for color representation
return $"hsl({hue.ToString(CultureInfo.InvariantCulture)}"
+ $", {saturation.ToString(CultureInfo.InvariantCulture)}%"
+ $", {lightness.ToString(CultureInfo.InvariantCulture)}%)";
@@ -84,6 +85,7 @@ namespace ColorPicker.Helpers
saturation = Math.Round(saturation * 100);
value = Math.Round(value * 100);
// Using InvariantCulture since this is used for color representation
return $"hsv({hue.ToString(CultureInfo.InvariantCulture)}"
+ $", {saturation.ToString(CultureInfo.InvariantCulture)}%"
+ $", {value.ToString(CultureInfo.InvariantCulture)}%)";
@@ -103,6 +105,7 @@ namespace ColorPicker.Helpers
yellow = Math.Round(yellow * 100);
blackKey = Math.Round(blackKey * 100);
// Using InvariantCulture since this is used for color representation
return $"cmyk({cyan.ToString(CultureInfo.InvariantCulture)}%"
+ $", {magenta.ToString(CultureInfo.InvariantCulture)}%"
+ $", {yellow.ToString(CultureInfo.InvariantCulture)}%"

View File

@@ -5,22 +5,24 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
namespace ColorPicker.Helpers
{
public static class Logger
{
private static readonly string ApplicationLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker");
private static readonly IFileSystem _fileSystem = new FileSystem();
private static readonly string ApplicationLogPath = _fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker");
static Logger()
{
if (!Directory.Exists(ApplicationLogPath))
if (!_fileSystem.Directory.Exists(ApplicationLogPath))
{
Directory.CreateDirectory(ApplicationLogPath);
_fileSystem.Directory.CreateDirectory(ApplicationLogPath);
}
var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.CurrentCulture) + ".txt");
// Using InvariantCulture since this is used for a log file name
var logFilePath = _fileSystem.Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using ColorPicker.Helpers;
using Microsoft.Win32;
@@ -28,11 +28,13 @@ namespace ColorPicker.Mouse
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Interop object")]
private const int SPIF_SENDCHANGE = 0x02;
private static readonly IFileSystem _fileSystem = new FileSystem();
public static void SetColorPickerCursor()
{
BackupOriginalCursors();
var colorPickerCursorPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ColorPickerCursorName);
var colorPickerCursorPath = _fileSystem.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ColorPickerCursorName);
ChangeCursor(colorPickerCursorPath, ArrowRegistryName);
ChangeCursor(colorPickerCursorPath, IBeamRegistryName);
}

View File

@@ -5,6 +5,7 @@
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
@@ -20,14 +21,14 @@ namespace ColorPicker.Settings
private const int MaxNumberOfRetry = 5;
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Actually, call back is LoadSettingsFromJson")]
private readonly FileSystemWatcher _watcher;
private readonly IFileSystemWatcher _watcher;
private readonly object _loadingSettingsLock = new object();
[ImportingConstructor]
public UserSettings()
{
_settingsUtils = new SettingsUtils(new SystemIOProvider());
_settingsUtils = new SettingsUtils();
ChangeCursor = new SettingItem<bool>(true);
ActivationShortcut = new SettingItem<string>(DefaultActivationShortcut);
CopiedColorRepresentation = new SettingItem<ColorRepresentationType>(ColorRepresentationType.HEX);

View File

@@ -167,7 +167,7 @@ namespace UnitTest_ColorPickerUI.Helpers
{
var color = Color.FromArgb(red, green, blue);
Exception? exception = null;
Exception exception = null;
try
{

View File

@@ -2,20 +2,16 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>UnitTest_ColorPickerUI</RootNamespace>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<LangVersion>8.0</LangVersion>
<OutputType>Library</OutputType>
<Platforms>x64</Platforms>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\..\..\..\x64\Debug\modules\ColorPicker\UnitTest-ColorPickerUI\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\..\..\..\x64\Release\modules\ColorPicker\UnitTest-ColorPickerUI\</OutputPath>
</PropertyGroup>

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@@ -41,6 +42,8 @@ namespace FancyZonesEditor
private const string CrashReportDynamicAssemblyTag = "dynamic assembly doesn't have location";
private const string CrashReportLocationNullTag = "location is null or empty";
private readonly IFileSystem _fileSystem = new FileSystem();
public Settings ZoneSettings { get; }
public App()
@@ -157,6 +160,8 @@ namespace FancyZonesEditor
sb.AppendLine("## " + CrashReportEnvironmentTag);
sb.AppendLine(CrashReportCommandLineTag + Environment.CommandLine);
// Using InvariantCulture since this is used for a timestamp internally
sb.AppendLine(CrashReportTimestampTag + DateTime.Now.ToString(CultureInfo.InvariantCulture));
sb.AppendLine(CrashReportOSVersionTag + Environment.OSVersion.VersionString);
sb.AppendLine(CrashReportIntPtrLengthTag + IntPtr.Size);

View File

@@ -250,6 +250,9 @@
<PackageReference Include="MahApps.Metro">
<Version>2.3.0</Version>
</PackageReference>
<PackageReference Include="System.IO.Abstractions">
<Version>12.2.5</Version>
</PackageReference>
<PackageReference Include="System.Text.Json">
<Version>4.7.2</Version>
</PackageReference>

View File

@@ -166,8 +166,8 @@
<TextBlock Name="windowEditorDialogTitle" Text="{x:Static props:Resources.Custom_Table_Layout}" Style="{StaticResource titleText}" />
<TextBlock Text="{x:Static props:Resources.Note_Custom_Table}" Style="{StaticResource textLabel}" TextWrapping="Wrap" />
<TextBlock Text="{x:Static props:Resources.Name}" Style="{StaticResource textLabel}" />
<TextBox Text="{Binding Name}" Style="{StaticResource textBox}" />
<TextBlock x:Name="customLayoutName" Text="{x:Static props:Resources.Name}" Style="{StaticResource textLabel}" />
<TextBox Text="{Binding Name}" AutomationProperties.LabeledBy="{Binding ElementName=customLayoutName}" Style="{StaticResource textBox}" />
<!--
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
<CheckBox x:Name="showGridSetting" VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="True" Margin="21,4,0,0"/>

View File

@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Text.Json;
using System.Windows;
@@ -201,7 +201,7 @@ namespace FancyZonesEditor.Models
try
{
string jsonString = JsonSerializer.Serialize(jsonObj, options);
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
FileSystem.File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
}
catch (Exception ex)
{

View File

@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Windows;
@@ -237,7 +236,7 @@ namespace FancyZonesEditor.Models
try
{
string jsonString = JsonSerializer.Serialize(jsonObj, options);
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
FileSystem.File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
}
catch (Exception ex)
{

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -29,6 +30,8 @@ namespace FancyZonesEditor.Models
// Manages common properties and base persistence
public abstract class LayoutModel : INotifyPropertyChanged
{
protected static readonly IFileSystem FileSystem = new FileSystem();
// Localizable strings
private const string ErrorMessageBoxTitle = "FancyZones Editor Exception Handler";
private const string ErrorMessageBoxMessage = "Please report the bug to ";
@@ -194,7 +197,7 @@ namespace FancyZonesEditor.Models
try
{
string jsonString = JsonSerializer.Serialize(deletedLayouts, options);
File.WriteAllText(Settings.DeletedCustomZoneSetsTmpFile, jsonString);
FileSystem.File.WriteAllText(Settings.DeletedCustomZoneSetsTmpFile, jsonString);
}
catch (Exception ex)
{
@@ -209,7 +212,7 @@ namespace FancyZonesEditor.Models
try
{
FileStream inputStream = File.Open(Settings.FancyZonesSettingsFile, FileMode.Open);
Stream inputStream = FileSystem.File.Open(Settings.FancyZonesSettingsFile, FileMode.Open);
JsonDocument jsonObject = JsonDocument.Parse(inputStream, options: default);
JsonElement.ArrayEnumerator customZoneSetsEnumerator = jsonObject.RootElement.GetProperty(CustomZoneSetsJsonTag).EnumerateArray();
@@ -437,7 +440,7 @@ namespace FancyZonesEditor.Models
try
{
string jsonString = JsonSerializer.Serialize(zoneSet, options);
File.WriteAllText(Settings.ActiveZoneSetTmpFile, jsonString);
FileSystem.File.WriteAllText(Settings.ActiveZoneSetTmpFile, jsonString);
}
catch (Exception ex)
{

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.IO.Abstractions;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Windows;
@@ -39,6 +40,8 @@ namespace FancyZonesEditor
Debug,
}
private static readonly IFileSystem _fileSystem = new FileSystem();
private static CanvasLayoutModel _blankCustomModel;
private readonly CanvasLayoutModel _focusModel;
private readonly GridLayoutModel _rowsModel;
@@ -137,7 +140,7 @@ namespace FancyZonesEditor
public Settings()
{
string tmpDirPath = Path.GetTempPath();
string tmpDirPath = _fileSystem.Path.GetTempPath();
ActiveZoneSetTmpFile = tmpDirPath + ActiveZoneSetsTmpFileName;
AppliedZoneSetTmpFile = tmpDirPath + AppliedZoneSetsTmpFileName;
@@ -441,9 +444,9 @@ namespace FancyZonesEditor
ActiveZoneSetUUid = NullUuidStr;
JsonElement jsonObject = default(JsonElement);
if (File.Exists(Settings.ActiveZoneSetTmpFile))
if (_fileSystem.File.Exists(Settings.ActiveZoneSetTmpFile))
{
FileStream inputStream = File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Open);
Stream inputStream = _fileSystem.File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Open);
jsonObject = JsonDocument.Parse(inputStream, options: default).RootElement;
inputStream.Close();
UniqueKey = jsonObject.GetProperty(DeviceIdJsonTag).GetString();

View File

@@ -37,7 +37,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";FancyZones" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";FancyZones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -46,7 +46,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";FancyZones_Data_Error" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";FancyZones_Data_Error" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[FancyZones persisted data path not found. Please report the bug to]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -55,7 +55,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";FancyZones_Editor_Launch_Error" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";FancyZones_Editor_Launch_Error" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The FancyZones editor failed to start. Please report the bug to]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -64,7 +64,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";FancyZones_Settings_Load_Error" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";FancyZones_Settings_Load_Error" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Failed to load the FancyZones settings. Default settings will be used.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -73,7 +73,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";FancyZones_Settings_Save_Error" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";FancyZones_Settings_Save_Error" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Failed to save the FancyZones settings. Please retry again later, if the problem persists report the bug to]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -91,7 +91,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Powertoys_FancyZones" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Powertoys_FancyZones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[PowerToys - FancyZones]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -100,7 +100,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Create window layouts to help make multi-tasking easy]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -109,7 +109,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_AppLastZone_MoveWindows" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_AppLastZone_MoveWindows" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Move newly created windows to their last known zone]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -118,7 +118,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_DisplayChange_MoveWindows" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_DisplayChange_MoveWindows" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Keep windows in their zones when the screen resolution changes]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -145,7 +145,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_Move_Window_Across_Monitors" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_Move_Window_Across_Monitors" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Move windows between zones across all monitors when snapping with (Win + Arrow)]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -154,7 +154,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_Move_Windows_Based_On_Position" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_Move_Windows_Based_On_Position" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Move windows based on their position when snapping with (Win + Arrow)]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -172,7 +172,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_Override_Snap_Hotkeys" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_Override_Snap_Hotkeys" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Override Windows Snap hotkeys (Win + Arrow) to move windows between zones]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -190,7 +190,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_ShiftDrag" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_ShiftDrag" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Hold Shift key to activate zones while dragging]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -219,10 +219,13 @@
</Item>
<Item ItemId=";Setting_Description_Use_CursorPos_Editor_StartupScreen" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Follow mouse cursor instead of focus when launching editor in a multi screen environment]]></Val>
<Val><![CDATA[Follow mouse cursor instead of focus when launching editor in a multi-screen environment]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Při spouštění editoru v prostředí s více obrazovkami sledovat ukazatel myši místo fokusu]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Follow mouse cursor instead of focus when launching editor in a multi screen environment]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>
@@ -244,7 +247,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_ZoneSetChange_FlashZones" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_ZoneSetChange_FlashZones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Flash zones when the active FancyZones layout changes]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -253,7 +256,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Description_ZoneSetChange_MoveWindows" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Description_ZoneSetChange_MoveWindows" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[During zone layout changes, windows assigned to a zone will match new size/positions]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -271,7 +274,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Excluded_Apps_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Excluded_Apps_Description" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[To exclude an application from snapping to zones add its name here (one per line). Excluded apps will react to the Windows Snap regardless of all other settings.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -289,7 +292,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Setting_Launch_Editor_Description" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Setting_Launch_Editor_Description" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[To launch the zone editor, select the Edit zones button below or press the zone editor hotkey anytime]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -316,7 +319,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Settings_Highlight_Opacity" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Settings_Highlight_Opacity" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Zone opacity (%)]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -334,7 +337,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Window_Event_Listener_Error" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";Window_Event_Listener_Error" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Failed to install Windows event listener.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">

View File

@@ -69,6 +69,7 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.IO.Abstractions" Version="12.2.5" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;

View File

@@ -170,6 +170,7 @@ namespace ImageResizer.Properties
var result = ((IDataErrorInfo)settings)["JpegQualityLevel"];
// Using InvariantCulture since this is used internally
Assert.Equal(
string.Format(CultureInfo.InvariantCulture, Resources.ValueMustBeBetween, 1, 100),
result);

View File

@@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.IO.Abstractions;
using System.Windows.Media.Imaging;
using Xunit;
@@ -14,6 +14,8 @@ namespace ImageResizer.Test
{
internal static class AssertEx
{
private static readonly IFileSystem _fileSystem = new FileSystem();
public static void All<T>(IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
@@ -24,7 +26,7 @@ namespace ImageResizer.Test
public static void Image(string path, Action<BitmapDecoder> action)
{
using (var stream = File.OpenRead(path))
using (var stream = _fileSystem.File.OpenRead(path))
{
var image = BitmapDecoder.Create(
stream,

View File

@@ -28,6 +28,7 @@ namespace ImageResizer.Views
var timeRemaining = new TimeSpan(hours, minutes, seconds);
var converter = new TimeRemainingConverter();
// Using InvariantCulture since these are internal
var result = converter.Convert(
timeRemaining,
targetType: null,

View File

@@ -69,6 +69,9 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.IO.Abstractions">
<Version>12.2.5</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\interop\interop.vcxproj" />

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using System.Threading.Tasks;
using ImageResizer.Properties;
@@ -14,6 +15,8 @@ namespace ImageResizer.Models
{
public class ResizeBatch
{
private readonly IFileSystem _fileSystem = new FileSystem();
public string DestinationDirectory { get; set; }
public ICollection<string> Files { get; } = new List<string>();
@@ -71,7 +74,7 @@ namespace ImageResizer.Models
catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
{
errors.Add(new ResizeError { File = Path.GetFileName(file), Error = ex.Message });
errors.Add(new ResizeError { File = _fileSystem.Path.GetFileName(file), Error = ex.Message });
}
Interlocked.Increment(ref completed);

View File

@@ -5,6 +5,7 @@
using System;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Windows;
using System.Windows.Media;
@@ -12,11 +13,14 @@ using System.Windows.Media.Imaging;
using ImageResizer.Properties;
using ImageResizer.Utilities;
using Microsoft.VisualBasic.FileIO;
using FileSystem = Microsoft.VisualBasic.FileIO.FileSystem;
namespace ImageResizer.Models
{
internal class ResizeOperation
{
private readonly IFileSystem _fileSystem = new System.IO.Abstractions.FileSystem();
private readonly string _file;
private readonly string _destinationDirectory;
private readonly Settings _settings;
@@ -31,7 +35,7 @@ namespace ImageResizer.Models
public void Execute()
{
string path;
using (var inputStream = File.OpenRead(_file))
using (var inputStream = _fileSystem.File.OpenRead(_file))
{
var decoder = BitmapDecoder.Create(
inputStream,
@@ -87,8 +91,8 @@ namespace ImageResizer.Models
}
path = GetDestinationPath(encoder);
Directory.CreateDirectory(Path.GetDirectoryName(path));
using (var outputStream = File.Open(path, FileMode.CreateNew, FileAccess.Write))
_fileSystem.Directory.CreateDirectory(_fileSystem.Path.GetDirectoryName(path));
using (var outputStream = _fileSystem.File.Open(path, FileMode.CreateNew, FileAccess.Write))
{
encoder.Save(outputStream);
}
@@ -96,13 +100,13 @@ namespace ImageResizer.Models
if (_settings.KeepDateModified)
{
File.SetLastWriteTimeUtc(path, File.GetLastWriteTimeUtc(_file));
_fileSystem.File.SetLastWriteTimeUtc(path, _fileSystem.File.GetLastWriteTimeUtc(_file));
}
if (_settings.Replace)
{
var backup = GetBackupPath();
File.Replace(path, _file, backup, ignoreMetadataErrors: true);
_fileSystem.File.Replace(path, _file, backup, ignoreMetadataErrors: true);
FileSystem.DeleteFile(backup, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
}
}
@@ -179,16 +183,17 @@ namespace ImageResizer.Models
private string GetDestinationPath(BitmapEncoder encoder)
{
var directory = _destinationDirectory ?? Path.GetDirectoryName(_file);
var originalFileName = Path.GetFileNameWithoutExtension(_file);
var directory = _destinationDirectory ?? _fileSystem.Path.GetDirectoryName(_file);
var originalFileName = _fileSystem.Path.GetFileNameWithoutExtension(_file);
var supportedExtensions = encoder.CodecInfo.FileExtensions.Split(',');
var extension = Path.GetExtension(_file);
var extension = _fileSystem.Path.GetExtension(_file);
if (!supportedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
extension = supportedExtensions.FirstOrDefault();
}
// Using CurrentCulture since this is user facing
var fileName = string.Format(
CultureInfo.CurrentCulture,
_settings.FileNameFormat,
@@ -198,11 +203,11 @@ namespace ImageResizer.Models
_settings.SelectedSize.Height,
encoder.Frames[0].PixelWidth,
encoder.Frames[0].PixelHeight);
var path = Path.Combine(directory, fileName + extension);
var path = _fileSystem.Path.Combine(directory, fileName + extension);
var uniquifier = 1;
while (File.Exists(path))
while (_fileSystem.File.Exists(path))
{
path = Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + extension);
path = _fileSystem.Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + extension);
}
return path;
@@ -210,15 +215,15 @@ namespace ImageResizer.Models
private string GetBackupPath()
{
var directory = Path.GetDirectoryName(_file);
var fileName = Path.GetFileNameWithoutExtension(_file);
var extension = Path.GetExtension(_file);
var directory = _fileSystem.Path.GetDirectoryName(_file);
var fileName = _fileSystem.Path.GetFileNameWithoutExtension(_file);
var extension = _fileSystem.Path.GetExtension(_file);
var path = Path.Combine(directory, fileName + ".bak" + extension);
var path = _fileSystem.Path.Combine(directory, fileName + ".bak" + extension);
var uniquifier = 1;
while (File.Exists(path))
while (_fileSystem.File.Exists(path))
{
path = Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + ".bak" + extension);
path = _fileSystem.Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + ".bak" + extension);
}
return path;

View File

@@ -9,7 +9,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using System.Windows.Media.Imaging;
using ImageResizer.Models;
@@ -22,9 +22,11 @@ namespace ImageResizer.Properties
[JsonObject(MemberSerialization.OptIn)]
public sealed partial class Settings : IDataErrorInfo, INotifyPropertyChanged
{
private static readonly IFileSystem _fileSystem = new FileSystem();
// Used to synchronize access to the settings.json file
private static Mutex _jsonMutex = new Mutex();
private static string _settingsPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Microsoft", "PowerToys", "ImageResizer", "settings.json");
private static string _settingsPath = _fileSystem.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Microsoft", "PowerToys", "ImageResizer", "settings.json");
private string _fileNameFormat;
private bool _shrinkOnly;
private int _selectedSizeIndex;
@@ -63,6 +65,7 @@ namespace ImageResizer.Properties
public IEnumerable<ResizeSize> AllSizes { get; set; }
// Using OrdinalIgnoreCase since this is internal and used for comparison with symbols
public string FileNameFormat
=> _fileNameFormat
?? (_fileNameFormat = FileName
@@ -111,6 +114,7 @@ namespace ImageResizer.Properties
if (JpegQualityLevel < 1 || JpegQualityLevel > 100)
{
// Using CurrentCulture since this is user facing
return string.Format(CultureInfo.CurrentCulture, Resources.ValueMustBeBetween, 1, 100);
}
@@ -382,25 +386,25 @@ namespace ImageResizer.Properties
jsonData += "}";
// Create directory if it doesn't exist
FileInfo file = new FileInfo(SettingsPath);
IFileInfo file = _fileSystem.FileInfo.FromFileName(SettingsPath);
file.Directory.Create();
// write string to file
File.WriteAllText(SettingsPath, jsonData);
_fileSystem.File.WriteAllText(SettingsPath, jsonData);
_jsonMutex.ReleaseMutex();
}
public void Reload()
{
_jsonMutex.WaitOne();
if (!File.Exists(SettingsPath))
if (!_fileSystem.File.Exists(SettingsPath))
{
_jsonMutex.ReleaseMutex();
Save();
return;
}
string jsonData = File.ReadAllText(SettingsPath);
string jsonData = _fileSystem.File.ReadAllText(SettingsPath);
JObject imageResizerSettings = JObject.Parse(jsonData);
// Replace the { "value": <Value> } with <Value> to match the Settings object format

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.Collections.Generic;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Documents;
namespace ImageResizer.Views
{
public class AccessibleHyperlink : Hyperlink
{
public AutomationControlType ControlType { get; set; }
protected override AutomationPeer OnCreateAutomationPeer()
{
var peer = new CustomizableHyperlinkAutomationPeer(this);
peer.ControlType = ControlType;
return peer;
}
}
}

View File

@@ -114,18 +114,18 @@
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Column="6" Margin="5,0,0,0" VerticalAlignment="Center">
<Hyperlink Command="{Binding DataContext.RemoveSizeCommand,ElementName=_this}" CommandParameter="{Binding}">
<local:AccessibleHyperlink ControlType="Button" Command="{Binding DataContext.RemoveSizeCommand,ElementName=_this}" CommandParameter="{Binding}">
<Run Text="{x:Static p:Resources.Advanced_DeleteSize}"/>
</Hyperlink>
</local:AccessibleHyperlink>
</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock>
<Hyperlink Command="{Binding AddSizeCommand}">
<local:AccessibleHyperlink ControlType="Button" Command="{Binding AddSizeCommand}">
<Run Text="{x:Static p:Resources.Advanced_CreateSize}"/>
</Hyperlink>
</local:AccessibleHyperlink>
</TextBlock>
</StackPanel>
</TabItem>

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.Windows.Automation.Peers;
using System.Windows.Documents;
namespace ImageResizer.Views
{
public class CustomizableHyperlinkAutomationPeer : HyperlinkAutomationPeer
{
public CustomizableHyperlinkAutomationPeer(Hyperlink owner)
: base(owner)
{
}
public AutomationControlType ControlType { get; set; }
protected override AutomationControlType GetAutomationControlTypeCore()
{
return ControlType;
}
}
}

View File

@@ -133,9 +133,9 @@
<TextBlock VerticalAlignment="Center"
Visibility="{Binding ShowAdvancedSettings, Converter={StaticResource BoolValueConverter}}">
<Hyperlink Command="{Binding ShowAdvancedCommand}">
<local:AccessibleHyperlink ControlType="Button" Command="{Binding ShowAdvancedCommand}">
<Run Text="{x:Static p:Resources.Input_ShowAdvanced}"/>
</Hyperlink>
</local:AccessibleHyperlink>
</TextBlock>
<Button Grid.Column="1"

View File

@@ -68,6 +68,7 @@ namespace Microsoft.Plugin.Calculator.UnitTests
var engine = new CalculateEngine();
// Act
// Using InvariantCulture since this is internal
var result = engine.Interpret(input, CultureInfo.InvariantCulture);
// Assert
@@ -84,6 +85,7 @@ namespace Microsoft.Plugin.Calculator.UnitTests
var engine = new CalculateEngine();
// Act
// Using InvariantCulture since this is internal
var result = engine.Interpret(input, CultureInfo.InvariantCulture);
// Assert
@@ -140,6 +142,7 @@ namespace Microsoft.Plugin.Calculator.UnitTests
var engine = new CalculateEngine();
// Act
// Using InvariantCulture since this is internal
var result = engine.Interpret(input, CultureInfo.InvariantCulture);
// Assert
@@ -158,6 +161,7 @@ namespace Microsoft.Plugin.Calculator.UnitTests
var engine = new CalculateEngine();
// Act
// Using InvariantCulture since this is internal
var result = engine.Interpret(input, CultureInfo.InvariantCulture);
// Assert

View File

@@ -15,6 +15,7 @@ namespace Microsoft.Plugin.Calculator
public CalculateResult Interpret(string input)
{
// Using CurrentCulture this is user facing
return Interpret(input, CultureInfo.CurrentCulture);
}

View File

@@ -35,6 +35,7 @@ namespace Microsoft.Plugin.Calculator
try
{
// Using CurrentUICulture since this is user facing
var result = CalculateEngine.Interpret(query.Search, CultureInfo.CurrentUICulture);
// This could happen for some incorrect queries, like pi(2)

View File

@@ -27,6 +27,7 @@ namespace Microsoft.Plugin.Calculator
return new Result
{
// Using CurrentCulture since this is user facing
Title = roundedResult?.ToString(CultureInfo.CurrentCulture),
IcoPath = iconPath,
Score = 300,
@@ -45,6 +46,7 @@ namespace Microsoft.Plugin.Calculator
{
try
{
// Using CurrentUICulture since this is user facing
Clipboard.SetText(roundedResult?.ToString(CultureInfo.CurrentUICulture.NumberFormat));
ret = true;
}

View File

@@ -69,8 +69,10 @@ namespace Microsoft.Plugin.Folder.UnitTests
{
// Setup
var folderHelperMock = new Mock<IFolderHelper>();
// Using Ordinal since this is used with paths
folderHelperMock.Setup(r => r.IsDriveOrSharedFolder(It.IsAny<string>()))
.Returns<string>(s => s.StartsWith("C:", StringComparison.CurrentCultureIgnoreCase));
.Returns<string>(s => s.StartsWith("C:", StringComparison.Ordinal));
var itemResultMock = new Mock<IItemResult>();

View File

@@ -5,11 +5,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Plugin.Folder.Sources;
using Microsoft.Plugin.Folder.Sources.Result;
using Moq;
using NUnit.Framework;
namespace Microsoft.Plugin.Folder.UnitTests
@@ -17,115 +16,45 @@ namespace Microsoft.Plugin.Folder.UnitTests
[TestFixture]
public class InternalQueryFolderTests
{
private static readonly HashSet<string> DirectoryExist = new HashSet<string>()
{
@"c:",
@"c:\",
@"c:\Test\",
@"c:\Test\A\",
@"c:\Test\b\",
};
private static readonly HashSet<string> FilesExist = new HashSet<string>()
{
@"c:\bla.txt",
@"c:\Test\test.txt",
@"c:\Test\more-test.png",
};
private static Mock<IQueryFileSystemInfo> _queryFileSystemInfoMock;
private static IQueryFileSystemInfo _queryFileSystemInfoMock;
private static MockFileSystem _fileSystem;
[SetUp]
public void SetupMock()
{
var queryFileSystemInfoMock = new Mock<IQueryFileSystemInfo>();
queryFileSystemInfoMock.Setup(r => r.Exists(It.IsAny<string>()))
.Returns<string>(path => ContainsDirectory(path));
queryFileSystemInfoMock.Setup(r => r.MatchFileSystemInfo(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
.Returns<string, string, bool>(MatchFileSystemInfo);
_queryFileSystemInfoMock = queryFileSystemInfoMock;
}
// Windows supports C:\\\\\ => C:\
private static bool ContainsDirectory(string path)
{
return DirectoryExist.Contains(TrimDirectoryEnd(path));
}
private static string TrimDirectoryEnd(string path)
{
var trimEnd = path.TrimEnd('\\');
if (path.EndsWith('\\'))
// Note: This mock filesystem adds a 'c:\temp' directory.
_fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>()
{
trimEnd += '\\';
}
{ @"c:\bla.txt", new MockFileData(string.Empty) },
{ @"c:\Test\test.txt", new MockFileData(string.Empty) },
{ @"c:\Test\more-test.png", new MockFileData(string.Empty) },
{ @"c:\Test\A\deep-nested.png", new MockFileData(string.Empty) },
{ @"c:\Test\b\", new MockDirectoryData() },
});
return trimEnd;
}
private static IEnumerable<DisplayFileInfo> MatchFileSystemInfo(string search, string incompleteName, bool isRecursive)
{
Func<string, bool> folderSearchFunc;
Func<string, bool> fileSearchFunc;
switch (isRecursive)
{
case false:
folderSearchFunc = s => s.Equals(search, StringComparison.CurrentCultureIgnoreCase);
var regexSearch = TrimDirectoryEnd(search);
fileSearchFunc = s => Regex.IsMatch(s, $"^{Regex.Escape(regexSearch)}[^\\\\]*$");
break;
case true:
folderSearchFunc = s => s.StartsWith(search, StringComparison.CurrentCultureIgnoreCase);
fileSearchFunc = s => s.StartsWith(search, StringComparison.CurrentCultureIgnoreCase);
break;
}
var directories = DirectoryExist.Where(s => folderSearchFunc(s))
.Select(dir => new DisplayFileInfo()
{
Type = DisplayType.Directory,
FullName = dir,
});
var files = FilesExist.Where(s => fileSearchFunc(s))
.Select(file => new DisplayFileInfo()
{
Type = DisplayType.File,
FullName = file,
});
return directories.Concat(files);
_queryFileSystemInfoMock = new QueryFileSystemInfo(_fileSystem.DirectoryInfo);
}
[Test]
public void Query_ThrowsException_WhenCalledNull()
{
// Setup
var queryInternalDirectory = new QueryInternalDirectory(new FolderSettings(), _queryFileSystemInfoMock.Object);
var queryInternalDirectory = new QueryInternalDirectory(new FolderSettings(), _queryFileSystemInfoMock, _fileSystem.Directory);
// Act & Assert
Assert.Throws<ArgumentNullException>(() => queryInternalDirectory.Query(null).ToArray());
}
[TestCase(@"c", 0, 0, false, Reason = "String empty is nothing")]
[TestCase(@"c:", 1, 1, false, Reason = "Root without \\")]
[TestCase(@"c:\", 1, 1, false, Reason = "Normal root")]
[TestCase(@"c:\Test", 1, 2, false, Reason = "Select yourself")]
[TestCase(@"c:\>", 2, 2, true, Reason = "Max Folder test recursive")]
[TestCase(@"c:\Test>", 2, 2, true, Reason = "2 Folders recursive")]
[TestCase(@"c:\not-exist", 1, 1, false, Reason = "Folder not exist, return root")]
[TestCase(@"c:\not-exist>", 2, 2, true, Reason = "Folder not exist, return root recursive")]
[TestCase(@"c:", 2, 1, false, Reason = "Root without \\")]
[TestCase(@"c:\", 2, 1, false, Reason = "Normal root")]
[TestCase(@"c:\Test", 2, 2, false, Reason = "Select yourself")]
[TestCase(@"c:\not-exist", 2, 1, false, Reason = "Folder not exist, return root")]
[TestCase(@"c:\not-exist\not-exist2", 0, 0, false, Reason = "Folder not exist, return root")]
[TestCase(@"c:\not-exist\not-exist2>", 0, 0, false, Reason = "Folder not exist, return root recursive")]
[TestCase(@"c:\bla.t", 1, 1, false, Reason = "Partial match file")]
[TestCase(@"c:\bla.t", 2, 1, false, Reason = "Partial match file")]
public void Query_WhenCalled(string search, int folders, int files, bool truncated)
{
const int maxFolderSetting = 2;
const int maxFolderSetting = 3;
// Setup
var folderSettings = new FolderSettings()
@@ -134,7 +63,42 @@ namespace Microsoft.Plugin.Folder.UnitTests
MaxFolderResults = maxFolderSetting,
};
var queryInternalDirectory = new QueryInternalDirectory(folderSettings, _queryFileSystemInfoMock.Object);
var queryInternalDirectory = new QueryInternalDirectory(folderSettings, _queryFileSystemInfoMock, _fileSystem.Directory);
// Act
var isDriveOrSharedFolder = queryInternalDirectory.Query(search)
.ToLookup(r => r.GetType());
// Assert
Assert.AreEqual(files, isDriveOrSharedFolder[typeof(FileItemResult)].Count(), "File count doesn't match");
Assert.AreEqual(folders, isDriveOrSharedFolder[typeof(FolderItemResult)].Count(), "folder count doesn't match");
// Always check if there is less than max folders
Assert.LessOrEqual(isDriveOrSharedFolder[typeof(FileItemResult)].Count(), maxFolderSetting, "Files are not limited");
Assert.LessOrEqual(isDriveOrSharedFolder[typeof(FolderItemResult)].Count(), maxFolderSetting, "Folders are not limited");
// Checks if CreateOpenCurrentFolder is displayed
Assert.AreEqual(Math.Min(folders + files, 1), isDriveOrSharedFolder[typeof(CreateOpenCurrentFolderResult)].Count(), "CreateOpenCurrentFolder displaying is incorrect");
Assert.AreEqual(truncated, isDriveOrSharedFolder[typeof(TruncatedItemResult)].Count() == 1, "CreateOpenCurrentFolder displaying is incorrect");
}
[TestCase(@"c:\>", 3, 3, true, Reason = "Max Folder test recursive")]
[TestCase(@"c:\Test>", 3, 3, true, Reason = "2 Folders recursive")]
[TestCase(@"c:\not-exist>", 3, 3, true, Reason = "Folder not exist, return root recursive")]
[TestCase(@"c:\not-exist\not-exist2>", 0, 0, false, Reason = "Folder not exist, return root recursive")]
public void Query_Recursive_WhenCalled(string search, int folders, int files, bool truncated)
{
const int maxFolderSetting = 3;
// Setup
var folderSettings = new FolderSettings()
{
MaxFileResults = maxFolderSetting,
MaxFolderResults = maxFolderSetting,
};
var queryInternalDirectory = new QueryInternalDirectory(folderSettings, _queryFileSystemInfoMock, _fileSystem.Directory);
// Act
var isDriveOrSharedFolder = queryInternalDirectory.Query(search)

View File

@@ -14,6 +14,7 @@
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="12.2.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
@@ -17,6 +17,7 @@ namespace Microsoft.Plugin.Folder
{
internal class ContextMenuLoader : IContextMenu
{
private readonly IFileSystem _fileSystem = new FileSystem();
private readonly PluginInitContext _context;
public ContextMenuLoader(PluginInitContext context)
@@ -76,7 +77,7 @@ namespace Microsoft.Plugin.Folder
{
if (record.Type == ResultType.File)
{
Helper.OpenInConsole(Path.GetDirectoryName(record.FullPath));
Helper.OpenInConsole(_fileSystem.Path.GetDirectoryName(record.FullPath));
}
else
{

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
using System.Windows.Controls;
using ManagedCommon;
@@ -21,9 +22,10 @@ namespace Microsoft.Plugin.Folder
public const string DeleteFileFolderImagePath = "Images\\delete.dark.png";
public const string CopyImagePath = "Images\\copy.dark.png";
private static readonly IFileSystem _fileSystem = new FileSystem();
private static readonly PluginJsonStorage<FolderSettings> _storage = new PluginJsonStorage<FolderSettings>();
private static readonly FolderSettings _settings = _storage.Load();
private static readonly IQueryInternalDirectory _internalDirectory = new QueryInternalDirectory(_settings, new QueryFileSystemInfo());
private static readonly IQueryInternalDirectory _internalDirectory = new QueryInternalDirectory(_settings, new QueryFileSystemInfo(_fileSystem.DirectoryInfo), _fileSystem.Directory);
private static readonly FolderHelper _folderHelper = new FolderHelper(new DriveInformation(), new FolderLinksSettings(_settings));
private static readonly ICollection<IFolderProcessor> _processors = new IFolderProcessor[]

View File

@@ -78,6 +78,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.IO.Abstractions" Version="12.2.5" />
<PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup>

View File

@@ -2,17 +2,6 @@
// 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.Plugin;
using Wox.Plugin.Logger;
namespace Microsoft.Plugin.Folder
{
public class SearchResult

View File

@@ -3,12 +3,10 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.IO;
using Wox.Infrastructure.FileSystemHelper;
namespace Microsoft.Plugin.Folder.Sources
{
public interface IQueryFileSystemInfo : IDirectoryWrapper
public interface IQueryFileSystemInfo
{
IEnumerable<DisplayFileInfo> MatchFileSystemInfo(string search, string incompleteName, bool isRecursive);
}

View File

@@ -4,20 +4,22 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
namespace Microsoft.Plugin.Folder.Sources
{
internal class DriveInformation : IDriveInformation
{
private static readonly IFileSystem _fileSystem = new FileSystem();
private static readonly List<string> DriverNames = InitialDriverList().ToList();
[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 IEnumerable<string> InitialDriverList()
{
var directorySeparatorChar = System.IO.Path.DirectorySeparatorChar;
return DriveInfo.GetDrives()
// Using InvariantCulture since this is internal
var directorySeparatorChar = _fileSystem.Path.DirectorySeparatorChar;
return _fileSystem.DriveInfo.GetDrives()
.Select(driver => driver.Name.ToLower(CultureInfo.InvariantCulture).TrimEnd(directorySeparatorChar));
}

View File

@@ -27,6 +27,7 @@ namespace Microsoft.Plugin.Folder.Sources
throw new ArgumentNullException(paramName: nameof(query));
}
// Using OrdinalIgnoreCase since this is internal
return _folderLinks.FolderLinks()
.Where(x => x.Nickname.StartsWith(query, StringComparison.OrdinalIgnoreCase));
}
@@ -38,7 +39,8 @@ namespace Microsoft.Plugin.Folder.Sources
throw new ArgumentNullException(nameof(search));
}
if (search.StartsWith(@"\\", StringComparison.InvariantCulture))
// Using Ordinal this is internal and we're comparing symbols
if (search.StartsWith(@"\\", StringComparison.Ordinal))
{ // share folder
return true;
}
@@ -48,6 +50,7 @@ namespace Microsoft.Plugin.Folder.Sources
if (driverNames.Any())
{
// Using InvariantCultureIgnoreCase since this is searching for drive names
if (driverNames.Any(dn => search.StartsWith(dn, StringComparison.InvariantCultureIgnoreCase)))
{
// normal drive letter

View File

@@ -2,20 +2,26 @@
// 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.IO;
using System.IO.Abstractions;
using System.Linq;
using Wox.Infrastructure.FileSystemHelper;
namespace Microsoft.Plugin.Folder.Sources
{
public class QueryFileSystemInfo : DirectoryWrapper, IQueryFileSystemInfo
public class QueryFileSystemInfo : IQueryFileSystemInfo
{
private readonly IDirectoryInfoFactory _directoryInfoFactory;
public QueryFileSystemInfo(IDirectoryInfoFactory directoryInfoFactory)
{
_directoryInfoFactory = directoryInfoFactory;
}
public IEnumerable<DisplayFileInfo> MatchFileSystemInfo(string search, string incompleteName, bool isRecursive)
{
// search folder and add results
var directoryInfo = new DirectoryInfo(search);
var directoryInfo = _directoryInfoFactory.FromDirectoryName(search);
var fileSystemInfos = directoryInfo.EnumerateFileSystemInfos(incompleteName, new EnumerationOptions()
{
MatchType = MatchType.Win32,
@@ -30,7 +36,7 @@ namespace Microsoft.Plugin.Folder.Sources
.Select(CreateDisplayFileInfo);
}
private static DisplayFileInfo CreateDisplayFileInfo(FileSystemInfo fileSystemInfo)
private static DisplayFileInfo CreateDisplayFileInfo(IFileSystemInfo fileSystemInfo)
{
return new DisplayFileInfo()
{
@@ -40,9 +46,9 @@ namespace Microsoft.Plugin.Folder.Sources
};
}
private static DisplayType GetDisplayType(FileSystemInfo fileSystemInfo)
private static DisplayType GetDisplayType(IFileSystemInfo fileSystemInfo)
{
if (fileSystemInfo is DirectoryInfo)
if (fileSystemInfo is IDirectoryInfo)
{
return DisplayType.Directory;
}

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using ManagedCommon;
using Microsoft.Plugin.Folder.Sources.Result;
@@ -18,6 +19,7 @@ namespace Microsoft.Plugin.Folder.Sources
{
private readonly FolderSettings _settings;
private readonly IQueryFileSystemInfo _queryFileSystemInfo;
private readonly IDirectory _directory;
private static readonly HashSet<char> SpecialSearchChars = new HashSet<char>
{
@@ -26,10 +28,11 @@ namespace Microsoft.Plugin.Folder.Sources
private static string _warningIconPath;
public QueryInternalDirectory(FolderSettings folderSettings, IQueryFileSystemInfo queryFileSystemInfo)
public QueryInternalDirectory(FolderSettings folderSettings, IQueryFileSystemInfo queryFileSystemInfo, IDirectory directory)
{
_settings = folderSettings;
_queryFileSystemInfo = queryFileSystemInfo;
_directory = directory;
}
private static bool HasSpecialChars(string search)
@@ -47,7 +50,7 @@ namespace Microsoft.Plugin.Folder.Sources
private (string search, string incompleteName) Process(string search)
{
string incompleteName = string.Empty;
if (HasSpecialChars(search) || !_queryFileSystemInfo.Exists($@"{search}\"))
if (HasSpecialChars(search) || !_directory.Exists($@"{search}\"))
{
// if folder doesn't exist, we want to take the last part and use it afterwards to help the user
// find the right folder.
@@ -60,10 +63,11 @@ namespace Microsoft.Plugin.Folder.Sources
}
// Remove everything after the last \ and add *
// Using InvariantCulture since this is internal
incompleteName = search.Substring(index + 1)
.ToLower(CultureInfo.InvariantCulture) + "*";
search = search.Substring(0, index + 1);
if (!_queryFileSystemInfo.Exists(search))
if (!_directory.Exists(search))
{
return default;
}
@@ -71,7 +75,8 @@ namespace Microsoft.Plugin.Folder.Sources
else
{
// folder exist, add \ at the end of doesn't exist
if (!search.EndsWith(@"\", StringComparison.InvariantCulture))
// Using Ordinal since this is internal and is used for a symbol
if (!search.EndsWith(@"\", StringComparison.Ordinal))
{
search += @"\";
}

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using Wox.Infrastructure;
using Wox.Plugin;
@@ -13,17 +13,31 @@ namespace Microsoft.Plugin.Folder.Sources.Result
{
private static readonly IShellAction ShellAction = new ShellAction();
private readonly IPath _path;
public FileItemResult()
: this(new FileSystem().Path)
{
}
private FileItemResult(IPath path)
{
_path = path;
}
public string FilePath { get; set; }
public string Title => Path.GetFileName(FilePath);
public string Title => _path.GetFileName(FilePath);
public string Search { get; set; }
public Wox.Plugin.Result Create(IPublicAPI contextApi)
{
var result = new Wox.Plugin.Result(StringMatcher.FuzzySearch(Search, Path.GetFileName(FilePath)).MatchData)
var result = new Wox.Plugin.Result(StringMatcher.FuzzySearch(Search, _path.GetFileName(FilePath)).MatchData)
{
Title = Title,
// Using CurrentCulture since this is user facing
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_file_result_subtitle, FilePath),
IcoPath = FilePath,
Action = c => ShellAction.Execute(FilePath, contextApi),

View File

@@ -37,6 +37,8 @@ namespace Microsoft.Plugin.Folder.Sources.Result
{
Title = Title,
IcoPath = Path,
// Using CurrentCulture since this is user facing
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_folder_result_subtitle, Subtitle),
QueryTextDisplay = Path,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = Path },

View File

@@ -23,6 +23,8 @@ namespace Microsoft.Plugin.Folder.Sources.Result
{
Title = Properties.Resources.Microsoft_plugin_folder_truncation_warning_title,
QueryTextDisplay = Search,
// Using CurrentCulture since this is user facing
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.Microsoft_plugin_folder_truncation_warning_subtitle, PostTruncationCount, PreTruncationCount),
IcoPath = WarningIconPath,
};

View File

@@ -39,7 +39,8 @@ namespace Microsoft.Plugin.Folder.Sources
var sanitizedPath = Regex.Replace(search, @"[\/\\]+", "\\");
// A network path must start with \\
if (!sanitizedPath.StartsWith("\\", StringComparison.InvariantCulture))
// Using Ordinal since this is internal and used with a symbol
if (!sanitizedPath.StartsWith("\\", StringComparison.Ordinal))
{
return sanitizedPath;
}

View File

@@ -28,6 +28,8 @@ namespace Microsoft.Plugin.Folder
{
Title = Title,
IcoPath = Path,
// Using CurrentCulture since this is user facing
SubTitle = string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_folder_select_folder_result_subtitle, Subtitle),
QueryTextDisplay = Path,
ContextData = new SearchResult { Type = ResultType.Folder, FullPath = Path },

View File

@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
@@ -19,6 +19,8 @@ namespace Microsoft.Plugin.Indexer
{
internal class ContextMenuLoader : IContextMenu
{
private readonly IPath _path = new FileSystem().Path;
private readonly PluginInitContext _context;
public enum ResultType
@@ -41,7 +43,7 @@ namespace Microsoft.Plugin.Indexer
var contextMenus = new List<ContextMenuResult>();
if (selectedResult.ContextData is SearchResult record)
{
ResultType type = Path.HasExtension(record.Path) ? ResultType.File : ResultType.Folder;
ResultType type = _path.HasExtension(record.Path) ? ResultType.File : ResultType.Folder;
if (type == ResultType.File)
{
@@ -95,7 +97,7 @@ namespace Microsoft.Plugin.Indexer
{
if (type == ResultType.File)
{
Helper.OpenInConsole(Path.GetDirectoryName(record.Path));
Helper.OpenInConsole(_path.GetDirectoryName(record.Path));
}
else
{
@@ -147,9 +149,10 @@ namespace Microsoft.Plugin.Indexer
// Function to test if the file can be run as admin
private bool CanFileBeRunAsAdmin(string path)
{
string fileExtension = Path.GetExtension(path);
string fileExtension = _path.GetExtension(path);
foreach (string extension in appExtensions)
{
// Using OrdinalIgnoreCase since this is internal
if (extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
{
return true;

View File

@@ -7,7 +7,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Controls;
@@ -24,6 +24,8 @@ namespace Microsoft.Plugin.Indexer
{
internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable, IDelayedExecutionPlugin
{
private static readonly IFileSystem _fileSystem = new FileSystem();
// This variable contains metadata about the Plugin
private PluginInitContext _context;
@@ -38,7 +40,7 @@ namespace Microsoft.Plugin.Indexer
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(_search);
// To obtain information regarding the drives that are indexed
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection(new RegistryWrapper(), new DriveInfoWrapper());
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection(new RegistryWrapper(), new DriveDetection.DriveInfoWrapper());
// Reserved keywords in oleDB
private readonly string reservedStringPattern = @"^[\/\\\$\%]+$|^.*[<>].*$";
@@ -110,12 +112,14 @@ namespace Microsoft.Plugin.Indexer
foreach (var searchResult in searchResultsList)
{
var path = searchResult.Path;
// Using CurrentCulture since this is user facing
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", Properties.Resources.Microsoft_plugin_indexer_name, searchResult.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", Properties.Resources.Microsoft_plugin_indexer_path, path);
string workingDir = null;
if (_settings.UseLocationAsWorkingDir)
{
workingDir = Path.GetDirectoryName(path);
workingDir = _fileSystem.Path.GetDirectoryName(path);
}
Result r = new Result();
@@ -149,7 +153,7 @@ namespace Microsoft.Plugin.Indexer
r.ContextData = searchResult;
// If the result is a directory, then it's display should show a directory.
if (Directory.Exists(path))
if (_fileSystem.Directory.Exists(path))
{
r.QueryTextDisplay = path;
}

View File

@@ -59,6 +59,7 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
}
// # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
// Using OrdinalIgnoreCase since this is internal and used with symbols
var string_path = ((string)oleDBResult.FieldData[0]).Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
var uri_path = new Uri(string_path);
@@ -89,10 +90,11 @@ namespace Microsoft.Plugin.Indexer.SearchHelper
// convert file pattern if it is not '*'. Don't create restriction for '*' as it includes all files.
if (pattern != "*")
{
pattern = pattern.Replace("*", "%", StringComparison.InvariantCulture);
pattern = pattern.Replace("?", "_", StringComparison.InvariantCulture);
// Using Ordinal since these are internal and used with symbols
pattern = pattern.Replace("*", "%", StringComparison.Ordinal);
pattern = pattern.Replace("?", "_", StringComparison.Ordinal);
if (pattern.Contains("%", StringComparison.InvariantCulture) || pattern.Contains("_", StringComparison.InvariantCulture))
if (pattern.Contains("%", StringComparison.Ordinal) || pattern.Contains("_", StringComparison.Ordinal))
{
queryHelper.QueryWhereRestrictions += " AND System.FileName LIKE '" + pattern + "' ";
}

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Upozornění: Ne všechny jednotky jsou indexované.]]></Val>
<Val><![CDATA[Upozornění: Ne všechny soubory jsou indexované.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Warnung: Nicht alle Laufwerke sind indiziert.]]></Val>
<Val><![CDATA[Warnung: Nicht alle Dateien sind indiziert.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Advertencia: No se indexaron todas las unidades.]]></Val>
<Val><![CDATA[Advertencia: No se indexaron todos los archivos.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[警告: すべてのドライブがインデックス化されているわけではありません。]]></Val>
<Val><![CDATA[警告: すべてのファイルがインデックス化されているわけではありません。]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Waarschuwing: niet alle stations zijn geïndexeerd.]]></Val>
<Val><![CDATA[Waarschuwing: niet alle bestanden zijn geïndexeerd.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Ostrzeżenie: Nie wszystkie dyski są indeksowane.]]></Val>
<Val><![CDATA[Ostrzeżenie: Nie wszystkie pliki są indeksowane.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Внимание! Проиндексированы не все диски.]]></Val>
<Val><![CDATA[Предупреждение: индексируются не все файлы.]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -39,10 +39,13 @@
</Item>
<Item ItemId=";Microsoft_plugin_indexer_drivedetectionwarning" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
<Val><![CDATA[Warning: Not all files are indexed.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[警告: 並非所有磁碟機皆已編製索引。]]></Val>
<Val><![CDATA[警告: 並非所有檔案皆已編製索引。]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Warning: Not all drives are indexed.]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>

View File

@@ -567,6 +567,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Programs
var result = _cmderRunCommand.Result("cmder", string.Empty, mock.Object);
// Assert
// Using Ordinal since this is used internally
Assert.IsTrue(result.Title.Equals(_cmderRunCommand.Name, StringComparison.Ordinal));
Assert.IsFalse(result.Title.Equals(_cmderRunCommand.Description, StringComparison.Ordinal));
}

View File

@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using Microsoft.Plugin.Program.Programs;
using Microsoft.Plugin.Program.Storage;
@@ -209,7 +210,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
FileSystemEventArgs e = new FileSystemEventArgs(WatcherChangeTypes.Created, "directory", path);
// File.ReadAllLines must be mocked for url applications
var mockFile = new Mock<IFileWrapper>();
var mockFile = new Mock<IFile>();
mockFile.Setup(m => m.ReadAllLines(It.IsAny<string>())).Returns(new string[] { "URL=steam://rungameid/1258080", "IconFile=iconFile" });
Win32Program.FileWrapper = mockFile.Object;
@@ -256,7 +257,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
FileSystemEventArgs e = new FileSystemEventArgs(WatcherChangeTypes.Deleted, directory, path);
// File.ReadAllLines must be mocked for url applications
var mockFile = new Mock<IFileWrapper>();
var mockFile = new Mock<IFile>();
mockFile.Setup(m => m.ReadAllLines(It.IsAny<string>())).Returns(new string[] { "URL=steam://rungameid/1258080", "IconFile=iconFile" });
Win32Program.FileWrapper = mockFile.Object;
@@ -279,7 +280,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage
RenamedEventArgs e = new RenamedEventArgs(WatcherChangeTypes.Renamed, directory, newpath, oldpath);
// File.ReadAllLines must be mocked for url applications
var mockFile = new Mock<IFileWrapper>();
var mockFile = new Mock<IFile>();
mockFile.Setup(m => m.ReadAllLines(It.IsAny<string>())).Returns(new string[] { "URL=steam://rungameid/1258080", "IconFile=iconFile" });
Win32Program.FileWrapper = mockFile.Object;

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;

View File

@@ -23,6 +23,7 @@ namespace Microsoft.Plugin.Program
{
for (var i = 1; i < query.Terms.Count; i++)
{
// Using Ordinal since this is internal and used with a symbol
if (!string.Equals(query.Terms[i], DoubleDash, StringComparison.Ordinal))
{
continue;

View File

@@ -2,7 +2,7 @@
// 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.IO;
using System.IO.Abstractions;
namespace Microsoft.Plugin.Program
{
@@ -16,11 +16,13 @@ namespace Microsoft.Plugin.Program
/// </remarks>
public class ProgramSource
{
private static readonly IFileSystem FileSystem = new FileSystem();
private string name;
public string Location { get; set; }
public string Name { get => name ?? new DirectoryInfo(Location).Name; set => name = value; }
public string Name { get => name ?? FileSystem.DirectoryInfo.FromDirectoryName(Location).Name; set => name = value; }
public bool Enabled { get; set; } = true;

View File

@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -19,6 +19,8 @@ namespace Microsoft.Plugin.Program.Programs
[Serializable]
public partial class UWP
{
private static readonly IPath Path = new FileSystem().Path;
public string Name { get; }
public string FullName { get; }
@@ -204,6 +206,7 @@ namespace Microsoft.Plugin.Program.Programs
{
if (obj is UWP uwp)
{
// Using CurrentCultureIgnoreCase since this is used with FamilyName
return FamilyName.Equals(uwp.FamilyName, StringComparison.CurrentCultureIgnoreCase);
}
else
@@ -214,6 +217,7 @@ namespace Microsoft.Plugin.Program.Programs
public override int GetHashCode()
{
// Using CurrentCultureIgnoreCase since this is used with FamilyName
return FamilyName.GetHashCode(StringComparison.CurrentCultureIgnoreCase);
}

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -31,6 +32,10 @@ namespace Microsoft.Plugin.Program.Programs
[Serializable]
public class UWPApplication : IProgram
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
public string AppListEntry { get; set; }
public string UniqueIdentifier { get; set; }
@@ -111,6 +116,7 @@ namespace Microsoft.Plugin.Program.Programs
result.Title = DisplayName;
result.SetTitleHighlightData(StringMatcher.FuzzySearch(query, Name).MatchData);
// Using CurrentCulture since this is user facing
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_name, result.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_path, Package.Location);
result.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
@@ -263,6 +269,8 @@ namespace Microsoft.Plugin.Program.Programs
if (File.Exists(manifest))
{
var file = File.ReadAllText(manifest);
// Using OrdinalIgnoreCase since this is used internally
if (file.Contains("TrustLevel=\"mediumIL\"", StringComparison.OrdinalIgnoreCase))
{
return true;
@@ -276,12 +284,16 @@ namespace Microsoft.Plugin.Program.Programs
internal string ResourceFromPri(string packageFullName, string resourceReference)
{
const string prefix = "ms-resource:";
// Using OrdinalIgnoreCase since this is used internally
if (!string.IsNullOrWhiteSpace(resourceReference) && resourceReference.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
// magic comes from @talynone
// https://github.com/talynone/Wox.Plugin.WindowsUniversalAppLauncher/blob/master/StoreAppLauncher/Helpers/NativeApiHelper.cs#L139-L153
string key = resourceReference.Substring(prefix.Length);
string parsed;
// Using Ordinal/OrdinalIgnorcase since these are used internally
if (key.StartsWith("//", StringComparison.Ordinal))
{
parsed = prefix + key;
@@ -540,6 +552,8 @@ namespace Microsoft.Plugin.Program.Programs
// windows 8 https://msdn.microsoft.com/en-us/library/windows/apps/br211475.aspx
string path;
bool isLogoUriSet;
// Using Ordinal since this is used internally with uri
if (uri.Contains("\\", StringComparison.Ordinal))
{
path = Path.Combine(Package.Location, uri);
@@ -598,6 +612,7 @@ namespace Microsoft.Plugin.Program.Programs
string currentBackgroundColor;
if (BackgroundColor == "transparent")
{
// Using InvariantCulture since this is internal
currentBackgroundColor = SystemParameters.WindowGlassBrush.ToString(CultureInfo.InvariantCulture);
}
else

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Security;
@@ -20,12 +21,18 @@ using Wox.Infrastructure;
using Wox.Infrastructure.FileSystemHelper;
using Wox.Plugin;
using Wox.Plugin.Logger;
using DirectoryWrapper = Wox.Infrastructure.FileSystemHelper.DirectoryWrapper;
namespace Microsoft.Plugin.Program.Programs
{
[Serializable]
public class Win32Program : IProgram
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IDirectory Directory = FileSystem.Directory;
public string Name { get; set; }
public string UniqueIdentifier { get; set; }
@@ -57,7 +64,7 @@ namespace Microsoft.Plugin.Program.Programs
// Wrappers for File Operations
public static IFileVersionInfoWrapper FileVersionInfoWrapper { get; set; } = new FileVersionInfoWrapper();
public static IFileWrapper FileWrapper { get; set; } = new FileWrapper();
public static IFile FileWrapper { get; set; } = new FileSystem().File;
public static IShellLinkHelper Helper { get; set; } = new ShellLinkHelper();
@@ -98,6 +105,7 @@ namespace Microsoft.Plugin.Program.Programs
// To Filter PWAs when the user searches for the main application
// All Chromium based applications contain the --app-id argument
// Reference : https://codereview.chromium.org/399045/show
// Using Ordinal IgnoreCase since this is used internally
bool isWebApplication = FullPath.Contains(ProxyWebApp, StringComparison.OrdinalIgnoreCase) && Arguments.Contains(AppIdArgument, StringComparison.OrdinalIgnoreCase);
return isWebApplication;
}
@@ -121,6 +129,7 @@ namespace Microsoft.Plugin.Program.Programs
// check if any space separated query is a part of the app name or path name
foreach (var subquery in subqueries)
{
// Using OrdinalIgnoreCase since these are used internally
if (FullPath.Contains(subquery, StringComparison.OrdinalIgnoreCase))
{
pathContainsQuery = true;
@@ -172,6 +181,7 @@ namespace Microsoft.Plugin.Program.Programs
{
if (query != null && AppType == ApplicationType.RunCommand)
{
// Using OrdinalIgnoreCase since this is used internally
if (!query.Equals(Name, StringComparison.OrdinalIgnoreCase) && !query.Equals(ExecutableName, StringComparison.OrdinalIgnoreCase))
{
return false;
@@ -235,6 +245,7 @@ namespace Microsoft.Plugin.Program.Programs
result.Title = Name;
result.SetTitleHighlightData(StringMatcher.FuzzySearch(query, Name).MatchData);
// Using CurrentCulture since this is user facing
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_name, result.Title);
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", Properties.Resources.powertoys_run_plugin_program_file_path, FullPath);
result.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
@@ -342,6 +353,8 @@ namespace Microsoft.Plugin.Program.Programs
Name = Path.GetFileNameWithoutExtension(path),
ExecutableName = Path.GetFileName(path),
IcoPath = path,
// Using CurrentCulture since this is user facing
FullPath = path.ToLower(CultureInfo.CurrentCulture),
UniqueIdentifier = path,
ParentDirectory = Directory.GetParent(path).FullName,
@@ -384,6 +397,7 @@ namespace Microsoft.Plugin.Program.Programs
foreach (string line in lines)
{
// Using OrdinalIgnoreCase since this is used internally
if (line.StartsWith(urlPrefix, StringComparison.OrdinalIgnoreCase))
{
urlPath = line.Substring(urlPrefix.Length);
@@ -407,6 +421,7 @@ namespace Microsoft.Plugin.Program.Programs
}
}
// Using OrdinalIgnoreCase since this is used internally
if (line.StartsWith(iconFilePrefix, StringComparison.OrdinalIgnoreCase))
{
iconPath = line.Substring(iconFilePrefix.Length);
@@ -465,6 +480,8 @@ namespace Microsoft.Plugin.Program.Programs
if (File.Exists(target) || Directory.Exists(target))
{
program.LnkResolvedPath = program.FullPath;
// Using CurrentCulture since this is user facing
program.FullPath = Path.GetFullPath(target).ToLower(CultureInfo.CurrentCulture);
program.AppType = GetAppTypeFromPath(target);
@@ -543,6 +560,7 @@ namespace Microsoft.Plugin.Program.Programs
string extension = Extension(path);
ApplicationType appType = ApplicationType.GenericFile;
// Using OrdinalIgnoreCase since these are used internally with paths
if (ExecutableApplicationExtensions.Contains(extension))
{
appType = ApplicationType.Win32Application;
@@ -677,6 +695,7 @@ namespace Microsoft.Plugin.Program.Programs
private static string Extension(string path)
{
// Using CurrentCulture since this is user facing
var extension = Path.GetExtension(path)?.ToLower(CultureInfo.CurrentCulture);
if (!string.IsNullOrEmpty(extension))
@@ -734,6 +753,7 @@ namespace Microsoft.Plugin.Program.Programs
.Distinct()
.ToArray();
// Using OrdinalIgnoreCase since this is used internally with paths
var programs1 = allPaths.AsParallel().Where(p => Extension(p).Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(LnkProgram);
var programs2 = allPaths.AsParallel().Where(p => Extension(p).Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase)).Select(CreateWin32Program);
var programs3 = allPaths.AsParallel().Where(p => Extension(p).Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(InternetShortcutProgram);
@@ -768,6 +788,7 @@ namespace Microsoft.Plugin.Program.Programs
.Distinct()
.ToArray();
// Using OrdinalIgnoreCase since this is used internally with paths
var programs1 = paths.AsParallel().Where(p => Extension(p).Equals(ShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(LnkProgram);
var programs2 = paths.AsParallel().Where(p => Extension(p).Equals(ApplicationReferenceExtension, StringComparison.OrdinalIgnoreCase)).Select(CreateWin32Program);
var programs3 = paths.AsParallel().Where(p => Extension(p).Equals(InternetShortcutExtension, StringComparison.OrdinalIgnoreCase)).Select(InternetShortcutProgram);
@@ -908,6 +929,7 @@ namespace Microsoft.Plugin.Program.Programs
&& !string.IsNullOrEmpty(app1.ExecutableName) && !string.IsNullOrEmpty(app2.ExecutableName)
&& !string.IsNullOrEmpty(app1.FullPath) && !string.IsNullOrEmpty(app2.FullPath))
{
// Using OrdinalIgnoreCase since this is used internally
return app1.Name.Equals(app2.Name, StringComparison.OrdinalIgnoreCase)
&& app1.ExecutableName.Equals(app2.ExecutableName, StringComparison.OrdinalIgnoreCase)
&& app1.FullPath.Equals(app2.FullPath, StringComparison.OrdinalIgnoreCase);
@@ -924,6 +946,8 @@ namespace Microsoft.Plugin.Program.Programs
int fullPathPrime = 31;
int result = 1;
// Using Ordinal since this is used internally
result = (result * namePrime) + obj.Name.ToUpperInvariant().GetHashCode(StringComparison.Ordinal);
result = (result * executablePrime) + obj.ExecutableName.ToUpperInvariant().GetHashCode(StringComparison.Ordinal);
result = (result * fullPathPrime) + obj.FullPath.ToUpperInvariant().GetHashCode(StringComparison.Ordinal);

View File

@@ -24,6 +24,7 @@ namespace Microsoft.Plugin.Program.Storage
// To obtain the last event associated with a particular app.
while (eventHandlingQueue.TryPeek(out string currentAppPath))
{
// Using OrdinalIgnoreCase since this is used internally with paths
if (string.IsNullOrEmpty(previousAppPath) || previousAppPath.Equals(currentAppPath, StringComparison.OrdinalIgnoreCase))
{
// To dequeue a path only if it is the first one in the queue or if the path was the same as thre previous one (to avoid trying to create apps on duplicate events)

View File

@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Threading.Tasks;
using Wox.Infrastructure.Storage;
using Wox.Plugin.Logger;
@@ -17,6 +18,9 @@ namespace Microsoft.Plugin.Program.Storage
{
internal class Win32ProgramRepository : ListRepository<Programs.Win32Program>, IProgramRepository
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private const string LnkExtension = ".lnk";
private const string UrlExtension = ".url";
@@ -145,6 +149,7 @@ namespace Microsoft.Plugin.Program.Storage
try
{
// To mitigate the issue of not having a FullPath for a shortcut app, we iterate through the items and find the app with the same hashcode.
// Using OrdinalIgnoreCase since this is used internally
if (extension.Equals(LnkExtension, StringComparison.OrdinalIgnoreCase))
{
app = GetAppWithSameLnkResolvedPath(path);
@@ -174,6 +179,7 @@ namespace Microsoft.Plugin.Program.Storage
{
foreach (Win32Program app in Items)
{
// Using CurrentCultureIgnoreCase since application names could be dependent on currentculture See: https://github.com/microsoft/PowerToys/pull/5847/files#r468245190
if (name.Equals(app.Name, StringComparison.CurrentCultureIgnoreCase) && executableName.Equals(app.ExecutableName, StringComparison.CurrentCultureIgnoreCase))
{
return app;
@@ -189,7 +195,8 @@ namespace Microsoft.Plugin.Program.Storage
{
foreach (Programs.Win32Program app in Items)
{
if (lnkResolvedPath.ToLower(CultureInfo.CurrentCulture).Equals(app.LnkResolvedPath, StringComparison.CurrentCultureIgnoreCase))
// Using Invariant / OrdinalIgnoreCase since we're comparing paths
if (lnkResolvedPath.ToUpperInvariant().Equals(app.LnkResolvedPath, StringComparison.OrdinalIgnoreCase))
{
return app;
}
@@ -201,7 +208,9 @@ namespace Microsoft.Plugin.Program.Storage
private void OnAppCreated(object sender, FileSystemEventArgs e)
{
string path = e.FullPath;
if (!Path.GetExtension(path).Equals(UrlExtension, StringComparison.CurrentCultureIgnoreCase) && !Path.GetExtension(path).Equals(LnkExtension, StringComparison.CurrentCultureIgnoreCase))
// Using OrdinalIgnoreCase since we're comparing extensions
if (!Path.GetExtension(path).Equals(UrlExtension, StringComparison.OrdinalIgnoreCase) && !Path.GetExtension(path).Equals(LnkExtension, StringComparison.OrdinalIgnoreCase))
{
Programs.Win32Program app = Programs.Win32Program.GetAppFromPath(path);
if (app != null)
@@ -214,7 +223,9 @@ namespace Microsoft.Plugin.Program.Storage
private void OnAppChanged(object sender, FileSystemEventArgs e)
{
string path = e.FullPath;
if (Path.GetExtension(path).Equals(UrlExtension, StringComparison.CurrentCultureIgnoreCase) || Path.GetExtension(path).Equals(LnkExtension, StringComparison.CurrentCultureIgnoreCase))
// Using OrdinalIgnoreCase since we're comparing extensions
if (Path.GetExtension(path).Equals(UrlExtension, StringComparison.OrdinalIgnoreCase) || Path.GetExtension(path).Equals(LnkExtension, StringComparison.OrdinalIgnoreCase))
{
// When a url or lnk app is installed, multiple created and changed events are triggered.
// To prevent the code from acting on the first such event (which may still be during app installation), the events are added a common queue and dequeued by a background task at regular intervals - https://github.com/microsoft/PowerToys/issues/6429.

View File

@@ -8,6 +8,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Windows.Input;
@@ -23,6 +24,11 @@ namespace Microsoft.Plugin.Shell
{
public class Main : IPlugin, ISettingProvider, IPluginI18n, IContextMenu, ISavable
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IDirectory Directory = FileSystem.Directory;
private readonly ShellPluginSettings _settings;
private readonly PluginJsonStorage<ShellPluginSettings> _storage;
@@ -84,6 +90,7 @@ namespace Microsoft.Plugin.Shell
{
if (m.Key == cmd)
{
// Using CurrentCulture since this is user facing
result.SubTitle = Properties.Resources.wox_plugin_cmd_plugin_name + ": " + string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_cmd_cmd_has_been_executed_times, m.Value);
return null;
}
@@ -91,6 +98,8 @@ namespace Microsoft.Plugin.Shell
var ret = new Result
{
Title = m.Key,
// Using CurrentCulture since this is user facing
SubTitle = Properties.Resources.wox_plugin_cmd_plugin_name + ": " + string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_cmd_cmd_has_been_executed_times, m.Value),
IcoPath = IconPath,
Action = c =>
@@ -128,6 +137,8 @@ namespace Microsoft.Plugin.Shell
.Select(m => new Result
{
Title = m.Key,
// Using CurrentCulture since this is user facing
SubTitle = Properties.Resources.wox_plugin_cmd_plugin_name + ": " + string.Format(CultureInfo.CurrentCulture, Properties.Resources.wox_plugin_cmd_cmd_has_been_executed_times, m.Value),
IcoPath = IconPath,
Action = c =>

View File

@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Text;
using ManagedCommon;
using Microsoft.Plugin.Uri.UriHelper;
@@ -17,6 +17,10 @@ namespace Microsoft.Plugin.Uri
{
public class Main : IPlugin, IPluginI18n, IContextMenu, ISavable, IDisposable
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private readonly ExtendedUriParser _uriParser;
private readonly UriResolver _uriResolver;
private readonly PluginJsonStorage<UriSettings> _storage;
@@ -119,6 +123,7 @@ namespace Microsoft.Plugin.Uri
?? _registryWrapper.GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\DefaultIcon", null);
// "Handles 'Indirect Strings' (UWP programs)"
// Using Ordinal since this is internal and used with a symbol
if (programLocation.StartsWith("@", StringComparison.Ordinal))
{
var directProgramLocationStringBuilder = new StringBuilder(128);
@@ -137,6 +142,7 @@ namespace Microsoft.Plugin.Uri
}
else
{
// Using Ordinal since this is internal and used with a symbol
var indexOfComma = programLocation.IndexOf(',', StringComparison.Ordinal);
BrowserIconPath = indexOfComma > 0
? programLocation.Substring(0, indexOfComma)

View File

@@ -18,9 +18,10 @@ namespace Microsoft.Plugin.Uri.UriHelper
}
// Handle common cases UriBuilder does not handle
if (input.EndsWith(":", StringComparison.Ordinal)
|| input.EndsWith(".", StringComparison.Ordinal)
|| input.EndsWith(":/", StringComparison.Ordinal))
// Using CurrentCulture since this is a user typed string
if (input.EndsWith(":", StringComparison.CurrentCulture)
|| input.EndsWith(".", StringComparison.CurrentCulture)
|| input.EndsWith(":/", StringComparison.CurrentCulture))
{
result = default;
return false;

View File

@@ -37,6 +37,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
throw new ArgumentNullException(nameof(text));
}
// Using CurrentCulture since this is user facing
searchText = searchText.ToLower(CultureInfo.CurrentCulture);
text = text.ToLower(CultureInfo.CurrentCulture);

View File

@@ -563,6 +563,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
public override string ToString()
{
// Using CurrentCulture since this is user facing
return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
}
}

View File

@@ -54,6 +54,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
set
{
// Using CurrentCulture since this is user facing
searchText = value.ToLower(CultureInfo.CurrentCulture).Trim();
}
}

View File

@@ -252,6 +252,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
// 1) There is a weird flashing behavior when trying
// to use ShowWindow for switching tabs in IE
// 2) SetForegroundWindow fails on minimized windows
// Using Ordinal since this is internal
if (ProcessName.ToUpperInvariant().Equals("IEXPLORE.EXE", StringComparison.Ordinal) || !Minimized)
{
NativeMethods.SetForegroundWindow(Hwnd);
@@ -270,6 +271,7 @@ namespace Microsoft.Plugin.WindowWalker.Components
/// <returns>The title of the window</returns>
public override string ToString()
{
// Using CurrentCulture since this is user facing
return Title + " (" + ProcessName.ToUpper(CultureInfo.CurrentCulture) + ")";
}

View File

@@ -1,10 +1,13 @@
<Application x:Class="PowerLauncher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:theming="clr-namespace:Wox.Plugin;assembly=Wox.Plugin"
ShutdownMode="OnMainWindowClose"
Startup="OnStartup">
<Application.Resources>
<ResourceDictionary>
<theming:CustomLibraryThemeProvider x:Key="{x:Static theming:CustomLibraryThemeProvider.DefaultInstance}" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Dark.xaml" />
</ResourceDictionary.MergedDictionaries>

View File

@@ -34,7 +34,8 @@ namespace PowerLauncher.Helper
{
string uriString = uri.AbsoluteUri;
int commaIndex = uriString.IndexOf(',', StringComparison.InvariantCultureIgnoreCase);
// Using Ordinal since this is internal and used with a symbol
int commaIndex = uriString.IndexOf(',', StringComparison.Ordinal);
var headers = uriString.Substring(0, commaIndex).Split(';');
_contentType = headers[0];
string dataString = uriString.Substring(commaIndex + 1);

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.IO.Pipes;
using System.Text;
using System.Threading;
@@ -29,6 +30,10 @@ namespace PowerLauncher.Helper
public static class SingleInstance<TApplication>
where TApplication : Application, ISingleInstanceApp
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
/// <summary>
/// String delimiter used in channel names.
/// </summary>

View File

@@ -6,6 +6,7 @@ using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text;
using System.Windows;
@@ -21,6 +22,9 @@ namespace PowerLauncher
{
internal partial class ReportWindow
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IFile File = FileSystem.File;
public ReportWindow(Exception exception)
{
InitializeComponent();
@@ -44,7 +48,9 @@ namespace PowerLauncher
StringBuilder content = new StringBuilder();
content.AppendLine(ErrorReporting.RuntimeInfo());
content.AppendLine($"Date: {DateTime.Now.ToString(CultureInfo.InvariantCulture)}");
// Using CurrentCulture since this is displayed to user in the report window
content.AppendLine($"Date: {DateTime.Now.ToString(CultureInfo.CurrentCulture)}");
content.AppendLine("Exception:");
content.AppendLine(exception.ToString());
var paragraph = new Paragraph();

View File

@@ -4,6 +4,7 @@
using System;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using System.Windows.Input;
using ManagedCommon;
@@ -26,14 +27,14 @@ namespace PowerLauncher
private const int MaxRetries = 10;
private static readonly object _watcherSyncObject = new object();
private readonly FileSystemWatcher _watcher;
private readonly IFileSystemWatcher _watcher;
private readonly PowerToysRunSettings _settings;
private readonly ThemeManager _themeManager;
public SettingsWatcher(PowerToysRunSettings settings, ThemeManager themeManager)
{
_settingsUtils = new SettingsUtils(new SystemIOProvider());
_settingsUtils = new SettingsUtils();
_settings = settings;
_themeManager = themeManager;
@@ -92,6 +93,7 @@ namespace PowerLauncher
_settings.IgnoreHotkeysOnFullscreen = overloadSettings.Properties.IgnoreHotkeysInFullscreen;
}
// Using OrdinalIgnoreCase since this is internal
var indexer = PluginManager.AllPlugins.Find(p => p.Metadata.Name.Equals("Windows Indexer", StringComparison.OrdinalIgnoreCase));
if (indexer != null)
{

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">Dark</system:String>
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
<Color x:Key="Theme.PrimaryAccentColor">Black</Color>
<system:Boolean x:Key="Theme.IsHighContrast">False</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#FF818181</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="#FF171717" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FF1b1b1b</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FFcdcdcd</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FFcdcdcd" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FFcdcdcd</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FF171717</Color>

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent2</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<system:Boolean x:Key="Theme.IsHighContrast">True</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#ffff00</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="Black" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FF000000</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FFFFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FFFFFFFF" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FFFFFFFF</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FFFFFFFF</Color>

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent3</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<system:Boolean x:Key="Theme.IsHighContrast">True</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#ffff00</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="Black" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FF000000</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FFFFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FFFFFFFF" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FFFFFFFF</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FFFFFFFF</Color>

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent4</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<system:Boolean x:Key="Theme.IsHighContrast">True</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#66FFFFFF</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="Black" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FF000000</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FFFFFFFF</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FFFFFFFF" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FFFFFFFF</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FFFFFFFF</Color>

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
<system:String x:Key="Theme.ColorScheme">Accent5</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<system:Boolean x:Key="Theme.IsHighContrast">True</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#66000000</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="White" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FFf0f0f0</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FF000000</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FF000000" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FF000000</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FF000000</Color>

View File

@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:markup="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:markupWithAssembly="clr-namespace:MahApps.Metro.Markup;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
@@ -14,6 +12,7 @@
<system:String x:Key="Theme.BaseColorScheme">Light</system:String>
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
<system:Boolean x:Key="Theme.IsHighContrast">False</system:Boolean>
<Color x:Key="SystemBaseMediumLowColor">#66000000</Color>
<SolidColorBrush x:Key="SystemChromeLow" Color="#FFF2F2F2" options:Freeze="True" />
@@ -37,7 +36,7 @@
<Color x:Key="ScrollBarBackgroundPointerOver">#FFf0f0f0</Color>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground">#FF1d1d1d</SolidColorBrush>
<SolidColorBrush x:Key="ScrollBarLineButtonForeground" Color="#FF1d1d1d" />
<Color x:Key="ScrollBarLineButtonForegroundPointerOver">#FF1d1d1d</Color>
<Color x:Key="ScrollBarLineButtonForegroundPointerPressed">#FFf3f3f3</Color>

View File

@@ -132,6 +132,7 @@ namespace PowerLauncher.ViewModel
if (index != null)
{
// Using InvariantCulture since this is internal
results.SelectedIndex = int.Parse(index.ToString(), CultureInfo.InvariantCulture);
}
@@ -438,8 +439,9 @@ namespace PowerLauncher.ViewModel
private void QueryHistory()
{
// Using CurrentCulture since query is received from user and used in downstream comparisons using CurrentCulture
#pragma warning disable CA1308 // Normalize strings to uppercase
var query = QueryText.ToLower(CultureInfo.InvariantCulture).Trim();
var query = QueryText.ToLower(CultureInfo.CurrentCulture).Trim();
#pragma warning restore CA1308 // Normalize strings to uppercase
History.Clear();
@@ -528,6 +530,7 @@ namespace PowerLauncher.ViewModel
lock (_addResultsLock)
{
// Using CurrentCultureIgnoreCase since this is user facing
if (queryText.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{
Results.Clear();
@@ -565,6 +568,7 @@ namespace PowerLauncher.ViewModel
{
lock (_addResultsLock)
{
// Using CurrentCultureIgnoreCase since this is user facing
if (queryText.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{
currentCancellationToken.ThrowIfCancellationRequested();
@@ -630,6 +634,7 @@ namespace PowerLauncher.ViewModel
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Using CurrentCultureIgnoreCase since this is user facing
if (queryText.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{
Results.Results.NotifyChanges();
@@ -818,6 +823,7 @@ namespace PowerLauncher.ViewModel
}
}
// Using CurrentCultureIgnoreCase since this is user facing
if (originQuery.Equals(_currentQuery, StringComparison.CurrentCultureIgnoreCase))
{
ct.ThrowIfCancellationRequested();
@@ -879,6 +885,7 @@ namespace PowerLauncher.ViewModel
}
else
{
// Using Ordinal this is internal
return string.IsNullOrEmpty(queryText) || autoCompleteText.IndexOf(queryText, StringComparison.Ordinal) != 0;
}
}
@@ -889,6 +896,7 @@ namespace PowerLauncher.ViewModel
{
if (index == 0)
{
// Using OrdinalIgnoreCase because we want the characters to be exact in autocomplete text and the query
if (input.IndexOf(query, StringComparison.OrdinalIgnoreCase) == 0)
{
// Use the same case as the input query for the matched portion of the string
@@ -906,6 +914,7 @@ namespace PowerLauncher.ViewModel
{
if (index == 0 && !string.IsNullOrEmpty(query))
{
// Using OrdinalIgnoreCase since this is internal
if (input.IndexOf(query, StringComparison.OrdinalIgnoreCase) == 0)
{
return query + input.Substring(query.Length);

View File

@@ -120,10 +120,13 @@
</Item>
<Item ItemId=";deseralization_error_title" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Powertoys Run deserialization error]]></Val>
<Val><![CDATA[PowerToys Run deserialization error]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Chyba deserializace nástroje Spuštění PowerToys]]></Val>
</Tgt>
<Prev Cat="Text">
<Val><![CDATA[Powertoys Run deserialization error]]></Val>
</Prev>
</Str>
<Disp Icon="Str" />
</Item>
@@ -154,7 +157,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";reportWindow_file_bug" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";reportWindow_file_bug" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Please file a bug in the]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
@@ -163,7 +166,7 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";reportWindow_github_repo" ItemType="0;.resx" PsrId="211" Leaf="true">
<Item ItemId=";reportWindow_github_repo" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[PowerToys GitHub repository]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">

View File

@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
@@ -15,6 +15,11 @@ namespace Wox.Core.Plugin
{
internal abstract class PluginConfig
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IDirectory Directory = FileSystem.Directory;
private const string PluginConfigName = "plugin.json";
private static readonly List<PluginMetadata> PluginMetadatas = new List<PluginMetadata>();

View File

@@ -4,6 +4,7 @@
using System;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using System.Windows;
using ICSharpCode.SharpZipLib.Zip;
@@ -15,6 +16,11 @@ namespace Wox.Core.Plugin
{
internal class PluginInstaller
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IDirectory Directory = FileSystem.Directory;
internal static void Install(string path)
{
if (File.Exists(path))
@@ -35,7 +41,7 @@ namespace Wox.Core.Plugin
}
PluginMetadata plugin = GetMetadataFromJson(tempFolder);
if (plugin == null || plugin.Name == null)
if (plugin?.Name == null)
{
MessageBox.Show("Install failed: plugin config is invalid");
return;
@@ -196,7 +202,7 @@ namespace Wox.Core.Plugin
{
if ((File.Exists(strDirectory + directoryName + fileName) && overWrite) || (!File.Exists(strDirectory + directoryName + fileName)))
{
using (FileStream streamWriter = File.Create(strDirectory + directoryName + fileName))
using (Stream streamWriter = File.Create(strDirectory + directoryName + fileName))
{
byte[] data = new byte[2048];
while (true)

View File

@@ -6,7 +6,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -23,6 +23,9 @@ namespace Wox.Core.Plugin
/// </summary>
public static class PluginManager
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IDirectory Directory = FileSystem.Directory;
private static IEnumerable<PluginPair> _contextMenuPlugins = new List<PluginPair>();
/// <summary>

View File

@@ -70,6 +70,8 @@ namespace Wox.Infrastructure.Exception
sb.AppendLine("## Environment");
sb.AppendLine($"* Command Line: {Environment.CommandLine}");
// Using InvariantCulture since this is internal
sb.AppendLine($"* Timestamp: {DateTime.Now.ToString(CultureInfo.InvariantCulture)}");
sb.AppendLine($"* Wox version: {Constant.Version}");
sb.AppendLine($"* OS Version: {Environment.OSVersion.VersionString}");

View File

@@ -4,18 +4,27 @@
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
namespace Wox.Infrastructure.FileSystemHelper
{
public class FileVersionInfoWrapper : IFileVersionInfoWrapper
{
private readonly IFile _file;
public FileVersionInfoWrapper()
: this(new FileSystem().File)
{
}
public FileVersionInfoWrapper(IFile file)
{
_file = file;
}
public FileVersionInfo GetVersionInfo(string path)
{
if (File.Exists(path))
if (_file.Exists(path))
{
return FileVersionInfo.GetVersionInfo(path);
}

View File

@@ -1,32 +0,0 @@
// 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.IO;
using System.Security;
using Wox.Plugin.Logger;
namespace Wox.Infrastructure.FileSystemHelper
{
public class FileWrapper : IFileWrapper
{
public FileWrapper()
{
}
public string[] ReadAllLines(string path)
{
try
{
return File.ReadAllLines(path);
}
catch (System.Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException || ex is IOException)
{
Log.Info($"Unable to read File: {path}| {ex.Message}", GetType());
return new string[] { string.Empty };
}
}
}
}

View File

@@ -1,11 +0,0 @@
// 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.
namespace Wox.Infrastructure.FileSystemHelper
{
public interface IFileWrapper
{
string[] ReadAllLines(string path);
}
}

View File

@@ -4,7 +4,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@@ -14,6 +14,12 @@ namespace Wox.Infrastructure
{
public static class Helper
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IFileInfoFactory FileInfo = FileSystem.FileInfo;
private static readonly IDirectory Directory = FileSystem.Directory;
/// <summary>
/// http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy
/// </summary>
@@ -54,8 +60,8 @@ namespace Wox.Infrastructure
}
else
{
var time1 = new FileInfo(bundledDataPath).LastWriteTimeUtc;
var time2 = new FileInfo(dataPath).LastWriteTimeUtc;
var time1 = FileInfo.FromFileName(bundledDataPath).LastWriteTimeUtc;
var time2 = FileInfo.FromFileName(dataPath).LastWriteTimeUtc;
if (time1 != time2)
{
File.Copy(bundledDataPath, dataPath, true);

View File

@@ -6,7 +6,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -21,6 +21,11 @@ namespace Wox.Infrastructure.Image
{
public static class ImageLoader
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
private static readonly IFile File = FileSystem.File;
private static readonly IDirectory Directory = FileSystem.Directory;
private static readonly ImageCache ImageCache = new ImageCache();
private static readonly ConcurrentDictionary<string, string> GuidToKey = new ConcurrentDictionary<string, string>();
@@ -131,6 +136,7 @@ namespace Wox.Infrastructure.Image
return new ImageResult(ImageCache[path], ImageType.Cache);
}
// Using OrdinalIgnoreCase since this is internal and used with paths
if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
{
var imageSource = new BitmapImage(new Uri(path));

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
@@ -24,6 +24,9 @@ namespace Wox.Infrastructure.Image
public static class WindowsThumbnailProvider
{
private static readonly IFileSystem FileSystem = new FileSystem();
private static readonly IPath Path = FileSystem.Path;
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";

Some files were not shown because too many files have changed in this diff Show More