diff --git a/src/dev/DevToys.Startup/Package.appxmanifest b/src/dev/DevToys.Startup/Package.appxmanifest
index 3bec993557..c4d57e3f1f 100644
--- a/src/dev/DevToys.Startup/Package.appxmanifest
+++ b/src/dev/DevToys.Startup/Package.appxmanifest
@@ -15,7 +15,7 @@
+ Version="1.0.9.0" />
DevToys - Preview
diff --git a/src/dev/impl/DevToys/Core/Collections/ExtendedObservableCollection.cs b/src/dev/impl/DevToys/Core/Collections/ExtendedObservableCollection.cs
index 6e54bc466a..f24deec200 100644
--- a/src/dev/impl/DevToys/Core/Collections/ExtendedObservableCollection.cs
+++ b/src/dev/impl/DevToys/Core/Collections/ExtendedObservableCollection.cs
@@ -48,7 +48,7 @@ internal void Update(IEnumerable newItems)
foreach (T? item in newItems)
{
int indexOfItemInOldMenu = IndexOf(item);
- if (indexOfItemInOldMenu > -1)
+ if (indexOfItemInOldMenu > -1 && insertionIndex < Count)
{
if (indexOfItemInOldMenu != insertionIndex)
{
diff --git a/src/dev/impl/DevToys/LanguageManager.cs b/src/dev/impl/DevToys/LanguageManager.cs
index 34fcb706ae..acbfc2baa2 100644
--- a/src/dev/impl/DevToys/LanguageManager.cs
+++ b/src/dev/impl/DevToys/LanguageManager.cs
@@ -2417,6 +2417,16 @@ public class RegExStrings : ObservableObject
/// Gets the resource SearchKeywords.
///
public string SearchKeywords => _resources.GetString("SearchKeywords");
+
+ ///
+ /// Gets the resource InputTitle.
+ ///
+ public string InputTitle => _resources.GetString("InputTitle");
+
+ ///
+ /// Gets the resource OutputTitle.
+ ///
+ public string OutputTitle => _resources.GetString("OutputTitle");
}
public class SearchResultStrings : ObservableObject
diff --git a/src/dev/impl/DevToys/Strings/en-US/RegEx.resw b/src/dev/impl/DevToys/Strings/en-US/RegEx.resw
index 65e6f9bf48..7292dac888 100644
--- a/src/dev/impl/DevToys/Strings/en-US/RegEx.resw
+++ b/src/dev/impl/DevToys/Strings/en-US/RegEx.resw
@@ -186,4 +186,10 @@
Regular expression
+
+ Input
+
+
+ Output
+
\ No newline at end of file
diff --git a/src/dev/impl/DevToys/UI/Controls/CustomTextBox.xaml.cs b/src/dev/impl/DevToys/UI/Controls/CustomTextBox.xaml.cs
index d87c9cdf17..e81e02445d 100644
--- a/src/dev/impl/DevToys/UI/Controls/CustomTextBox.xaml.cs
+++ b/src/dev/impl/DevToys/UI/Controls/CustomTextBox.xaml.cs
@@ -8,6 +8,7 @@
using DevToys.Core;
using DevToys.Core.Settings;
using DevToys.Core.Threading;
+using DevToys.MonacoEditor.Monaco;
using Microsoft.Toolkit.Mvvm.Input;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
@@ -16,6 +17,7 @@
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Media;
using Clipboard = Windows.ApplicationModel.DataTransfer.Clipboard;
@@ -315,9 +317,6 @@ private void ExecuteSelectAllCommand()
public void SetHighlights(IEnumerable? spans)
{
- IEnumerable? highlightsToRemove = _highlightedSpans?.Except(spans ?? Array.Empty());
- IEnumerable? highlightsToAdd = spans?.Except(_highlightedSpans ?? Array.Empty());
-
_highlightedSpans = spans;
if (!IsRichTextEdit)
@@ -328,31 +327,49 @@ public void SetHighlights(IEnumerable? spans)
RichEditBox? richEditBox = GetRichEditBox();
richEditBox.TextDocument.BatchDisplayUpdates();
- if (highlightsToRemove is not null)
+ if (spans is not null && spans.Any())
{
- foreach (HighlightSpan span in highlightsToRemove)
+ HighlightSpan[] spansArray = spans.ToArray();
+ int clearFormattingStartIndex = 0;
+ for (int i = 0; i < spansArray.Length; i++)
{
+ HighlightSpan span = spansArray[i];
ITextRange range
= richEditBox.TextDocument.GetRange(
span.StartIndex,
span.StartIndex + span.Length);
- range.CharacterFormat.BackgroundColor = Colors.Transparent;
- range.CharacterFormat.ForegroundColor = ActualTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
+ range.CharacterFormat.BackgroundColor = span.BackgroundColor;
+ range.CharacterFormat.ForegroundColor = span.ForegroundColor;
+
+ if (span.StartIndex - clearFormattingStartIndex > 0)
+ {
+ range
+ = richEditBox.TextDocument.GetRange(
+ clearFormattingStartIndex,
+ span.StartIndex);
+ range.CharacterFormat.BackgroundColor = Colors.Transparent;
+ range.CharacterFormat.ForegroundColor = ActualTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
+ }
+
+ clearFormattingStartIndex = span.StartIndex + span.Length;
}
- }
- if (highlightsToAdd is not null)
- {
- foreach (HighlightSpan span in highlightsToAdd)
+ if (Text.Length - clearFormattingStartIndex > 0)
{
ITextRange range
- = richEditBox.TextDocument.GetRange(
- span.StartIndex,
- span.StartIndex + span.Length);
- range.CharacterFormat.BackgroundColor = span.BackgroundColor;
- range.CharacterFormat.ForegroundColor = span.ForegroundColor;
+ = richEditBox.TextDocument.GetRange(
+ clearFormattingStartIndex,
+ Text.Length);
+ range.CharacterFormat.BackgroundColor = Colors.Transparent;
+ range.CharacterFormat.ForegroundColor = ActualTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
}
}
+ else
+ {
+ ITextRange range = richEditBox.TextDocument.GetRange(0, Text.Length);
+ range.CharacterFormat.BackgroundColor = Colors.Transparent;
+ range.CharacterFormat.ForegroundColor = ActualTheme == ElementTheme.Dark ? Colors.White : Colors.Black;
+ }
richEditBox.TextDocument.ApplyDisplayUpdates();
}
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/Text/RegEx/RegExToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/Text/RegEx/RegExToolViewModel.cs
index 1acad443bb..350a7d7822 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/Text/RegEx/RegExToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/Text/RegEx/RegExToolViewModel.cs
@@ -3,11 +3,13 @@
using System;
using System.Collections.Generic;
using System.Composition;
+using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DevToys.Api.Core;
using DevToys.Api.Core.Settings;
using DevToys.Api.Tools;
+using DevToys.Core.Collections;
using DevToys.Core.Threading;
using DevToys.Shared.Core.Threading;
using DevToys.UI.Controls;
@@ -196,6 +198,40 @@ internal string? Text
}
}
+ private string? _errorMsg;
+ internal string? ErrorMsg
+ {
+ get => _errorMsg;
+ set
+ {
+ SetProperty(ref _errorMsg, value);
+ }
+ }
+
+ internal ExtendedObservableCollection MatchGroups { get; } = new();
+
+ private string? _inputValue;
+ internal string? InputValue
+ {
+ get => _inputValue;
+ set
+ {
+ SetProperty(ref _inputValue, value);
+ QueueRegExMatch();
+ }
+ }
+
+ private string? _outputValue;
+ internal string? OutputValue
+ {
+ get => _outputValue;
+ set
+ {
+ SetProperty(ref _outputValue, value);
+ QueueRegExMatch();
+ }
+ }
+
internal ICustomTextBox? MatchTextBox { private get; set; }
[ImportingConstructor]
@@ -225,52 +261,86 @@ private async Task TreatQueueAsync()
await ThreadHelper.RunOnUIThreadAsync(() =>
{
ElementTheme currentTheme = ((Frame)Window.Current.Content).ActualTheme;
- string? highlighterBackgroundResourceName = currentTheme == ElementTheme.Light ? "SystemAccentColorLight2" : "SystemAccentColorDark1";
+ string? highlighterBackgroundResourceName = currentTheme == ElementTheme.Light
+ ? "SystemAccentColorLight2"
+ : "SystemAccentColorDark1";
highlighterForegroundColor = currentTheme == ElementTheme.Light ? Colors.Black : Colors.White;
highlighterBackgroundColor = (Color)Application.Current.Resources[highlighterBackgroundResourceName];
});
await TaskScheduler.Default;
-
+ string errorMsg = "";
while (_regExMatchingQueue.TryDequeue(out (string pattern, string text) data))
{
var spans = new List();
-
- try
+ MatchCollection? matches = null;
+ Regex? regex = null;
+ if (!String.IsNullOrWhiteSpace(data.pattern))
{
- string? pattern = data.pattern.Trim('/');
-
- var regex = new Regex(data.pattern, GetOptions());
- MatchCollection matches = regex.Matches(data.text);
-
- foreach (Match match in matches)
+ try
{
- int lineCount = CountLines(data.text, match.Index);
- spans.Add(
- new HighlightSpan()
- {
- StartIndex = match.Index - lineCount,
- Length = match.Length,
- BackgroundColor = highlighterBackgroundColor,
- ForegroundColor = highlighterForegroundColor
- });
+ string? pattern = data.pattern.Trim('/');
+ regex = new Regex(data.pattern, GetOptions());
+ matches = regex.Matches(data.text);
+ foreach (Match match in matches)
+ {
+ int lineCount = CountLines(data.text, match.Index);
+ spans.Add(
+ new HighlightSpan()
+ {
+ StartIndex = match.Index - lineCount,
+ Length = match.Length,
+ BackgroundColor = highlighterBackgroundColor,
+ ForegroundColor = highlighterForegroundColor
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ errorMsg = ex.Message;
+ // TODO: indicate the user that the regex is wrong.
}
- }
- catch
- {
- // TODO: indicate the user that the regex is wrong.
}
ThreadHelper.RunOnUIThreadAsync(
ThreadPriority.Low,
() =>
{
- MatchTextBox?.SetHighlights(spans);
+ ErrorMsg = errorMsg;
+ if (matches != null)
+ {
+ MatchTextBox?.SetHighlights(spans);
+
+ IEnumerable matchesGroups
+ = matches
+ .Cast()
+ .SelectMany(
+ (c, inx) => c.Groups
+ .Cast()
+ .OrderBy(g => g.Index)
+ .Select(mm => new MatchDetails2
+ {
+ Title = (mm.Name == "0" ? $"Match {inx + 1}:" : $" Group \"{mm.Name}\""),
+ Range = $"{mm.Index}-{mm.Index + mm.Length}",
+ Value = mm.Value
+ }));
+ MatchGroups.Update(matchesGroups);
+
+ if (InputValue != null)
+ {
+ OutputValue = regex?.Replace(data.text, InputValue);
+ }
- if (spans.Count > 0 && !_toolSuccessfullyWorked)
+ if (spans.Count > 0 && !_toolSuccessfullyWorked)
+ {
+ _toolSuccessfullyWorked = true;
+ _marketingService.NotifyToolSuccessfullyWorked();
+ }
+ }
+ else
{
- _toolSuccessfullyWorked = true;
- _marketingService.NotifyToolSuccessfullyWorked();
+ MatchGroups.Clear();
+ MatchTextBox?.SetHighlights(null);
}
}).ForgetSafely();
}
@@ -315,6 +385,11 @@ private RegexOptions GetOptions()
private int CountLines(string input, int maxLength)
{
+ if (string.IsNullOrEmpty(input))
+ {
+ return 0;
+ }
+
int lines = 0;
int i = 0;
while (i > -1 && i < maxLength)
@@ -330,4 +405,11 @@ private int CountLines(string input, int maxLength)
return lines;
}
}
+
+ public record MatchDetails2
+ {
+ public string Title { get; set; }
+ public string Range { get; set; }
+ public string Value { get; set; }
+ }
}
diff --git a/src/dev/impl/DevToys/Views/Tools/Text/RegEx/RegExToolPage.xaml b/src/dev/impl/DevToys/Views/Tools/Text/RegEx/RegExToolPage.xaml
index b66d2512c1..c53bc3b4a7 100644
--- a/src/dev/impl/DevToys/Views/Tools/Text/RegEx/RegExToolPage.xaml
+++ b/src/dev/impl/DevToys/Views/Tools/Text/RegEx/RegExToolPage.xaml
@@ -4,94 +4,106 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:controls="using:DevToys.UI.Controls" xmlns:converters="using:DevToys.UI.Converters"
- mc:Ignorable="d"
- NavigationCacheMode="Required">
+ xmlns:controls="using:DevToys.UI.Controls"
+ xmlns:converters="using:DevToys.UI.Converters"
+ xmlns:regEx="using:DevToys.ViewModels.Tools.RegEx"
+ xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
+ NavigationCacheMode="Required"
+ mc:Ignorable="d">
-
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
-
-
+
+
-
+
-
+
-
+ Description="{x:Bind Path=ViewModel.Strings.EcmaScriptDescription}">
+
-
+ Description="{x:Bind Path=ViewModel.Strings.CultureInvariantDescription}">
+
-
+ Description="{x:Bind Path=ViewModel.Strings.IgnoreCaseDescription}">
+
+ Description="{x:Bind Path=ViewModel.Strings.IgnoreWhitespaceDescription}">
+ IsEnabled="{x:Bind Converter={StaticResource InvertedBooleanConverter}, Mode=OneWay, Path=ViewModel.EcmaScript}"
+ IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.IgnoreWhitespace, UpdateSourceTrigger=PropertyChanged}"
+ Style="{StaticResource RightAlignedToggleSwitchStyle}" />
+ Description="{x:Bind Path=ViewModel.Strings.SinglelineDescription}">
+ IsEnabled="{x:Bind Converter={StaticResource InvertedBooleanConverter}, Mode=OneWay, Path=ViewModel.EcmaScript}"
+ IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.Singleline, UpdateSourceTrigger=PropertyChanged}"
+ Style="{StaticResource RightAlignedToggleSwitchStyle}" />
-
+ Description="{x:Bind Path=ViewModel.Strings.MultilineDescription}">
+
+ Description="{x:Bind Path=ViewModel.Strings.RightToLeftDescription}">
+ IsEnabled="{x:Bind Converter={StaticResource InvertedBooleanConverter}, Mode=OneWay, Path=ViewModel.EcmaScript}"
+ IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.RightToLeft, UpdateSourceTrigger=PropertyChanged}"
+ Style="{StaticResource RightAlignedToggleSwitchStyle}" />
@@ -100,16 +112,48 @@
+ Header="{x:Bind Path=ViewModel.Strings.RegularExpression}"
+ Text="{x:Bind Mode=TwoWay, Path=ViewModel.RegularExpression, UpdateSourceTrigger=PropertyChanged}" />
+
+
+ Text="{x:Bind Mode=TwoWay, Path=ViewModel.Text, UpdateSourceTrigger=PropertyChanged}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/dev/shared/SharedAssemblyInfo.cs b/src/dev/shared/SharedAssemblyInfo.cs
index 10b703abb9..1984014948 100644
--- a/src/dev/shared/SharedAssemblyInfo.cs
+++ b/src/dev/shared/SharedAssemblyInfo.cs
@@ -37,7 +37,7 @@
// Please DO NOT commit changes on the 2 lines below unless
// you're about to release a new version of the app on the Store.
-[assembly: AssemblyVersion("0.0.0.0")]
-[assembly: AssemblyFileVersion("0.0.0.0")]
+[assembly: AssemblyVersion("1.0.9.0")]
+[assembly: AssemblyFileVersion("1.0.9.0")]
[assembly: InternalsVisibleTo("DevToys.Tests")]