mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
[PowerToys Run] Add Support for Uris (#5160)
* url handler plugin * updates * Add seperate interface classes rename to uri module * Update path * Update implementation to remove slow DNS lookup ( and let browser handle it) * tabs to spaces * - Update icon/assets - Finalize Project * Update wix project * Implement UpdateBrowserIconPath * Implemented Microsoft.CodeAnalysis.FxCopAnalyzers * Add Language component to installer * Update logic to determine icon * Update Translation File to "Open in browser" * Added test for typing http://test.com and which result to expect on each keystoke * Implement StyleCop * Added ipv6 tests * Fix Solution LineBreaks * Added Microsoft.Plugin.Uri as build Dependency * Use ArgumentNullException instead of InvalidOperationException * Fix wrong Directory in wix installer Co-authored-by: Roy <royvou@hotmailcom>
This commit is contained in:
@@ -189,6 +189,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Launcher", "src\m
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\modules\launcher\PowerLauncher\PowerLauncher.csproj", "{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\modules\launcher\PowerLauncher\PowerLauncher.csproj", "{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871} = {03276A39-D4E9-417C-8FFD-200B0EE5E871}
|
||||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
|
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
|
||||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
|
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
|
||||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
|
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
|
||||||
@@ -263,6 +264,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPickerUI", "src\module
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "colorpicker", "colorpicker", "{1D78B84B-CA39-406C-98F4-71F7EC266CC0}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "colorpicker", "colorpicker", "{1D78B84B-CA39-406C-98F4-71F7EC266CC0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Uri", "src\modules\launcher\Plugins\Microsoft.Plugin.Uri\Microsoft.Plugin.Uri.csproj", "{03276A39-D4E9-417C-8FFD-200B0EE5E871}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Plugin.Uri.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Uri.UnitTests\Microsoft.Plugin.Uri.UnitTests.csproj", "{B81FB7B6-D30E-428F-908A-41422EFC1172}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@@ -521,6 +526,14 @@ Global
|
|||||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
|
||||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
|
||||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.Build.0 = Release|x64
|
||||||
|
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -595,6 +608,8 @@ Global
|
|||||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
||||||
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
||||||
{1D78B84B-CA39-406C-98F4-71F7EC266CC0} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
{1D78B84B-CA39-406C-98F4-71F7EC266CC0} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||||
|
{03276A39-D4E9-417C-8FFD-200B0EE5E871} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||||
|
{B81FB7B6-D30E-428F-908A-41422EFC1172} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||||
|
|||||||
@@ -275,6 +275,11 @@
|
|||||||
<Directory Id="IndexerLanguagesFolder" Name="Languages" />
|
<Directory Id="IndexerLanguagesFolder" Name="Languages" />
|
||||||
<Directory Id="IndexerpinyindbFolder" Name="pinyindb" />
|
<Directory Id="IndexerpinyindbFolder" Name="pinyindb" />
|
||||||
</Directory>
|
</Directory>
|
||||||
|
<Directory Id="UriPluginFolder" Name="Microsoft.Plugin.Uri">
|
||||||
|
<Directory Id="UriImagesFolder" Name="Images" />
|
||||||
|
<Directory Id="UriLanguagesFolder" Name="Languages" />
|
||||||
|
<Directory Id="UripinyindbFolder" Name="pinyindb" />
|
||||||
|
</Directory>
|
||||||
<Directory Id="WindowWalkerPluginFolder" Name="Microsoft.Plugin.WindowWalker">
|
<Directory Id="WindowWalkerPluginFolder" Name="Microsoft.Plugin.WindowWalker">
|
||||||
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
|
<Directory Id="WindowWalkerImagesFolder" Name="Images" />
|
||||||
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
|
<Directory Id="WindowWalkerLanguagesFolder" Name="Languages" />
|
||||||
@@ -1013,6 +1018,36 @@
|
|||||||
<?endforeach?>
|
<?endforeach?>
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
|
<!-- Uri Plugin -->
|
||||||
|
<Component Id="UriComponent" Directory="UriPluginFolder" Guid="C7DC8F88-554C-4375-9510-9435399B5D3D">
|
||||||
|
<?foreach File in plugin.json;Wox.Infrastructure.dll;Wox.Plugin.dll;Microsoft.Plugin.Uri.deps.json;Microsoft.Plugin.Uri.dll;Telemetry.dll?>
|
||||||
|
<File Id="Uri_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\$(var.File)" />
|
||||||
|
<?endforeach?>
|
||||||
|
</Component>
|
||||||
|
<Component Id="UriImagesComponent" Directory="UriImagesFolder" Guid="8C9C1634-28C8-45C4-A8EA-8D4C9B4810D0">
|
||||||
|
<File Id="UriDarkIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.dark.png" />
|
||||||
|
<File Id="UriLightIcon" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Images\Uri.light.png" />
|
||||||
|
</Component>
|
||||||
|
<Component Id="UriLanguagesComponent" Directory="UriLanguagesFolder" Guid="4CA9CECE-BB93-4686-A58F-35835F5C3F7D">
|
||||||
|
<?foreach LanguageFile in de.xaml;en.xaml;pl.xaml;tr.xaml;zh-cn.xaml;zh-tw.xaml?>
|
||||||
|
<!--NB: Ids can't contain hyphens-->
|
||||||
|
<?if $(var.LanguageFile) = zh-cn.xaml?>
|
||||||
|
<?define IdSafeLanguage = zh_cn.xaml?>
|
||||||
|
<?elseif $(var.LanguageFile) = zh-tw.xaml?>
|
||||||
|
<?define IdSafeLanguage = zh_tw.xaml?>
|
||||||
|
<?else?>
|
||||||
|
<?define IdSafeLanguage = $(var.LanguageFile)?>
|
||||||
|
<?endif?>
|
||||||
|
<File Id="File_Uri_Plugin_$(var.IdSafeLanguage)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\Languages\$(var.LanguageFile)" />
|
||||||
|
<?undef IdSafeLanguage?>
|
||||||
|
<?endforeach?>
|
||||||
|
</Component>
|
||||||
|
<Component Id="UripinyindbComponent" Directory="UripinyindbFolder" Guid="A52A7281-CD7C-4E7D-A5A6-EA8CFCF462A2">
|
||||||
|
<?foreach File in pinyin_gwoyeu_mapping.xml;pinyin_mapping.xml;unicode_to_hanyu_pinyin.txt?>
|
||||||
|
<File Id="UriPlugin_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\Plugins\Microsoft.Plugin.Uri\pinyindb\$(var.File)" />
|
||||||
|
<?endforeach?>
|
||||||
|
</Component>
|
||||||
|
|
||||||
<!-- WindowWalker Plugin -->
|
<!-- WindowWalker Plugin -->
|
||||||
<Component Id="WindowWalkerComponent" Directory="WindowWalkerPluginFolder" Guid="EB1391C9-B701-421F-80FC-ABB2FEDFAD19">
|
<Component Id="WindowWalkerComponent" Directory="WindowWalkerPluginFolder" Guid="EB1391C9-B701-421F-80FC-ABB2FEDFAD19">
|
||||||
<?foreach File in plugin.json;Wox.Infrastructure.dll;Wox.Plugin.dll;Microsoft.Plugin.WindowWalker.deps.json;Microsoft.Plugin.WindowWalker.dll;Telemetry.dll?>
|
<?foreach File in plugin.json;Wox.Infrastructure.dll;Wox.Plugin.dll;Microsoft.Plugin.WindowWalker.deps.json;Microsoft.Plugin.WindowWalker.dll;Telemetry.dll?>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
<RootNamespace>Microsoft.Plugin.Uri.UnitTests</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="nunit" Version="3.12.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Microsoft.Plugin.Uri\Microsoft.Plugin.Uri.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.Plugin.Uri.UriHelper;
|
||||||
|
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri.UnitTests.UriHelper
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ExtendedUriParserTests
|
||||||
|
{
|
||||||
|
[TestCase("google.com", true, "http://google.com/")]
|
||||||
|
[TestCase("localhost", true, "http://localhost/")]
|
||||||
|
[TestCase("127.0.0.1", true, "http://127.0.0.1/")]
|
||||||
|
[TestCase("127.0.0.1:80", true, "http://127.0.0.1/")]
|
||||||
|
[TestCase("127", true, "http://0.0.0.127/")]
|
||||||
|
[TestCase("", false, null)]
|
||||||
|
[TestCase("https://google.com", true, "https://google.com/")]
|
||||||
|
[TestCase("ftps://google.com", true, "ftps://google.com/")]
|
||||||
|
[TestCase(null, false, null)]
|
||||||
|
[TestCase("bing.com/search?q=gmx", true, "http://bing.com/search?q=gmx")]
|
||||||
|
[TestCase("h", true, "http://h/")]
|
||||||
|
[TestCase("ht", true, "http://ht/")]
|
||||||
|
[TestCase("htt", true, "http://htt/")]
|
||||||
|
[TestCase("http", true, "http://http/")]
|
||||||
|
[TestCase("http:", false, null)]
|
||||||
|
[TestCase("http:/", false, null)]
|
||||||
|
[TestCase("http://", false, null)]
|
||||||
|
[TestCase("http://t", true, "http://t/")]
|
||||||
|
[TestCase("http://te", true, "http://te/")]
|
||||||
|
[TestCase("http://tes", true, "http://tes/")]
|
||||||
|
[TestCase("http://test", true, "http://test/")]
|
||||||
|
[TestCase("http://test.", false, null)]
|
||||||
|
[TestCase("http://test.c", true, "http://test.c/")]
|
||||||
|
[TestCase("http://test.co", true, "http://test.co/")]
|
||||||
|
[TestCase("http://test.com", true, "http://test.com/")]
|
||||||
|
[TestCase("http:3", true,"http://http:3/")]
|
||||||
|
[TestCase("[::]", true, "http://[::]")]
|
||||||
|
[TestCase("[2001:0DB8::1]", true, "http://[2001:0DB8::1]/")]
|
||||||
|
[TestCase("[2001:0DB8::1]:80",true, "http://[2001:0DB8::1]/")]
|
||||||
|
public void TryParse_CanParseHostName(string query, bool expectedSuccess, string expectedResult)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parser = new ExtendedUriParser();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var success = parser.TryParse(query, out var result);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.AreEqual(expectedResult, result?.ToString());
|
||||||
|
Assert.AreEqual(expectedSuccess, success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces
|
||||||
|
{
|
||||||
|
public interface IRegistryWrapper
|
||||||
|
{
|
||||||
|
string GetRegistryValue(string registryLocation, string valueName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUriParser
|
||||||
|
{
|
||||||
|
bool TryParse(string input, out System.Uri result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces
|
||||||
|
{
|
||||||
|
public interface IUrlResolver
|
||||||
|
{
|
||||||
|
bool IsValidHost(System.Uri uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<system:String x:Key="Microsoft_plugin_uri_website">Open in browser</system:String>
|
||||||
|
</ResourceDictionary>
|
||||||
179
src/modules/launcher/Plugins/Microsoft.Plugin.Uri/Main.cs
Normal file
179
src/modules/launcher/Plugins/Microsoft.Plugin.Uri/Main.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Plugin.Uri.UriHelper;
|
||||||
|
using Wox.Infrastructure.Logger;
|
||||||
|
using Wox.Infrastructure.Storage;
|
||||||
|
using Wox.Plugin;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri
|
||||||
|
{
|
||||||
|
public class Main : IPlugin, IPluginI18n, IContextMenu, ISavable, IDisposable
|
||||||
|
{
|
||||||
|
private readonly ExtendedUriParser _uriParser;
|
||||||
|
private readonly UriResolver _uriResolver;
|
||||||
|
private readonly PluginJsonStorage<UriSettings> _storage;
|
||||||
|
private bool _disposed;
|
||||||
|
private UriSettings _uriSettings;
|
||||||
|
private RegisteryWrapper _registeryWrapper;
|
||||||
|
|
||||||
|
public Main()
|
||||||
|
{
|
||||||
|
_storage = new PluginJsonStorage<UriSettings>();
|
||||||
|
_uriSettings = _storage.Load();
|
||||||
|
_uriParser = new ExtendedUriParser();
|
||||||
|
_uriResolver = new UriResolver();
|
||||||
|
_registeryWrapper = new RegisteryWrapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BrowserIconPath { get; set; }
|
||||||
|
|
||||||
|
public string DefaultIconPath { get; set; }
|
||||||
|
|
||||||
|
public PluginInitContext Context { get; protected set; }
|
||||||
|
|
||||||
|
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
||||||
|
{
|
||||||
|
return new List<ContextMenuResult>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Result> Query(Query query)
|
||||||
|
{
|
||||||
|
var results = new List<Result>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(query?.Search)
|
||||||
|
&& _uriParser.TryParse(query.Search, out var uriResult)
|
||||||
|
&& _uriResolver.IsValidHost(uriResult))
|
||||||
|
{
|
||||||
|
var uriResultString = uriResult.ToString();
|
||||||
|
|
||||||
|
results.Add(new Result
|
||||||
|
{
|
||||||
|
Title = uriResultString,
|
||||||
|
SubTitle = Context.API.GetTranslation("Microsoft_plugin_uri_website"),
|
||||||
|
IcoPath = _uriSettings.ShowBrowserIcon
|
||||||
|
? BrowserIconPath
|
||||||
|
: DefaultIconPath,
|
||||||
|
Action = action =>
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo(uriResultString)
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(PluginInitContext context)
|
||||||
|
{
|
||||||
|
Context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
|
Context.API.ThemeChanged += OnThemeChanged;
|
||||||
|
UpdateIconPath(Context.API.GetCurrentTheme());
|
||||||
|
UpdateBrowserIconPath(Context.API.GetCurrentTheme());
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTranslatedPluginTitle()
|
||||||
|
{
|
||||||
|
return "Url Handler";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTranslatedPluginDescription()
|
||||||
|
{
|
||||||
|
return "Handles urls";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
_storage.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnThemeChanged(Theme oldtheme, Theme newTheme)
|
||||||
|
{
|
||||||
|
UpdateIconPath(newTheme);
|
||||||
|
UpdateBrowserIconPath(newTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
|
||||||
|
private void UpdateBrowserIconPath(Theme newTheme)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var progId = _registeryWrapper.GetRegistryValue("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", "ProgId");
|
||||||
|
var programLocation =
|
||||||
|
|
||||||
|
// Resolve App Icon (UWP)
|
||||||
|
_registeryWrapper.GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\Application", "ApplicationIcon")
|
||||||
|
|
||||||
|
// Resolves default file association icon (UWP + Normal)
|
||||||
|
?? _registeryWrapper.GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\DefaultIcon", null);
|
||||||
|
|
||||||
|
// "Handles 'Indirect Strings' (UWP programs)"
|
||||||
|
if (programLocation.StartsWith("@", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var directProgramLocationStringBuilder = new StringBuilder(128);
|
||||||
|
if (NativeMethods.SHLoadIndirectString(programLocation, directProgramLocationStringBuilder, (uint)directProgramLocationStringBuilder.Capacity, IntPtr.Zero) ==
|
||||||
|
NativeMethods.Hresult.Ok)
|
||||||
|
{
|
||||||
|
// Check if there's a postfix with contract-white/contrast-black icon is available and use that instead
|
||||||
|
var directProgramLocation = directProgramLocationStringBuilder.ToString();
|
||||||
|
var themeIcon = newTheme == Theme.Light || newTheme == Theme.HighContrastWhite ? "contrast-white" : "contrast-black";
|
||||||
|
var extension = Path.GetExtension(directProgramLocation);
|
||||||
|
var themedProgLocation = $"{directProgramLocation.Substring(0, directProgramLocation.Length - extension.Length)}_{themeIcon}{extension}";
|
||||||
|
BrowserIconPath = File.Exists(themedProgLocation)
|
||||||
|
? themedProgLocation
|
||||||
|
: directProgramLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var indexOfComma = programLocation.IndexOf(',', StringComparison.Ordinal);
|
||||||
|
BrowserIconPath = indexOfComma > 0
|
||||||
|
? programLocation.Substring(0, indexOfComma)
|
||||||
|
: programLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
BrowserIconPath = DefaultIconPath;
|
||||||
|
Log.Exception("Exception when retreiving icon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateIconPath(Theme theme)
|
||||||
|
{
|
||||||
|
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
|
||||||
|
{
|
||||||
|
DefaultIconPath = "Images/uri.light.png";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DefaultIconPath = "Images/uri.dark.png";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposed && disposing)
|
||||||
|
{
|
||||||
|
Context.API.ThemeChanged -= OnThemeChanged;
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<ProjectGuid>{03276a39-d4e9-417c-8ffd-200b0ee5e871}</ProjectGuid>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Microsoft.Plugin.Uri</RootNamespace>
|
||||||
|
<AssemblyName>Microsoft.Plugin.Uri</AssemblyName>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Uri\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Uri\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||||
|
<Link>GlobalSuppressions.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
|
||||||
|
<Link>StyleCop.json</Link>
|
||||||
|
</AdditionalFiles>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Languages\de.xaml" />
|
||||||
|
<None Remove="Languages\en.xaml" />
|
||||||
|
<None Remove="Languages\ja.xaml" />
|
||||||
|
<None Remove="Languages\pl.xaml" />
|
||||||
|
<None Remove="Languages\tr.xaml" />
|
||||||
|
<None Remove="Languages\zh-cn.xaml" />
|
||||||
|
<None Remove="Languages\zh-tw.xaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Languages\zh-tw.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\zh-cn.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\tr.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\pl.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\ja.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\de.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Languages\en.xaml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="plugin.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Images\uri.dark.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Images\uri.light.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// 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.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri
|
||||||
|
{
|
||||||
|
internal static class NativeMethods
|
||||||
|
{
|
||||||
|
internal enum Hresult : uint
|
||||||
|
{
|
||||||
|
Ok = 0x0000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||||
|
internal static extern Hresult SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri
|
||||||
|
{
|
||||||
|
public class RegisteryWrapper : IRegistryWrapper
|
||||||
|
{
|
||||||
|
public string GetRegistryValue(string registryLocation, string valueName)
|
||||||
|
{
|
||||||
|
return Registry.GetValue(registryLocation, valueName, null) as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri.UriHelper
|
||||||
|
{
|
||||||
|
public class ExtendedUriParser : IUriParser
|
||||||
|
{
|
||||||
|
public bool TryParse(string input, out System.Uri result)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle common cases UriBuilder does not handle
|
||||||
|
if (input.EndsWith(":", StringComparison.Ordinal)
|
||||||
|
|| input.EndsWith(".", StringComparison.Ordinal)
|
||||||
|
|| input.EndsWith(":/", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var urlBuilder = new UriBuilder(input);
|
||||||
|
|
||||||
|
result = urlBuilder.Uri;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (System.UriFormatException)
|
||||||
|
{
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri.Interfaces;
|
||||||
|
|
||||||
|
namespace Microsoft.Plugin.Uri.UriHelper
|
||||||
|
{
|
||||||
|
public class UriResolver : IUrlResolver
|
||||||
|
{
|
||||||
|
public bool IsValidHost(System.Uri uri)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// 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 Microsoft.Plugin.Uri
|
||||||
|
{
|
||||||
|
public class UriSettings
|
||||||
|
{
|
||||||
|
public bool ShowBrowserIcon { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"ID": "03276A39D4E9417C8FFD200B0EE5E871",
|
||||||
|
"ActionKeyword": "*",
|
||||||
|
"Name": "Windows Uri Handler",
|
||||||
|
"Description": "Handles urls",
|
||||||
|
"Author": "Microsoft",
|
||||||
|
"Version": "1.0.0",
|
||||||
|
"Language": "csharp",
|
||||||
|
"Website": "http://aka.ms/PowerToys",
|
||||||
|
"ExecuteFileName": "Microsoft.Plugin.Uri.dll",
|
||||||
|
"IcoPath": "Images\\uri.dark.png"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user