diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Main.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Main.cs index f75fc82366..18f18882b0 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Main.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Main.cs @@ -1,181 +1,193 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using System.Threading; -using System.Windows; -using Mages.Core; +// 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.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows; +using Mages.Core; using Wox.Infrastructure.Logger; -using Wox.Plugin; - -namespace Microsoft.Plugin.Calculator -{ - public class Main : IPlugin, IPluginI18n, IDisposable - { - private static readonly Regex RegValidExpressChar = new Regex( - @"^(" + - @"ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|" + - @"sin|cos|tan|arcsin|arccos|arctan|" + - @"eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|" + - @"bin2dec|hex2dec|oct2dec|" + - @"==|~=|&&|\|\||" + - @"[ei]|[0-9]|[\+\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + - @")+$", RegexOptions.Compiled); - private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); - private static readonly Engine MagesEngine = new Engine(); - private PluginInitContext Context { get; set; } - private string IconPath { get; set; } - private bool _disposed = false; - - public List Query(Query query) - { - if(query == null) +using Wox.Plugin; + +namespace Microsoft.Plugin.Calculator +{ + public class Main : IPlugin, IPluginI18n, IDisposable + { + private static readonly Regex RegValidExpressChar = new Regex( + @"^(" + + @"ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|" + + @"sin|cos|tan|arcsin|arccos|arctan|" + + @"eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|" + + @"bin2dec|hex2dec|oct2dec|" + + @"==|~=|&&|\|\||" + + @"[ei]|[0-9]|[\+\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + + @")+$", RegexOptions.Compiled); + + private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); + private static readonly Engine MagesEngine = new Engine(); + + private PluginInitContext Context { get; set; } + + private string IconPath { get; set; } + + private bool _disposed = false; + + public List Query(Query query) + { + if (query == null) { throw new ArgumentNullException(paramName: nameof(query)); - } - - if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword - || !RegValidExpressChar.IsMatch(query.Search) - || !IsBracketComplete(query.Search)) return new List(); - - try - { - var result = MagesEngine.Interpret(query.Search); - - // This could happen for some incorrect queries, like pi(2) - if (result == null) - { - return new List(); - } - - if (result.ToString() == "NaN") - result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number"); - - if (result is Function) - result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete"); - - - if (!string.IsNullOrEmpty(result?.ToString())) - { - return new List - { - new Result - { - Title = result.ToString(), - IcoPath = IconPath, - Score = 300, - SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"), - Action = c => - { - var ret = false; - var thread = new Thread(() => - { - try - { - Clipboard.SetText(result.ToString()); - ret = true; - } - catch (ExternalException) - { - MessageBox.Show("Copy failed, please try later"); - } - }); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - thread.Join(); - return ret; - } - } - }; - } } -//We want to keep the process alive if any the mages library throws any exceptions. + + if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword + || !RegValidExpressChar.IsMatch(query.Search) + || !IsBracketComplete(query.Search)) + { + return new List(); + } + + try + { + var result = MagesEngine.Interpret(query.Search); + + // This could happen for some incorrect queries, like pi(2) + if (result == null) + { + return new List(); + } + + if (result.ToString() == "NaN") + { + result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number"); + } + + if (result is Function) + { + result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete"); + } + + if (!string.IsNullOrEmpty(result?.ToString())) + { + return new List + { + new Result + { + Title = result.ToString(), + IcoPath = IconPath, + Score = 300, + SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"), + Action = c => + { + var ret = false; + var thread = new Thread(() => + { + try + { + Clipboard.SetText(result.ToString()); + ret = true; + } + catch (ExternalException) + { + MessageBox.Show("Copy failed, please try later"); + } + }); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + thread.Join(); + return ret; + }, + }, + }; + } + } // We want to keep the process alive if any the mages library throws any exceptions. #pragma warning disable CA1031 // Do not catch general exception types - catch(Exception e) + catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types - { - Log.Exception($"|Microsoft.Plugin.Calculator.Main.Query|Exception when query for <{query}>", e); - } - - return new List(); - } - - private static bool IsBracketComplete(string query) - { - var matchs = RegBrackets.Matches(query); - var leftBracketCount = 0; - foreach (Match match in matchs) - { - if (match.Value == "(" || match.Value == "[") - { - leftBracketCount++; - } - else - { - leftBracketCount--; - } - } - - return leftBracketCount == 0; - } - - public void Init(PluginInitContext context) - { - if(context == null) + { + Log.Exception($"|Microsoft.Plugin.Calculator.Main.Query|Exception when query for <{query}>", e); + } + + return new List(); + } + + private static bool IsBracketComplete(string query) + { + var matchs = RegBrackets.Matches(query); + var leftBracketCount = 0; + foreach (Match match in matchs) + { + if (match.Value == "(" || match.Value == "[") + { + leftBracketCount++; + } + else + { + leftBracketCount--; + } + } + + return leftBracketCount == 0; + } + + public void Init(PluginInitContext context) + { + if (context == null) { throw new ArgumentNullException(paramName: nameof(context)); - } - - Context = context; - Context.API.ThemeChanged += OnThemeChanged; - UpdateIconPath(Context.API.GetCurrentTheme()); - } - - // Todo : Update with theme based IconPath - private void UpdateIconPath(Theme theme) - { - if (theme == Theme.Light || theme == Theme.HighContrastWhite) - { - IconPath = "Images/calculator.light.png"; - } - else - { - IconPath = "Images/calculator.dark.png"; - } - } - - private void OnThemeChanged(Theme _, Theme newTheme) - { - UpdateIconPath(newTheme); - } - - public string GetTranslatedPluginTitle() - { - return Context.API.GetTranslation("wox_plugin_calculator_plugin_name"); - } - - public string GetTranslatedPluginDescription() - { - return Context.API.GetTranslation("wox_plugin_calculator_plugin_description"); - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - Context.API.ThemeChanged -= OnThemeChanged; - _disposed = true; - } - } - } - } -} \ No newline at end of file + } + + Context = context; + Context.API.ThemeChanged += OnThemeChanged; + UpdateIconPath(Context.API.GetCurrentTheme()); + } + + // Todo : Update with theme based IconPath + private void UpdateIconPath(Theme theme) + { + if (theme == Theme.Light || theme == Theme.HighContrastWhite) + { + IconPath = "Images/calculator.light.png"; + } + else + { + IconPath = "Images/calculator.dark.png"; + } + } + + private void OnThemeChanged(Theme currentTheme, Theme newTheme) + { + UpdateIconPath(newTheme); + } + + public string GetTranslatedPluginTitle() + { + return Context.API.GetTranslation("wox_plugin_calculator_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return Context.API.GetTranslation("wox_plugin_calculator_plugin_description"); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + Context.API.ThemeChanged -= OnThemeChanged; + _disposed = true; + } + } + } + } +} diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Microsoft.Plugin.Calculator.csproj b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Microsoft.Plugin.Calculator.csproj index abb9c429b4..ff1812f930 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Microsoft.Plugin.Calculator.csproj +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/Microsoft.Plugin.Calculator.csproj @@ -1,113 +1,113 @@ - - - - netcoreapp3.1 - {59BD9891-3837-438A-958D-ADC7F91F6F7E} - Properties - Microsoft.Plugin.Calculator - Microsoft.Plugin.Calculator - true - false - false - x64 - - - - true - ..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Calculator\ - DEBUG;TRACE - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - 4 - false - true - - - - ..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Calculator\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - 4 - - - - - PreserveNewest - - - - - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - MSBuild:Compile - Designer - PreserveNewest - - - - - - - NU1701 - + + + + netcoreapp3.1 + {59BD9891-3837-438A-958D-ADC7F91F6F7E} + Properties + Microsoft.Plugin.Calculator + Microsoft.Plugin.Calculator + true + false + false + x64 + + + + true + ..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Calculator\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + 4 + false + true + + + + ..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Calculator\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + 4 + + + + + PreserveNewest + + + + + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + MSBuild:Compile + Designer + PreserveNewest + + + + + + + NU1701 + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + PreserveNewest @@ -115,6 +115,20 @@ PreserveNewest - - + + + + GlobalSuppressions.cs + + + StyleCop.json + + + + + 1.1.118 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/NumberTranslator.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/NumberTranslator.cs index ed584906cc..2bb76237ae 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/NumberTranslator.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Calculator/NumberTranslator.cs @@ -1,105 +1,107 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Microsoft.Plugin.Calculator -{ - /// - /// Tries to convert all numbers in a text from one culture format to another. - /// - public class NumberTranslator - { - private readonly CultureInfo sourceCulture; - private readonly CultureInfo targetCulture; - private readonly Regex splitRegexForSource; - private readonly Regex splitRegexForTarget; - - private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture) - { - this.sourceCulture = sourceCulture; - this.targetCulture = targetCulture; - - this.splitRegexForSource = GetSplitRegex(this.sourceCulture); - this.splitRegexForTarget = GetSplitRegex(this.targetCulture); - } - - /// - /// Create a new - returns null if no number conversion - /// is required between the cultures. - /// - /// source culture - /// target culture - /// - public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture) - { +// 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.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace Microsoft.Plugin.Calculator +{ + /// + /// Tries to convert all numbers in a text from one culture format to another. + /// + public class NumberTranslator + { + private readonly CultureInfo sourceCulture; + private readonly CultureInfo targetCulture; + private readonly Regex splitRegexForSource; + private readonly Regex splitRegexForTarget; + + private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture) + { + this.sourceCulture = sourceCulture; + this.targetCulture = targetCulture; + + splitRegexForSource = GetSplitRegex(this.sourceCulture); + splitRegexForTarget = GetSplitRegex(this.targetCulture); + } + + /// + /// Create a new - returns null if no number conversion + /// is required between the cultures. + /// + /// source culture + /// target culture + /// Number translator for target culture + public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture) + { if (sourceCulture == null) - { - throw new ArgumentNullException(paramName:nameof(sourceCulture)); - } - - if (targetCulture == null) - { + { throw new ArgumentNullException(paramName: nameof(sourceCulture)); - } - - bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator - || sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator - || sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes; - return conversionRequired - ? new NumberTranslator(sourceCulture, targetCulture) - : null; - } - - /// - /// Translate from source to target culture. - /// - /// - /// - public string Translate(string input) - { - return Translate(input, this.sourceCulture, this.targetCulture, this.splitRegexForSource); - } - - /// - /// Translate from target to source culture. - /// - /// - /// - public string TranslateBack(string input) - { - return Translate(input, this.targetCulture, this.sourceCulture, this.splitRegexForTarget); - } - - private static string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex) - { - var outputBuilder = new StringBuilder(); - - string[] tokens = splitRegex.Split(input); - foreach (string token in tokens) - { - decimal number; - outputBuilder.Append( - decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number) - ? number.ToString(cultureTo) - : token); - } - - return outputBuilder.ToString(); - } - - private static Regex GetSplitRegex(CultureInfo culture) - { - var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}"; - if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator)) - { - splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}"; - } - splitPattern += ")+)"; - return new Regex(splitPattern); - } - } -} + } + + if (targetCulture == null) + { + throw new ArgumentNullException(paramName: nameof(sourceCulture)); + } + + bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator + || sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator + || sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes; + return conversionRequired + ? new NumberTranslator(sourceCulture, targetCulture) + : null; + } + + /// + /// Translate from source to target culture. + /// + /// input string to translate + /// translated string + public string Translate(string input) + { + return Translate(input, sourceCulture, targetCulture, splitRegexForSource); + } + + /// + /// Translate from target to source culture. + /// + /// input string to translate back to source culture + /// source culture string + public string TranslateBack(string input) + { + return Translate(input, targetCulture, sourceCulture, splitRegexForTarget); + } + + private static string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex) + { + var outputBuilder = new StringBuilder(); + + string[] tokens = splitRegex.Split(input); + foreach (string token in tokens) + { + decimal number; + outputBuilder.Append( + decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number) + ? number.ToString(cultureTo) + : token); + } + + return outputBuilder.ToString(); + } + + private static Regex GetSplitRegex(CultureInfo culture) + { + var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}"; + if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator)) + { + splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}"; + } + + splitPattern += ")+)"; + return new Regex(splitPattern); + } + } +}