diff --git a/ColorCode.Core/CodeColorizerBase.cs b/ColorCode.Core/CodeColorizerBase.cs
index 2618b58..b155600 100644
--- a/ColorCode.Core/CodeColorizerBase.cs
+++ b/ColorCode.Core/CodeColorizerBase.cs
@@ -1,7 +1,6 @@
using ColorCode.Compilation;
using ColorCode.Parsing;
using ColorCode.Styling;
-using System.Collections.Generic;
namespace ColorCode
{
@@ -20,13 +19,6 @@ public CodeColorizerBase(StyleDictionary Styles, ILanguageParser languageParser)
this.Styles = Styles ?? StyleDictionary.DefaultLight;
}
- ///
- /// Writes the parsed source code to the ouput using the specified style sheet.
- ///
- /// The parsed source code to format and write to the output.
- /// The captured scopes for the parsed source code.
- protected abstract void Write(string parsedSourceCode, IList scopes);
-
///
/// The language parser that the instance will use for its lifetime.
///
diff --git a/ColorCode.HTML/HtmlClassFormatter.cs b/ColorCode.HTML/HtmlClassFormatter.cs
index ac1918d..5b4853c 100644
--- a/ColorCode.HTML/HtmlClassFormatter.cs
+++ b/ColorCode.HTML/HtmlClassFormatter.cs
@@ -85,7 +85,7 @@ public string GetCSSString()
return str.ToString();
}
- protected override void Write(string parsedSourceCode, IList scopes)
+ protected void Write(string parsedSourceCode, IList scopes)
{
var styleInsertions = new List();
diff --git a/ColorCode.HTML/HtmlFormatter.cs b/ColorCode.HTML/HtmlFormatter.cs
index 0970cd0..1f5561f 100644
--- a/ColorCode.HTML/HtmlFormatter.cs
+++ b/ColorCode.HTML/HtmlFormatter.cs
@@ -52,7 +52,7 @@ public string GetHtmlString(string sourceCode, ILanguage language)
return buffer.ToString();
}
- protected override void Write(string parsedSourceCode, IList scopes)
+ protected void Write(string parsedSourceCode, IList scopes)
{
var styleInsertions = new List();
diff --git a/ColorCode.UWP/Common/ExtensionMethods.cs b/ColorCode.UWP/Common/ExtensionMethods.cs
index 0b0eed9..acea1e6 100644
--- a/ColorCode.UWP/Common/ExtensionMethods.cs
+++ b/ColorCode.UWP/Common/ExtensionMethods.cs
@@ -1,4 +1,5 @@
using System;
+using Windows.UI;
using Windows.UI.Xaml.Media;
namespace ColorCode.UWP.Common
@@ -6,6 +7,13 @@ namespace ColorCode.UWP.Common
public static class ExtensionMethods
{
public static SolidColorBrush GetSolidColorBrush(this string hex)
+ {
+ var color = GetColor(hex);
+ SolidColorBrush myBrush = new SolidColorBrush(color);
+ return myBrush;
+ }
+
+ public static Color GetColor(this string hex)
{
hex = hex.Replace("#", string.Empty);
@@ -23,8 +31,7 @@ public static SolidColorBrush GetSolidColorBrush(this string hex)
byte g = (byte)(Convert.ToUInt32(hex.Substring(index, 2), 16));
index += 2;
byte b = (byte)(Convert.ToUInt32(hex.Substring(index, 2), 16));
- SolidColorBrush myBrush = new SolidColorBrush(Windows.UI.Color.FromArgb(a, r, g, b));
- return myBrush;
+ return Color.FromArgb(a, r, g, b);
}
}
}
\ No newline at end of file
diff --git a/ColorCode.UWP/Common/VisualHelpers.cs b/ColorCode.UWP/Common/VisualHelpers.cs
new file mode 100644
index 0000000..643cdf9
--- /dev/null
+++ b/ColorCode.UWP/Common/VisualHelpers.cs
@@ -0,0 +1,74 @@
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+
+namespace ColorCode.Common
+{
+ public static class VisualHelpers
+ {
+ ///
+ /// Commandbars causing crashes at the mo
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T FirstChildofType(DependencyObject parent, bool deepscan = false, bool includeCommandBars = false)
+ {
+ if (parent == null) return (T)(object)null;
+ if (deepscan)
+ {
+ if (parent is ContentPresenter presenter)
+ {
+ var _Child = presenter.Content as DependencyObject;
+ if (_Child is T)
+ {
+ return (T)(object)_Child;
+ }
+ if (!(_Child is CommandBar) || includeCommandBars)
+ {
+ var next = (FirstChildofType(_Child, deepscan));
+ if (next is T)
+ {
+ return ((T)(object)next);
+ }
+ }
+ }
+ else if (parent is ContentControl control)
+ {
+ var _Child = control.Content as DependencyObject;
+ if (_Child is T)
+ {
+ return (T)(object)_Child;
+ }
+ if (!(_Child is CommandBar) || includeCommandBars)
+ {
+ var next = (FirstChildofType(_Child, deepscan));
+ if (next is T)
+ {
+ return ((T)(object)next);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
+ {
+ var _Child = VisualTreeHelper.GetChild(parent, i);
+ if (_Child is T)
+ {
+ return ((T)(object)_Child);
+ }
+ if (!(_Child is CommandBar) || includeCommandBars)
+ {
+ var next = (FirstChildofType(_Child, deepscan));
+ if (next is T)
+ {
+ return ((T)(object)next);
+ }
+ }
+ }
+ return (T)(object)null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ColorCode.UWP/RichEditBoxFormatter.cs b/ColorCode.UWP/RichEditBoxFormatter.cs
new file mode 100644
index 0000000..437d57b
--- /dev/null
+++ b/ColorCode.UWP/RichEditBoxFormatter.cs
@@ -0,0 +1,196 @@
+using System.Collections.Generic;
+using ColorCode.Parsing;
+using Windows.UI.Xaml.Controls;
+using ColorCode.Styling;
+using Windows.UI.Text;
+using ColorCode.UWP.Common;
+using ColorCode.Common;
+using Windows.UI.Xaml;
+using System.Text.RegularExpressions;
+
+namespace ColorCode
+{
+ ///
+ /// Creates a , for rendering Syntax Highlighted code to a RichTextBlock.
+ ///
+ public class RichEditBoxFormatter : CodeColorizerBase
+ {
+ ///
+ /// Creates a , for rendering Syntax Highlighted code to a RichTextBlock.
+ ///
+ /// The Theme to use, determines whether to use Default Light or Default Dark.
+ public RichEditBoxFormatter(ElementTheme Theme, ILanguageParser languageParser = null) : this(Theme == ElementTheme.Dark ? StyleDictionary.DefaultDark : StyleDictionary.DefaultLight, languageParser)
+ {
+ }
+
+ ///
+ /// Creates a , for rendering Syntax Highlighted code to a RichTextBlock.
+ ///
+ /// The Custom styles to Apply to the formatted Code.
+ /// The language parser that the instance will use for its lifetime.
+ public RichEditBoxFormatter(StyleDictionary Style = null, ILanguageParser languageParser = null) : base(Style, languageParser)
+ {
+ }
+
+ private RichEditBox RichEdit { get; set; }
+
+ public ILanguage Language
+ {
+ get => _Language;
+ set
+ {
+ _Language = value;
+ UpdateText();
+ }
+ }
+
+ private ILanguage _Language;
+
+ ///
+ /// Adds Syntax Highlighted Source Code to the provided RichTextBlock.
+ ///
+ /// The source code to colorize.
+ /// The language to use to colorize the source code.
+ /// The Control to add the Text to.
+ public void AttachRichEditBox(RichEditBox RichEdit, ILanguage Language)
+ {
+ this.RichEdit = RichEdit;
+ RichEdit.TextChanging += RichEdit_TextChanging;
+ this.Language = Language;
+ }
+
+ private void RichEdit_TextChanging(RichEditBox sender, RichEditBoxTextChangingEventArgs args)
+ {
+ if (args.IsContentChanging)
+ {
+ UpdateText();
+ }
+ }
+
+ public void UpdateText()
+ {
+ if (RichEdit != null)
+ {
+ // Attempt to get Scrollviewer offsets, to preserve location.
+ var scroll = VisualHelpers.FirstChildofType(RichEdit);
+ var vertOffset = scroll?.VerticalOffset;
+ var horOffset = scroll?.HorizontalOffset;
+
+ var selection = RichEdit.Document.Selection;
+ var selectionStart = selection.StartPosition;
+ var selectionEnd = selection.EndPosition;
+
+ RichEdit.Document.GetText(TextGetOptions.UseCrlf, out string raw);
+ RichEdit.Document.Undo();
+
+ RichEdit.Document.BeginUndoGroup();
+ RichEdit.Document.SetText(TextSetOptions.None, raw);
+
+ var newSelection = RichEdit.Document.Selection;
+ newSelection.StartPosition = selectionStart;
+ newSelection.EndPosition = selectionEnd;
+
+ Index = 0;
+ source = raw;
+
+ languageParser.Parse(raw, Language, (range, captures) => Style(range, captures));
+ RichEdit.Document.ApplyDisplayUpdates();
+ RichEdit.Document.EndUndoGroup();
+
+ if (scroll != null)
+ {
+ scroll.ChangeView(horOffset, vertOffset, null, true);
+ }
+ }
+ }
+
+ private static int Index = 0;
+ private static string source = string.Empty;
+
+ protected void Style(string range, IList scopes)
+ {
+ var scopeRange = source.Substring(Index);
+
+ var start = Index;
+
+ try
+ {
+ var previous = source.Remove(Index);
+ var crlfCorrection = CountOccurences(previous, "\r\n");
+ start -= crlfCorrection;
+ }
+ catch
+ {
+ }
+
+ var subIndex = scopeRange.IndexOf(range);
+ if (subIndex != -1)
+ {
+ start += subIndex;
+ }
+
+ foreach (var scope in scopes)
+ {
+ StyleFromScope(start, scope);
+ }
+
+ Index += range.Length;
+ }
+
+ private int CountOccurences(string str, string match)
+ {
+ return Regex.Matches(str, match).Count;
+ }
+
+ private void StyleFromScope(int Start, Scope Scope)
+ {
+ Start += Scope.Index;
+ var Range = RichEdit.Document.GetRange(Start, Start + Scope.Length);
+
+ string foreground = null;
+ string background = null;
+ bool italic = false;
+ bool bold = false;
+
+ if (Styles.Contains(Scope.Name))
+ {
+ Styling.Style style = Styles[Scope.Name];
+
+ foreground = style.Foreground;
+ background = style.Background;
+ italic = style.Italic;
+ bold = style.Bold;
+ }
+
+ if (!string.IsNullOrWhiteSpace(foreground))
+ {
+ Range.CharacterFormat.ForegroundColor = foreground.GetColor();
+ }
+
+ if (!string.IsNullOrWhiteSpace(background))
+ {
+ Range.CharacterFormat.BackgroundColor = background.GetColor();
+ }
+
+ if (italic)
+ Range.CharacterFormat.Italic = FormatEffect.On;
+
+ if (bold)
+ Range.CharacterFormat.Bold = FormatEffect.On;
+
+ foreach (var subScope in Scope.Children)
+ {
+ StyleFromScope(Start, subScope);
+ }
+ }
+
+ private void Reset(ITextRange Range)
+ {
+ var defaults = RichEdit.Document.GetDefaultCharacterFormat();
+ Range.CharacterFormat.Italic = FormatEffect.Off;
+ Range.CharacterFormat.Bold = FormatEffect.Off;
+ Range.CharacterFormat.BackgroundColor = defaults.BackgroundColor;
+ Range.CharacterFormat.ForegroundColor = defaults.ForegroundColor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ColorCode.UWP/RichTextBlockFormatter.cs b/ColorCode.UWP/RichTextBlockFormatter.cs
index 16753b9..0de50c4 100644
--- a/ColorCode.UWP/RichTextBlockFormatter.cs
+++ b/ColorCode.UWP/RichTextBlockFormatter.cs
@@ -54,12 +54,12 @@ public void FormatRichTextBlock(string sourceCode, ILanguage Language, RichTextB
public void FormatInlines(string sourceCode, ILanguage Language, InlineCollection InlineCollection)
{
this.InlineCollection = InlineCollection;
- languageParser.Parse(sourceCode, Language, (parsedSourceCode, captures) => Write(parsedSourceCode, captures));
+ languageParser.Parse(sourceCode, Language, (parsedSourceCode, captures) => Insert(parsedSourceCode, captures));
}
private InlineCollection InlineCollection { get; set; }
- protected override void Write(string parsedSourceCode, IList scopes)
+ protected void Insert(string parsedSourceCode, IList scopes)
{
var styleInsertions = new List();
diff --git a/Tests/ColorCode.UWPTests/ColorCode.UWPTests.csproj b/Tests/ColorCode.UWPTests/ColorCode.UWPTests.csproj
index 14c131f..17caf05 100644
--- a/Tests/ColorCode.UWPTests/ColorCode.UWPTests.csproj
+++ b/Tests/ColorCode.UWPTests/ColorCode.UWPTests.csproj
@@ -97,6 +97,12 @@
MainPage.xaml
+
+ RichEditSample.xaml
+
+
+ RichTextSample.xaml
+
@@ -123,6 +129,14 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
diff --git a/Tests/ColorCode.UWPTests/MainPage.xaml b/Tests/ColorCode.UWPTests/MainPage.xaml
index 7181342..a7fd21c 100644
--- a/Tests/ColorCode.UWPTests/MainPage.xaml
+++ b/Tests/ColorCode.UWPTests/MainPage.xaml
@@ -7,22 +7,20 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ColorCode.UWPTests/MainPage.xaml.cs b/Tests/ColorCode.UWPTests/MainPage.xaml.cs
index 984cefe..a970f5d 100644
--- a/Tests/ColorCode.UWPTests/MainPage.xaml.cs
+++ b/Tests/ColorCode.UWPTests/MainPage.xaml.cs
@@ -1,17 +1,7 @@
-using ColorCode.Common;
-using ColorCode.Styling;
-using ColorCode.UWP.Common;
-using System;
-using System.IO;
-using System.Threading.Tasks;
-using Windows.Storage;
-using Windows.Storage.Pickers;
-using Windows.System;
+using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
-// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
-
namespace ColorCode.UWPTests
{
///
@@ -19,80 +9,44 @@ namespace ColorCode.UWPTests
///
public sealed partial class MainPage : Page
{
+ private SystemNavigationManager Manager;
+ private static bool HasLoaded;
+
public MainPage()
{
this.InitializeComponent();
+ this.Loaded += MainPage_Loaded;
+ Manager = SystemNavigationManager.GetForCurrentView();
}
- private async Task> GetCodeFileText()
+ private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
- var picker = new FileOpenPicker();
- picker.FileTypeFilter.Add("*");
-
- var file = await picker.PickSingleFileAsync();
- if (file == null) return null;
- string text = "";
-
- using (var reader = new StreamReader(await file.OpenStreamForReadAsync(), true))
+ if (!HasLoaded)
{
- text = await reader.ReadToEndAsync();
+ this.Frame.Navigated += Frame_Navigated;
+ Manager.BackRequested += Manager_BackRequested;
+ HasLoaded = true;
}
-
- ILanguage Language = Languages.FindById(file.FileType.Replace(".", "")) ?? Languages.CSharp;
- return new Tuple(text, Language);
- }
-
- private void RenderLight(object sender, RoutedEventArgs e)
- {
- MainGrid.RequestedTheme = ElementTheme.Light;
- Render();
- }
-
- private void RenderDark(object sender, RoutedEventArgs e)
- {
- MainGrid.RequestedTheme = ElementTheme.Dark;
- Render();
}
- private async void Render()
+ private void Manager_BackRequested(object sender, BackRequestedEventArgs e)
{
- PresentationBlock.Blocks.Clear();
-
- var result = await GetCodeFileText();
- if (result == null) return;
-
- var formatter = new RichTextBlockFormatter(MainGrid.RequestedTheme);
- var plainText = formatter.Styles[ScopeName.PlainText];
- MainGrid.Background = (plainText?.Background ?? StyleDictionary.White).GetSolidColorBrush();
- formatter.FormatRichTextBlock(result.Item1, result.Item2, PresentationBlock);
+ this.Frame.GoBack();
}
- private void HTMLLight(object sender, RoutedEventArgs e)
+ private void Frame_Navigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
- MakeHTML(StyleDictionary.DefaultLight);
+ Manager.AppViewBackButtonVisibility = Frame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed;
}
- private void HTMLDark(object sender, RoutedEventArgs e)
+ private void RichTextSample_Click(object sender, RoutedEventArgs e)
{
- MakeHTML(StyleDictionary.DefaultDark);
+ this.Frame.Navigate(typeof(RichTextSample));
}
- private async void MakeHTML(StyleDictionary Styles)
+ private void RichEditSample_Click(object sender, RoutedEventArgs e)
{
- var result = await GetCodeFileText();
- if (result == null) return;
-
- var formatter = new HtmlFormatter(Styles);
- var html = formatter.GetHtmlString(result.Item1, result.Item2);
-
- var tempfile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("HTMLResult.html", CreationCollisionOption.ReplaceExisting);
- await FileIO.WriteTextAsync(tempfile, html);
-
- try
- {
- await Launcher.LaunchFileAsync(tempfile);
- }
- catch { }
+ this.Frame.Navigate(typeof(RichEditSample));
}
}
}
\ No newline at end of file
diff --git a/Tests/ColorCode.UWPTests/RichEditSample.xaml b/Tests/ColorCode.UWPTests/RichEditSample.xaml
new file mode 100644
index 0000000..4b8917a
--- /dev/null
+++ b/Tests/ColorCode.UWPTests/RichEditSample.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ColorCode.UWPTests/RichEditSample.xaml.cs b/Tests/ColorCode.UWPTests/RichEditSample.xaml.cs
new file mode 100644
index 0000000..e064a83
--- /dev/null
+++ b/Tests/ColorCode.UWPTests/RichEditSample.xaml.cs
@@ -0,0 +1,32 @@
+using System.Linq;
+using Windows.UI.Xaml.Controls;
+
+namespace ColorCode.UWPTests
+{
+ public sealed partial class RichEditSample : Page
+ {
+ public RichEditSample()
+ {
+ this.InitializeComponent();
+ formatter = new RichEditBoxFormatter();
+
+ foreach (var language in Languages.All)
+ {
+ LanguageBox.Items.Add(language.Name);
+ }
+
+ var defaultLang = Languages.Markdown;
+ LanguageBox.SelectedItem = defaultLang.Name;
+ formatter.AttachRichEditBox(RichEdit, defaultLang);
+ LanguageBox.SelectionChanged += LanguageBox_SelectionChanged;
+ }
+
+ private void LanguageBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ var language = Languages.All.FirstOrDefault(item => item.Name == LanguageBox.SelectedItem.ToString());
+ formatter.Language = language;
+ }
+
+ private readonly RichEditBoxFormatter formatter;
+ }
+}
\ No newline at end of file
diff --git a/Tests/ColorCode.UWPTests/RichTextSample.xaml b/Tests/ColorCode.UWPTests/RichTextSample.xaml
new file mode 100644
index 0000000..16e6bbf
--- /dev/null
+++ b/Tests/ColorCode.UWPTests/RichTextSample.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ColorCode.UWPTests/RichTextSample.xaml.cs b/Tests/ColorCode.UWPTests/RichTextSample.xaml.cs
new file mode 100644
index 0000000..d0ab5e4
--- /dev/null
+++ b/Tests/ColorCode.UWPTests/RichTextSample.xaml.cs
@@ -0,0 +1,96 @@
+using ColorCode.Common;
+using ColorCode.Styling;
+using ColorCode.UWP.Common;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Windows.Storage;
+using Windows.Storage.Pickers;
+using Windows.System;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace ColorCode.UWPTests
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class RichTextSample : Page
+ {
+ public RichTextSample()
+ {
+ this.InitializeComponent();
+ }
+
+ private async Task> GetCodeFileText()
+ {
+ var picker = new FileOpenPicker();
+ picker.FileTypeFilter.Add("*");
+
+ var file = await picker.PickSingleFileAsync();
+ if (file == null) return null;
+ string text = "";
+
+ using (var reader = new StreamReader(await file.OpenStreamForReadAsync(), true))
+ {
+ text = await reader.ReadToEndAsync();
+ }
+
+ ILanguage Language = Languages.FindById(file.FileType.Replace(".", "")) ?? Languages.CSharp;
+ return new Tuple(text, Language);
+ }
+
+ private void RenderLight(object sender, RoutedEventArgs e)
+ {
+ MainGrid.RequestedTheme = ElementTheme.Light;
+ Render();
+ }
+
+ private void RenderDark(object sender, RoutedEventArgs e)
+ {
+ MainGrid.RequestedTheme = ElementTheme.Dark;
+ Render();
+ }
+
+ private async void Render()
+ {
+ PresentationBlock.Blocks.Clear();
+
+ var result = await GetCodeFileText();
+ if (result == null) return;
+
+ var formatter = new RichTextBlockFormatter(MainGrid.RequestedTheme);
+ var plainText = formatter.Styles[ScopeName.PlainText];
+ MainGrid.Background = (plainText?.Background ?? StyleDictionary.White).GetSolidColorBrush();
+ formatter.FormatRichTextBlock(result.Item1, result.Item2, PresentationBlock);
+ }
+
+ private void HTMLLight(object sender, RoutedEventArgs e)
+ {
+ MakeHTML(StyleDictionary.DefaultLight);
+ }
+
+ private void HTMLDark(object sender, RoutedEventArgs e)
+ {
+ MakeHTML(StyleDictionary.DefaultDark);
+ }
+
+ private async void MakeHTML(StyleDictionary Styles)
+ {
+ var result = await GetCodeFileText();
+ if (result == null) return;
+
+ var formatter = new HtmlFormatter(Styles);
+ var html = formatter.GetHtmlString(result.Item1, result.Item2);
+
+ var tempfile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("HTMLResult.html", CreationCollisionOption.ReplaceExisting);
+ await FileIO.WriteTextAsync(tempfile, html);
+
+ try
+ {
+ await Launcher.LaunchFileAsync(tempfile);
+ }
+ catch { }
+ }
+ }
+}
\ No newline at end of file