diff --git a/ICSharpCode.AvalonEdit.Tests/Rendering/LinkElementGeneratorTests.cs b/ICSharpCode.AvalonEdit.Tests/Rendering/LinkElementGeneratorTests.cs
new file mode 100644
index 00000000..a1951735
--- /dev/null
+++ b/ICSharpCode.AvalonEdit.Tests/Rendering/LinkElementGeneratorTests.cs
@@ -0,0 +1,77 @@
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Rendering;
+
+using NUnit.Framework;
+
+namespace ICSharpCode.AvalonEdit.Tests.Rendering
+{
+ [TestFixture]
+ [Apartment(System.Threading.ApartmentState.STA)]
+ public class LinkElementGeneratorTests
+ {
+ [Test]
+ public void ParsingOfCustomLinkRegexes()
+ {
+ var linkElementGenerator = new LinkElementGenerator();
+ const string link = "example://mylink";
+ const string input = "Visit " + link + " please";
+ var textSource = GetTextSource(input);
+ linkElementGenerator.StartGeneration(textSource);
+
+ var interestedOffsetBeforeCustomRegex = linkElementGenerator.GetFirstInterestedOffset(0);
+ Assert.That(interestedOffsetBeforeCustomRegex, Is.EqualTo(-1));
+
+ var optionsWithCustomLink = new TextEditorOptions {
+ // Check for example:// protocol instead of http:// protocol.
+ LinkRegex = @"\bexample://\w+\b",
+ };
+ ((IBuiltinElementGenerator)linkElementGenerator).FetchOptions(optionsWithCustomLink);
+
+ var interestedOffsetAfterCustomRegex = linkElementGenerator.GetFirstInterestedOffset(0);
+ var expectedOffset = input.IndexOf(link);
+ Assert.That(interestedOffsetAfterCustomRegex, Is.EqualTo(expectedOffset));
+
+ linkElementGenerator.FinishGeneration();
+ }
+
+ [Test]
+ public void ParsingOfCustomMailRegexes()
+ {
+ var linkElementGenerator = new MailLinkElementGenerator();
+ const string link = "example@example.verylongtld";
+ const string input = "Email " + link + " please";
+ var textSource = GetTextSource(input);
+ linkElementGenerator.StartGeneration(textSource);
+
+ var interestedOffsetBeforeCustomRegex = linkElementGenerator.GetFirstInterestedOffset(0);
+ Assert.That(interestedOffsetBeforeCustomRegex, Is.EqualTo(-1));
+
+ var optionsWithCustomLink = new TextEditorOptions {
+ // The same as the default except that TLDs can be up to 12 chars now.
+ MailRegex = @"\b[\w\d\.\-]+\@[\w\d\.\-]+\.[a-z]{2,12}\b",
+ };
+ ((IBuiltinElementGenerator)linkElementGenerator).FetchOptions(optionsWithCustomLink);
+
+ var interestedOffsetAfterCustomRegex = linkElementGenerator.GetFirstInterestedOffset(0);
+ var expectedOffset = input.IndexOf(link);
+ Assert.That(interestedOffsetAfterCustomRegex, Is.EqualTo(expectedOffset));
+
+ linkElementGenerator.FinishGeneration();
+ }
+
+ private static VisualLineTextSource GetTextSource(string input)
+ {
+ var textDocument = new TextDocument(input);
+ var textView = new TextView {
+ Document = textDocument,
+ };
+ var documentLine = textDocument.Lines[0];
+ var visualLine = textView.GetOrConstructVisualLine(documentLine);
+ var textSource = new VisualLineTextSource(visualLine) {
+ Document = textDocument,
+ TextView = textView,
+ };
+ return textSource;
+ }
+ }
+}
diff --git a/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs b/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs
index eb838fc2..1d66c528 100644
--- a/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs
+++ b/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs
@@ -41,7 +41,10 @@ public class LinkElementGenerator : VisualLineElementGenerator, IBuiltinElementG
// try to detect email addresses
internal readonly static Regex defaultMailRegex = new Regex(@"\b[\w\d\.\-]+\@[\w\d\.\-]+\.[a-z]{2,6}\b");
- readonly Regex linkRegex;
+ ///
+ /// The regex used to parse the type of link this class represents.
+ ///
+ protected Regex linkRegex;
///
/// Gets/Sets whether the user needs to press Control to click the link.
@@ -71,6 +74,7 @@ protected LinkElementGenerator(Regex regex) : this()
void IBuiltinElementGenerator.FetchOptions(TextEditorOptions options)
{
this.RequireControlModifierForClick = options.RequireControlModifierForHyperlinkClick;
+ this.linkRegex = new Regex(options.LinkRegex);
}
Match GetMatch(int startOffset, out int matchOffset)
@@ -142,7 +146,7 @@ protected virtual Uri GetUriFromMatch(Match match)
/// This element generator can be easily enabled and configured using the
/// .
///
- sealed class MailLinkElementGenerator : LinkElementGenerator
+ sealed class MailLinkElementGenerator : LinkElementGenerator, IBuiltinElementGenerator
{
///
/// Creates a new MailLinkElementGenerator.
@@ -152,6 +156,12 @@ public MailLinkElementGenerator()
{
}
+ void IBuiltinElementGenerator.FetchOptions(TextEditorOptions options)
+ {
+ this.RequireControlModifierForClick = options.RequireControlModifierForHyperlinkClick;
+ this.linkRegex = new Regex(options.MailRegex);
+ }
+
protected override Uri GetUriFromMatch(Match match)
{
var targetUrl = "mailto:" + match.Value;
diff --git a/ICSharpCode.AvalonEdit/TextEditorOptions.cs b/ICSharpCode.AvalonEdit/TextEditorOptions.cs
index 66ee37f9..ed9cbdad 100644
--- a/ICSharpCode.AvalonEdit/TextEditorOptions.cs
+++ b/ICSharpCode.AvalonEdit/TextEditorOptions.cs
@@ -19,6 +19,9 @@
using System;
using System.ComponentModel;
using System.Reflection;
+using System.Text.RegularExpressions;
+
+using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.AvalonEdit
{
@@ -166,6 +169,20 @@ public virtual bool EnableHyperlinks {
}
}
+ string linkRegex = LinkElementGenerator.defaultLinkRegex.ToString();
+ ///
+ /// Gets/Sets the regex used to parse hyperlinks.
+ ///
+ public virtual string LinkRegex {
+ get { return linkRegex; }
+ set {
+ if (!Equals(linkRegex, value)) {
+ linkRegex = value;
+ OnPropertyChanged(nameof(LinkRegex));
+ }
+ }
+ }
+
bool enableEmailHyperlinks = true;
///
@@ -183,6 +200,20 @@ public virtual bool EnableEmailHyperlinks {
}
}
+ string mailRegex = LinkElementGenerator.defaultMailRegex.ToString();
+ ///
+ /// Gets/Sets the regex used to parse mail hyperlinks.
+ ///
+ public virtual string MailRegex {
+ get { return mailRegex; }
+ set {
+ if (!Equals(mailRegex, value)) {
+ mailRegex = value;
+ OnPropertyChanged(nameof(MailRegex));
+ }
+ }
+ }
+
bool requireControlModifierForHyperlinkClick = true;
///