[PTRun][ValueGenerator]Add URI/URL features (#30648)

* move existing generator classes

* add new generators

* implement new generators

* fixes

* improvements

* shorten query tags

* make spellcheck happy

* add tests

* dev docs

* fix typos

* fix tests
This commit is contained in:
Heiko
2024-01-03 17:30:11 +01:00
committed by GitHub
parent 2a544583c0
commit 7c0f24df65
16 changed files with 475 additions and 13 deletions

View File

@@ -1600,6 +1600,7 @@ UAL
uap uap
udit udit
uefi uefi
uesc
UHash UHash
UIA UIA
UIEx UIEx
@@ -1608,6 +1609,7 @@ ums
uncompilable uncompilable
UNCPRIORITY UNCPRIORITY
UNDNAME UNDNAME
unescape
UNICODETEXT UNICODETEXT
uninstantiated uninstantiated
uniquifier uniquifier
@@ -1626,6 +1628,7 @@ UOI
Updatelayout Updatelayout
UPGRADINGPRODUCTCODE UPGRADINGPRODUCTCODE
Uptool Uptool
urld
Usb Usb
USEDEFAULT USEDEFAULT
USEFILEATTRIBUTES USEFILEATTRIBUTES

View File

@@ -1,6 +1,6 @@
# Value Generator Plugin # Value Generator Plugin
The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings and to generate GUIDs versions 1, 3, 4 and 5. The Value Generator plugin is used to generate hashes for strings, to calculate base64 encodings, escape and encode URLs/URIs and to generate GUIDs versions 1, 3, 4 and 5.
![Image of Value Generator plugin](/doc/images/launcher/plugin/community.valuegenerator.png) ![Image of Value Generator plugin](/doc/images/launcher/plugin/community.valuegenerator.png)
@@ -10,7 +10,7 @@ The Value Generator plugin is used to generate hashes for strings, to calculate
- The result of `string ResultToString()` will be used for the Result's title - The result of `string ResultToString()` will be used for the Result's title
- The `Description` field will be used for the Result's subtitle - The `Description` field will be used for the Result's subtitle
### [`HashRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Hashing/HashRequest.cs) ### [`HashRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Hashing/HashRequest.cs)
- Implements IComputeRequest - Implements IComputeRequest
- Supports the hashing algorithms from System.Security.Cryptography: - Supports the hashing algorithms from System.Security.Cryptography:
- MD5 - MD5
@@ -20,19 +20,19 @@ The Value Generator plugin is used to generate hashes for strings, to calculate
- SHA512 - SHA512
- If other algorithms are added to System.Security.Cryptography, they can be added to the `_algorithms` dictionary. [`InputParser.ParseInput()`](#inputparser) will need to return a `HashRequest` for the algorithm in the query - If other algorithms are added to System.Security.Cryptography, they can be added to the `_algorithms` dictionary. [`InputParser.ParseInput()`](#inputparser) will need to return a `HashRequest` for the algorithm in the query
### [`Base64Request`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64Request.cs) ### [`Base64Request`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64Request.cs)
- Implements IComputeRequest - Implements IComputeRequest
- `Compute()` will populate `Result` with the base64 encoding of the byte array passed in the constructor - `Compute()` will populate `Result` with the base64 encoding of the byte array passed in the constructor
### [`Base64DecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Base64/Base64DecodeRequest.cs) ### [`Base64DecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Base64/Base64DecodeRequest.cs)
- Implements IComputeRequest - Implements IComputeRequest
- `Compute()` will populate `Result` with the decoded byte array of the base64 string passed in the constructor - `Compute()` will populate `Result` with the decoded byte array of the base64 string passed in the constructor
### [`GUIDRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDRequest.cs) ### [`GUIDRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDRequest.cs)
- Implements IComputeRequest - Implements IComputeRequest
- Uses the [`GUIDGenerator`](#guidgenerator) class to generate or compute the requested GUID - Uses the [`GUIDGenerator`](#guidgenerator) class to generate or compute the requested GUID
### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/GUID/GUIDGenerator.cs) ### [`GUIDGenerator`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/GUID/GUIDGenerator.cs)
- Utility class for generating or calculating GUIDs - Utility class for generating or calculating GUIDs
- Generating GUID versions 1 and 4 is done using builtin APIs. [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 and `System.Guid.NewGuid()` for version 4 - Generating GUID versions 1 and 4 is done using builtin APIs. [`UuidCreateSequential`](https://learn.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreatesequential) for version 1 and `System.Guid.NewGuid()` for version 4
- Versions 3 and 5 take two parameters, a namespace and a name - Versions 3 and 5 take two parameters, a namespace and a name
@@ -40,6 +40,32 @@ The Value Generator plugin is used to generate hashes for strings, to calculate
- The `PredefinedNamespaces` dictionary contains aliases for the predefined namespaces - The `PredefinedNamespaces` dictionary contains aliases for the predefined namespaces
- The name can be any string - The name can be any string
### [`UrlEncodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlEncodeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the encoded url converted using `HttpUtility.UrlEncode()`.
### [`UrlDecodeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/UrlDecodeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the decoded url converted using `HttpUtility.UrlDecode()`.
### [`DataEscapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataEscapeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the escaped data string converted using `System.Uri.EscapeDataString()`.
### [`DataUnescapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/DataUnescapeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the unescaped data string converted using `System.Uri.UnescapeDataString()`.
### [`HexEscapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexEscapeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the escaped data string converted using `System.Uri.HexEscape()`.
- Only single characters are supported as input.
### [`HexUnescapeRequest`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/Uri/HexUnescapeRequest.cs)
- Implements IComputeRequest
- `Compute()` will populate `Result` with the unescaped data string converted using `System.Uri.HexUnescape()`.
- Only the first hexadecimal character in the string gets unescaped. The rest of the user input is ignored.
### [`InputParser`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs) ### [`InputParser`](/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/InputParser.cs)
- It is responsible only for parsing the query from the user - It is responsible only for parsing the query from the user
- Based on the user query, the `ParseInput()` method must return an object that implements the `IComputeRequest` interface or it must throw one of `FormatException` or `ArgumentException` - Based on the user query, the `ParseInput()` method must return an object that implements the `IComputeRequest` interface or it must throw one of `FormatException` or `ArgumentException`
@@ -51,6 +77,6 @@ The Value Generator plugin is used to generate hashes for strings, to calculate
> The error message will not be shown to the user but a log message will be created > The error message will not be shown to the user but a log message will be created
### Adding a new value generator ### Adding a new value generator
1. To add a new value generator, create a folder under `/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/` and inside it add a class that implements `IComputeRequest`. 1. To add a new value generator, create a folder under `/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.ValueGenerator/Generators/` and inside it add a class that implements `IComputeRequest`.
2. Add any utility classes that are specific to the new generator inside the same folder to keep them separated from the other generators. 2. Add any utility classes that are specific to the new generator inside the same folder to keep them separated from the other generators.
3. Modify the `InputParser.ParseInput()` to handle a request for the new generator and return an instance of the class you created in step 1 3. Modify the `InputParser.ParseInput()` to handle a request for the new generator and return an instance of the class you created in step 1

View File

@@ -30,12 +30,23 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests
[DataRow("base99 abc", null)] [DataRow("base99 abc", null)]
[DataRow("base64s abc", null)] [DataRow("base64s abc", null)]
[DataRow("base64d abc=", typeof(Base64.Base64DecodeRequest))] [DataRow("base64d abc=", typeof(Base64.Base64DecodeRequest))]
public void ParserTest(string input, Type? expectedRequestType) [DataRow("url http://googl.de/u oii d", typeof(Uri.UrlEncodeRequest))]
[DataRow("urld http://googl.de/u oii d=oo", typeof(Uri.UrlDecodeRequest))]
[DataRow("esc:data jjdje332j 3 3l2jl32", typeof(Uri.DataEscapeRequest))]
[DataRow("esc:hex d", typeof(Uri.HexEscapeRequest))]
[DataRow("esc:hex 4", typeof(Uri.HexEscapeRequest))]
[DataRow("esc:hex ", typeof(Uri.HexEscapeRequest), true)]
[DataRow("esc:hex z44", typeof(Uri.HexEscapeRequest), true)]
[DataRow("uesc:data jjdje332j 3 3l2jl32", typeof(Uri.DataUnescapeRequest))]
[DataRow("uesc:hex %21", typeof(Uri.HexUnescapeRequest))]
[DataRow("uesc:hex 4", typeof(Uri.HexUnescapeRequest))]
[DataRow("uesc:hex ", typeof(Uri.HexUnescapeRequest))]
[DataRow("uesc:hex z44", typeof(Uri.HexUnescapeRequest))]
public void ParserTest(string input, Type? expectedRequestType, bool expectException = false)
{ {
var parser = new InputParser(); var parser = new InputParser();
var query = new Query(input); var query = new Query(input);
var expectException = false;
string? command = null; string? command = null;
if (query.Terms.Count == 0) if (query.Terms.Count == 0)
{ {
@@ -79,15 +90,24 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator.UnitTests
private static bool CommandIsKnown(string command) private static bool CommandIsKnown(string command)
{ {
string[] hashes = new string[] { "md5", "sha1", "sha256", "sha384", "sha512", "base64", "base64d" }; string[] hashes = new string[] { "md5", "sha1", "sha256", "sha384", "sha512", "base64", "base64d" };
if (hashes.Contains(command.ToLowerInvariant())) if (hashes.Contains(command.ToLowerInvariant()))
{ {
return true; return true;
} }
Regex regex = new Regex("^(guid|uuid)([1345]{0,1}|v[1345]{1})$", RegexOptions.IgnoreCase | RegexOptions.Compiled); Regex regexGuiUUID = new Regex("^(guid|uuid)([1345]{0,1}|v[1345]{1})$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (regexGuiUUID.IsMatch(command))
{
return true;
}
return regex.IsMatch(command); string[] uriCommands = new string[] { "url", "urld", "esc:hex", "uesc:hex", "esc:data", "uesc:data" };
if (uriCommands.Contains(command.ToLowerInvariant()))
{
return true;
}
return false;
} }
} }
} }

View File

@@ -0,0 +1,50 @@
// 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.Text;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class DataEscapeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Data string escaped";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToEscape { get; set; }
public DataEscapeRequest(string dataToEscape)
{
DataToEscape = dataToEscape ?? throw new ArgumentNullException(nameof(dataToEscape));
}
public bool Compute()
{
IsSuccessful = true;
try
{
Result = Encoding.UTF8.GetBytes(System.Uri.EscapeDataString(DataToEscape));
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
return Encoding.UTF8.GetString(Result);
}
}
}

View File

@@ -0,0 +1,58 @@
// 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.Diagnostics;
using System.Text;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class DataUnescapeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Data string unescaped";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToUnescape { get; set; }
public DataUnescapeRequest(string dataToUnescape)
{
DataToUnescape = dataToUnescape ?? throw new ArgumentNullException(nameof(dataToUnescape));
}
public bool Compute()
{
IsSuccessful = true;
try
{
Result = Encoding.UTF8.GetBytes(System.Uri.UnescapeDataString(DataToUnescape));
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
if (Result != null)
{
return Encoding.UTF8.GetString(Result);
}
else
{
return string.Empty;
}
}
}
}

View File

@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
using System.Text;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class HexEscapeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Hex escaped char";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToEscape { get; set; }
public HexEscapeRequest(string dataToEscape)
{
DataToEscape = dataToEscape ?? throw new ArgumentNullException(nameof(dataToEscape));
// Validate that we have only one character
if (dataToEscape.Length != 1)
{
throw new ArgumentOutOfRangeException(nameof(dataToEscape));
}
}
public bool Compute()
{
IsSuccessful = true;
try
{
char charToEscape = DataToEscape[0];
Result = Encoding.UTF8.GetBytes(System.Uri.HexEscape(charToEscape));
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
return Encoding.UTF8.GetString(Result);
}
}
}

View File

@@ -0,0 +1,62 @@
// 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.Diagnostics;
using System.Text;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class HexUnescapeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Hex char unescaped";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToUnescape { get; set; }
public HexUnescapeRequest(string dataToUnescape)
{
DataToUnescape = dataToUnescape ?? throw new ArgumentNullException(nameof(dataToUnescape));
}
public bool Compute()
{
IsSuccessful = true;
try
{
int index = 0;
if (System.Uri.IsHexEncoding(DataToUnescape, index))
{
Result = Encoding.UTF8.GetBytes(System.Uri.HexUnescape(DataToUnescape, ref index).ToString());
}
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
if (Result != null)
{
return Encoding.UTF8.GetString(Result);
}
else
{
return string.Empty;
}
}
}
}

View File

@@ -0,0 +1,60 @@
// 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.Diagnostics;
using System.Security.Policy;
using System.Text;
using System.Web;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class UrlDecodeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Decoded URL";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToDecode { get; set; }
public UrlDecodeRequest(string dataToDecode)
{
DataToDecode = dataToDecode ?? throw new ArgumentNullException(nameof(dataToDecode));
}
public bool Compute()
{
IsSuccessful = true;
try
{
Result = Encoding.UTF8.GetBytes(HttpUtility.UrlDecode(DataToDecode));
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
if (Result != null)
{
return Encoding.UTF8.GetString(Result);
}
else
{
return string.Empty;
}
}
}
}

View File

@@ -0,0 +1,52 @@
// 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.Security.Policy;
using System.Text;
using System.Web;
using Wox.Plugin.Logger;
namespace Community.PowerToys.Run.Plugin.ValueGenerator.Uri
{
public class UrlEncodeRequest : IComputeRequest
{
public byte[] Result { get; set; }
public string Description => "Encoded URL";
public bool IsSuccessful { get; set; }
public string ErrorMessage { get; set; }
private string DataToEncode { get; set; }
public UrlEncodeRequest(string dataToEncode)
{
DataToEncode = dataToEncode ?? throw new ArgumentNullException(nameof(dataToEncode));
}
public bool Compute()
{
IsSuccessful = true;
try
{
Result = Encoding.UTF8.GetBytes(HttpUtility.UrlEncode(DataToEncode));
}
catch (Exception e)
{
Log.Exception(e.Message, e, GetType());
ErrorMessage = e.Message;
IsSuccessful = false;
}
return IsSuccessful;
}
public string ResultToString()
{
return Encoding.UTF8.GetString(Result);
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Text;
using Community.PowerToys.Run.Plugin.ValueGenerator.Base64; using Community.PowerToys.Run.Plugin.ValueGenerator.Base64;
using Community.PowerToys.Run.Plugin.ValueGenerator.GUID; using Community.PowerToys.Run.Plugin.ValueGenerator.GUID;
using Community.PowerToys.Run.Plugin.ValueGenerator.Hashing; using Community.PowerToys.Run.Plugin.ValueGenerator.Hashing;
using Community.PowerToys.Run.Plugin.ValueGenerator.Uri;
using Wox.Plugin; using Wox.Plugin;
using Wox.Plugin.Logger; using Wox.Plugin.Logger;
@@ -127,6 +128,69 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim(); string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new Base64DecodeRequest(content); request = new Base64DecodeRequest(content);
} }
else if (command.StartsWith("esc:", StringComparison.OrdinalIgnoreCase))
{
// Escape things
if (command.Equals("esc:data", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new DataEscapeRequest(content);
}
else if (command.Equals("esc:hex", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
// This is only for single chars
if (content.Length > 1)
{
throw new ArgumentException($"Invalid Query: {query.RawUserQuery} (To many characters.)");
}
else if (content.Length == 0)
{
throw new FormatException($"Invalid Query: {query.RawUserQuery}");
}
request = new HexEscapeRequest(content);
}
else
{
throw new FormatException($"Invalid Query: {query.RawUserQuery}");
}
}
else if (command.StartsWith("uesc:", StringComparison.OrdinalIgnoreCase))
{
// Unescape things
if (command.Equals("uesc:data", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new DataUnescapeRequest(content);
}
else if (command.Equals("uesc:hex", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new HexUnescapeRequest(content);
}
else
{
throw new FormatException($"Invalid Query: {query.RawUserQuery}");
}
}
else if (command.Equals("url", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new UrlEncodeRequest(content);
}
else if (command.Equals("urld", StringComparison.OrdinalIgnoreCase))
{
int commandIndex = query.RawUserQuery.IndexOf(command, StringComparison.InvariantCultureIgnoreCase);
string content = query.RawUserQuery.Substring(commandIndex + command.Length).Trim();
request = new UrlDecodeRequest(content);
}
else else
{ {
throw new FormatException($"Invalid Query: {query.RawUserQuery}"); throw new FormatException($"Invalid Query: {query.RawUserQuery}");

View File

@@ -93,7 +93,16 @@ namespace Community.PowerToys.Run.Plugin.ValueGenerator
try try
{ {
IComputeRequest computeRequest = _inputParser.ParseInput(query); IComputeRequest computeRequest = _inputParser.ParseInput(query);
results.Add(GetResult(computeRequest)); var result = GetResult(computeRequest);
if (!string.IsNullOrEmpty(result.Title))
{
results.Add(result);
}
else
{
return results;
}
} }
catch (ArgumentException e) catch (ArgumentException e)
{ {