@@ -25,6 +25,8 @@ public class Main : IPlugin, IPluginI18n, ISettingProvider
25
25
@")+$" , RegexOptions . Compiled ) ;
26
26
private static readonly Regex RegBrackets = new Regex ( @"[\(\)\[\]]" , RegexOptions . Compiled ) ;
27
27
private static readonly Regex ThousandGroupRegex = new Regex ( @"\B(?=(\d{3})+(?!\d))" ) ;
28
+ private static readonly Regex NumberRegex = new Regex ( @"[\d\.,]+" , RegexOptions . Compiled ) ;
29
+
28
30
private static Engine MagesEngine ;
29
31
private const string comma = "," ;
30
32
private const string dot = "." ;
@@ -34,8 +36,15 @@ public class Main : IPlugin, IPluginI18n, ISettingProvider
34
36
private static Settings _settings ;
35
37
private static SettingsViewModel _viewModel ;
36
38
37
- private string _inputDecimalSeparator ;
38
- private bool _inputUsesGroupSeparators ;
39
+ /// <summary>
40
+ /// Holds the formatting information for a single query.
41
+ /// This is used to ensure thread safety by keeping query state local.
42
+ /// </summary>
43
+ private class ParsingContext
44
+ {
45
+ public string InputDecimalSeparator { get ; set ; }
46
+ public bool InputUsesGroupSeparators { get ; set ; }
47
+ }
39
48
40
49
public void Init ( PluginInitContext context )
41
50
{
@@ -59,13 +68,11 @@ public List<Result> Query(Query query)
59
68
return new List < Result > ( ) ;
60
69
}
61
70
62
- _inputDecimalSeparator = null ;
63
- _inputUsesGroupSeparators = false ;
71
+ var context = new ParsingContext ( ) ;
64
72
65
73
try
66
74
{
67
- var numberRegex = new Regex ( @"[\d\.,]+" ) ;
68
- var expression = numberRegex . Replace ( query . Search , m => NormalizeNumber ( m . Value ) ) ;
75
+ var expression = NumberRegex . Replace ( query . Search , m => NormalizeNumber ( m . Value , context ) ) ;
69
76
70
77
var result = MagesEngine . Interpret ( expression ) ;
71
78
@@ -78,7 +85,7 @@ public List<Result> Query(Query query)
78
85
if ( ! string . IsNullOrEmpty ( result ? . ToString ( ) ) )
79
86
{
80
87
decimal roundedResult = Math . Round ( Convert . ToDecimal ( result ) , _settings . MaxDecimalPlaces , MidpointRounding . AwayFromZero ) ;
81
- string newResult = FormatResult ( roundedResult ) ;
88
+ string newResult = FormatResult ( roundedResult , context ) ;
82
89
83
90
return new List < Result >
84
91
{
@@ -117,10 +124,10 @@ public List<Result> Query(Query query)
117
124
/// <summary>
118
125
/// Parses a string representation of a number, detecting its format. It uses structural analysis
119
126
/// (checking for 3-digit groups) and falls back to system culture for ambiguous cases (e.g., "1,234").
120
- /// It sets instance fields to remember the user's format for later output formatting .
127
+ /// It populates the provided ParsingContext with the detected format for later use .
121
128
/// </summary>
122
129
/// <returns>A normalized number string with '.' as the decimal separator for the Mages engine.</returns>
123
- private string NormalizeNumber ( string numberStr )
130
+ private string NormalizeNumber ( string numberStr , ParsingContext context )
124
131
{
125
132
var systemFormat = CultureInfo . CurrentCulture . NumberFormat ;
126
133
string systemDecimalSeparator = systemFormat . NumberDecimalSeparator ;
@@ -131,18 +138,18 @@ private string NormalizeNumber(string numberStr)
131
138
// Unambiguous case: both separators are present. The last one wins as decimal separator.
132
139
if ( hasDot && hasComma )
133
140
{
134
- _inputUsesGroupSeparators = true ;
141
+ context . InputUsesGroupSeparators = true ;
135
142
int lastDotPos = numberStr . LastIndexOf ( dot ) ;
136
143
int lastCommaPos = numberStr . LastIndexOf ( comma ) ;
137
144
138
145
if ( lastDotPos > lastCommaPos ) // e.g. 1,234.56
139
146
{
140
- _inputDecimalSeparator = dot ;
147
+ context . InputDecimalSeparator = dot ;
141
148
return numberStr . Replace ( comma , string . Empty ) ;
142
149
}
143
150
else // e.g. 1.234,56
144
151
{
145
- _inputDecimalSeparator = comma ;
152
+ context . InputDecimalSeparator = comma ;
146
153
return numberStr . Replace ( dot , string . Empty ) . Replace ( comma , dot ) ;
147
154
}
148
155
}
@@ -158,19 +165,19 @@ private string NormalizeNumber(string numberStr)
158
165
// Ambiguous case: "1,234". Resolve using culture.
159
166
if ( systemDecimalSeparator == comma )
160
167
{
161
- _inputDecimalSeparator = comma ;
168
+ context . InputDecimalSeparator = comma ;
162
169
return numberStr . Replace ( comma , dot ) ;
163
170
}
164
171
else
165
172
{
166
- _inputUsesGroupSeparators = true ;
173
+ context . InputUsesGroupSeparators = true ;
167
174
return numberStr . Replace ( comma , string . Empty ) ;
168
175
}
169
176
}
170
177
else
171
178
{
172
179
// Unambiguous decimal: "123,45" or "1,2,345"
173
- _inputDecimalSeparator = comma ;
180
+ context . InputDecimalSeparator = comma ;
174
181
return numberStr . Replace ( comma , dot ) ;
175
182
}
176
183
}
@@ -184,18 +191,18 @@ private string NormalizeNumber(string numberStr)
184
191
{
185
192
if ( systemDecimalSeparator == dot )
186
193
{
187
- _inputDecimalSeparator = dot ;
194
+ context . InputDecimalSeparator = dot ;
188
195
return numberStr ;
189
196
}
190
197
else
191
198
{
192
- _inputUsesGroupSeparators = true ;
199
+ context . InputUsesGroupSeparators = true ;
193
200
return numberStr . Replace ( dot , string . Empty ) ;
194
201
}
195
202
}
196
203
else
197
204
{
198
- _inputDecimalSeparator = dot ;
205
+ context . InputDecimalSeparator = dot ;
199
206
return numberStr ; // Already in Mages-compatible format
200
207
}
201
208
}
@@ -204,10 +211,10 @@ private string NormalizeNumber(string numberStr)
204
211
return numberStr ;
205
212
}
206
213
207
- private string FormatResult ( decimal roundedResult )
214
+ private string FormatResult ( decimal roundedResult , ParsingContext context )
208
215
{
209
216
// Use the detected decimal separator from the input; otherwise, fall back to settings.
210
- string decimalSeparator = _inputDecimalSeparator ?? GetDecimalSeparator ( ) ;
217
+ string decimalSeparator = context . InputDecimalSeparator ?? GetDecimalSeparator ( ) ;
211
218
string groupSeparator = decimalSeparator == dot ? comma : dot ;
212
219
213
220
string resultStr = roundedResult . ToString ( CultureInfo . InvariantCulture ) ;
@@ -216,7 +223,7 @@ private string FormatResult(decimal roundedResult)
216
223
string integerPart = parts [ 0 ] ;
217
224
string fractionalPart = parts . Length > 1 ? parts [ 1 ] : string . Empty ;
218
225
219
- if ( _inputUsesGroupSeparators )
226
+ if ( context . InputUsesGroupSeparators )
220
227
{
221
228
integerPart = ThousandGroupRegex . Replace ( integerPart , groupSeparator ) ;
222
229
}
0 commit comments