Skip to content

Commit 110f571

Browse files
committed
Rework solution for nested Mages
Previous solution missed e.g. `pow(min(2,3), 4)`
1 parent bd186e7 commit 110f571

File tree

1 file changed

+72
-17
lines changed
  • Plugins/Flow.Launcher.Plugin.Calculator

1 file changed

+72
-17
lines changed

Plugins/Flow.Launcher.Plugin.Calculator/Main.cs

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class Main : IPlugin, IPluginI18n, ISettingProvider
1616
private static readonly Regex RegBrackets = MainRegexHelper.GetRegBrackets();
1717
private static readonly Regex ThousandGroupRegex = MainRegexHelper.GetThousandGroupRegex();
1818
private static readonly Regex NumberRegex = MainRegexHelper.GetNumberRegex();
19+
private static readonly Regex PowRegex = new(@"\bpow(\((?:[^()\[\]]|\((?<Depth>)|\)(?<-Depth>)|\[(?<Depth>)|\](?<-Depth>))*(?(Depth)(?!))\))", RegexOptions.Compiled | RegexOptions.RightToLeft);
20+
1921

2022
private static Engine MagesEngine;
2123
private const string Comma = ",";
@@ -43,11 +45,23 @@ public void Init(PluginInitContext context)
4345

4446
public List<Result> Query(Query query)
4547
{
46-
if (!CanCalculate(query))
48+
if (string.IsNullOrWhiteSpace(query.Search))
4749
{
4850
return new List<Result>();
4951
}
5052

53+
if (!IsBracketComplete(query.Search))
54+
{
55+
return new List<Result>
56+
{
57+
new Result
58+
{
59+
Title = Localize.flowlauncher_plugin_calculator_expression_not_complete(),
60+
IcoPath = "Images/calculator.png"
61+
}
62+
};
63+
}
64+
5165
try
5266
{
5367
var expression = NumberRegex.Replace(query.Search, m => NormalizeNumber(m.Value));
@@ -60,7 +74,7 @@ public List<Result> Query(Query query)
6074
do
6175
{
6276
previous = expression;
63-
expression = Regex.Replace(previous, @"\bpow\s*\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)", "($1^$2)");
77+
expression = PowRegex.Replace(previous, PowMatchEvaluator);
6478
} while (previous != expression);
6579
// WORKAROUND END
6680

@@ -131,6 +145,57 @@ public List<Result> Query(Query query)
131145
return new List<Result>();
132146
}
133147

148+
private static string PowMatchEvaluator(Match m)
149+
{
150+
// m.Groups[1].Value will be `(...)` with parens
151+
var contentWithParen = m.Groups[1].Value;
152+
// remove outer parens. `(min(2,3), 4)` becomes `min(2,3), 4`
153+
var argsContent = contentWithParen.Substring(1, contentWithParen.Length - 2);
154+
155+
var bracketCount = 0;
156+
var splitIndex = -1;
157+
158+
// Find the top-level comma that separates the two arguments of pow.
159+
for (var i = 0; i < argsContent.Length; i++)
160+
{
161+
switch (argsContent[i])
162+
{
163+
case '(':
164+
case '[':
165+
bracketCount++;
166+
break;
167+
case ')':
168+
case ']':
169+
bracketCount--;
170+
break;
171+
case ',' when bracketCount == 0:
172+
splitIndex = i;
173+
break;
174+
}
175+
176+
if (splitIndex != -1)
177+
break;
178+
}
179+
180+
if (splitIndex == -1)
181+
{
182+
// This indicates malformed arguments for pow, e.g., pow(5) or pow().
183+
// Return original string to let Mages handle the error.
184+
return m.Value;
185+
}
186+
187+
var arg1 = argsContent.Substring(0, splitIndex).Trim();
188+
var arg2 = argsContent.Substring(splitIndex + 1).Trim();
189+
190+
// Check for empty arguments which can happen with stray commas, e.g., pow(,5)
191+
if (string.IsNullOrEmpty(arg1) || string.IsNullOrEmpty(arg2))
192+
{
193+
return m.Value;
194+
}
195+
196+
return $"({arg1}^{arg2})";
197+
}
198+
134199
/// <summary>
135200
/// Parses a string representation of a number using the system's current culture.
136201
/// </summary>
@@ -208,21 +273,6 @@ private string GetGroupSeparator(string decimalSeparator)
208273
return decimalSeparator == Dot ? Comma : Dot;
209274
}
210275

211-
private bool CanCalculate(Query query)
212-
{
213-
if (string.IsNullOrWhiteSpace(query.Search))
214-
{
215-
return false;
216-
}
217-
218-
if (!IsBracketComplete(query.Search))
219-
{
220-
return false;
221-
}
222-
223-
return true;
224-
}
225-
226276
private string GetDecimalSeparator()
227277
{
228278
string systemDecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
@@ -249,6 +299,11 @@ private static bool IsBracketComplete(string query)
249299
{
250300
leftBracketCount--;
251301
}
302+
303+
if (leftBracketCount < 0)
304+
{
305+
return false;
306+
}
252307
}
253308

254309
return leftBracketCount == 0;

0 commit comments

Comments
 (0)