diff --git a/samples/AvalonEdit.Sample/AvalonEdit.Sample.csproj b/samples/AvalonEdit.Sample/AvalonEdit.Sample.csproj index 1502c5f7f0..44b932a4e2 100644 --- a/samples/AvalonEdit.Sample/AvalonEdit.Sample.csproj +++ b/samples/AvalonEdit.Sample/AvalonEdit.Sample.csproj @@ -1,5 +1,5 @@  - + {13A5B497-BA12-45AE-9033-22620C3153FB} Debug @@ -71,6 +71,7 @@ Code Window1.xaml + diff --git a/samples/AvalonEdit.Sample/AvalonEdit/folding.png b/samples/AvalonEdit.Sample/AvalonEdit/folding.png new file mode 100644 index 0000000000..741ca289db Binary files /dev/null and b/samples/AvalonEdit.Sample/AvalonEdit/folding.png differ diff --git a/samples/AvalonEdit.Sample/ImageElementGenerator.cs b/samples/AvalonEdit.Sample/ImageElementGenerator.cs new file mode 100644 index 0000000000..492fa4953b --- /dev/null +++ b/samples/AvalonEdit.Sample/ImageElementGenerator.cs @@ -0,0 +1,105 @@ +// Copyright (c) 2009 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Rendering; + +namespace AvalonEdit.Sample +{ + /// + /// This class can be used to embed images inside AvalonEdit like this: + /// + public class ImageElementGenerator : VisualLineElementGenerator + { + readonly static Regex imageRegex = new Regex(@"", RegexOptions.IgnoreCase); + readonly string basePath; + + public ImageElementGenerator(string basePath) + { + if (basePath == null) + throw new ArgumentNullException("basePath"); + this.basePath = basePath; + } + + Match FindMatch(int startOffset) + { + // fetch the end offset of the VisualLine being generated + int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset; + string relevantText = CurrentContext.Document.GetText(startOffset, endOffset - startOffset); + return imageRegex.Match(relevantText); + } + + /// + /// Gets the first offset >= startOffset where the generator wants to construct an element. + /// Return -1 to signal no interest. + /// + public override int GetFirstInterestedOffset(int startOffset) + { + Match m = FindMatch(startOffset); + return m.Success ? (startOffset + m.Index) : -1; + } + + /// + /// Constructs an element at the specified offset. + /// May return null if no element should be constructed. + /// + public override VisualLineElement ConstructElement(int offset) + { + Match m = FindMatch(offset); + // check whether there's a match exactly at offset + if (m.Success && m.Index == 0) { + BitmapImage bitmap = LoadBitmap(m.Groups[1].Value); + if (bitmap != null) { + Image image = new Image(); + image.Source = bitmap; + image.Width = bitmap.PixelWidth; + image.Height = bitmap.PixelHeight; + // Pass the length of the match to the 'documentLength' parameter of InlineObjectElement. + return new InlineObjectElement(m.Length, image); + } + } + return null; + } + + BitmapImage LoadBitmap(string fileName) + { + // TODO: add some kind of cache to avoid reloading the image whenever the VisualLine is reconstructed + try { + string fullFileName = Path.Combine(basePath, fileName); + if (File.Exists(fullFileName)) { + BitmapImage bitmap = new BitmapImage(new Uri(fullFileName)); + bitmap.Freeze(); + return bitmap; + } + } catch (ArgumentException) { + // invalid filename syntax + } catch (IOException) { + // other IO error + } + return null; + } + } +} diff --git a/samples/AvalonEdit.Sample/RenderingPipeline.pptx b/samples/AvalonEdit.Sample/RenderingPipeline.pptx index d9dbc81988..31a9ec8767 100644 Binary files a/samples/AvalonEdit.Sample/RenderingPipeline.pptx and b/samples/AvalonEdit.Sample/RenderingPipeline.pptx differ diff --git a/samples/AvalonEdit.Sample/Window1.xaml b/samples/AvalonEdit.Sample/Window1.xaml index f732d9be08..0286c124a4 100644 --- a/samples/AvalonEdit.Sample/Window1.xaml +++ b/samples/AvalonEdit.Sample/Window1.xaml @@ -1,4 +1,23 @@ - + + ItemsSource="{Binding Source={x:Static avalonEdit:HighlightingManager.Instance}, Path=HighlightingDefinitions}" + SelectionChanged="HighlightingComboBox_SelectionChanged"/> @@ -49,8 +69,7 @@ Name="textEditor" FontFamily="Consolas" FontSize="10pt" - > - Initial Text + >This is AvalonEdit! Embedded image: <img src="Images/Open.png"/> diff --git a/samples/AvalonEdit.Sample/Window1.xaml.cs b/samples/AvalonEdit.Sample/Window1.xaml.cs index 24cd91ba56..5ed8258c9c 100644 --- a/samples/AvalonEdit.Sample/Window1.xaml.cs +++ b/samples/AvalonEdit.Sample/Window1.xaml.cs @@ -1,9 +1,20 @@ -// -// -// -// -// $Revision$ -// +// Copyright (c) 2009 Daniel Grunwald +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; @@ -15,7 +26,9 @@ using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Threading; +using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using Microsoft.Win32; @@ -31,10 +44,15 @@ namespace AvalonEdit.Sample InitializeComponent(); propertyGridComboBox.SelectedIndex = 2; - textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - //textEditor.TextArea.TextView.ElementGenerators.Add(new WordFilterElementGenerator()); + textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#"); + textEditor.TextArea.TextView.ElementGenerators.Add(new ImageElementGenerator(Path.GetFullPath("../.."))); + + DispatcherTimer foldingUpdateTimer = new DispatcherTimer(); + foldingUpdateTimer.Interval = TimeSpan.FromSeconds(2); + foldingUpdateTimer.Tick += foldingUpdateTimer_Tick; + foldingUpdateTimer.Start(); } - + string currentFileName; void openFileClick(object sender, RoutedEventArgs e) @@ -78,5 +96,49 @@ namespace AvalonEdit.Sample break; } } + + #region Folding + FoldingManager foldingManager; + AbstractFoldingStrategy foldingStrategy; + + void HighlightingComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (textEditor.SyntaxHighlighting == null) { + foldingStrategy = null; + } else { + switch (textEditor.SyntaxHighlighting.Name) { + case "XML": + foldingStrategy = new XmlFoldingStrategy(); + break; + case "C#": + case "C++": + case "PHP": + case "Java": + foldingStrategy = new BraceFoldingStrategy(); + break; + default: + foldingStrategy = null; + break; + } + } + if (foldingStrategy != null) { + if (foldingManager == null) + foldingManager = FoldingManager.Install(textEditor.TextArea); + foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document); + } else { + if (foldingManager != null) { + FoldingManager.Uninstall(foldingManager); + foldingManager = null; + } + } + } + + void foldingUpdateTimer_Tick(object sender, EventArgs e) + { + if (foldingStrategy != null) { + foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document); + } + } + #endregion } } \ No newline at end of file diff --git a/samples/AvalonEdit.Sample/article.html b/samples/AvalonEdit.Sample/article.html index 6e8c9d574e..f6ff0832e3 100644 --- a/samples/AvalonEdit.Sample/article.html +++ b/samples/AvalonEdit.Sample/article.html @@ -1,5 +1,5 @@ - + - + @@ -32,14 +32,14 @@ CODE { COLOR: #990000; FONT-FAMILY: "Courier New", Courier, mono; } - + - + - +
    @@ -50,7 +50,7 @@ CODE { COLOR: #990000; FONT-FAMILY: "Courier New", Courier, mono; }

    Sample Image - maximum width is 600 pixels

    - + @@ -90,15 +90,17 @@ You can use it just similar to a normal WPF TextBox:

    To enable syntax highlighting, use: -

    textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".cs");
    +
    textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
    AvalonEdit has syntax highlighting definitions built in for: -ASP.NET, Batch files, Boo, Coco/R grammars, C++, C#, HTML, Java, JavaScript, Patch files, PHP, TeX, VB.NET, XML +ASP.NET, Boo, Coco/R grammars, C++, C#, HTML, Java, JavaScript, Patch files, PHP, TeX, VB, XML

    If you need more of AvalonEdit than a simple text box with syntax highlighting, you will first have to learn more about the architecture of AvalonEdit. +

    Architecture

    TODO: overview of the namespaces, insert graph from NDepend +

    Document (The Model)

    So, what is the model of a text editor that has support for complex features like syntax highlighting and folding?
    @@ -243,7 +245,7 @@ The property TextAnchor.MovementType will be used to determine whic

    TextSegmentCollection

    Sometimes it is useful to store a list of segments and be able to efficiently find all segments overlapping with some other segment.
    -Example: you might want to store a large number compiler warnings and render squiggly underlines only those that are in the visible region of the document. +Example: you might want to store a large number compiler warnings and render squiggly underlines only for those that are in the visible region of the document.

    The TextSegmentCollection serves this purpose. Connected to a document, it will automatically update the offsets of all TextSegment instances inside the collection; but it also has the useful methods FindOverlappingSegments and FindFirstSegmentWithStartAfter. @@ -257,6 +259,7 @@ It returns an immutable snapshot of the document. The snapshot is thread-safe, s The overload CreateSnapshot(out ChangeTrackingCheckpoint) also returns a ChangeTrackingCheckpoint for the document snapshot. Once you have two checkpoints, you can call GetChangesTo to retrieve the complete list of document changes that happened between those versions of the document. +

    Rendering

    Noticed how through the whole Document section, there was no mention of extensibility? @@ -268,11 +271,112 @@ It takes care of getting the document onto the screen.

    To do this in an extensible way, the TextView uses its own kind of model: the VisualLine. VisualLines are created only for the visible part of the document.

    The creation process looks like this:
    -rendering pipeline +rendering pipeline + +

    Lifetime of VisualLines

    +When the TextView needs to construct VisualLines (usually before rendering), it first +determines which DocumentLine is the top-most visible line in the currently viewed region. +From there, it starts to build VisualLines and also immediately does the conversion to TextLine (word-wrapping). +The process stops once the viewed document region is filled. +

    +The resulting VisualLines (and TextLines) will be cached and reused in future rendering passes. +When the user scrolls down, only the VisualLines coming into view are created, the rest is reused. +

    +The TextView.Redraw methods are used to remove VisualLines from the cache. +AvalonEdit calls Redraw automatically on the affected lines when the document is changed; and will invalidate the whole cache +when any editor options are changed. You will only have to call Redraw manually if you write extensions to the VisualLine creation process +that maintain their own data source. For example, the FoldingManager is calling Redraw when text sections are expanded or collapsed. +

    +Calling Redraw does not cause immediate recreation of the lines. +They are just removed from the cache so that the next rendering step will recreate them. +All Redraw methods will trigger a new rendering step, but they will delay it using the WPF Dispatcher using a low priority. + +

    Element Generators

    + +You can extend the text view by registering a custom class deriving from VisualLineElementGenerator in the TextView.ElementGenerators collection. +This allows you to add custom VisualLineElements. +Using the InlineObjectElement class, you can even put interactive WPF controls into the text document. +

    +For all document text not consumed by element generators, AvalonEdit will create VisualLineText elements. +

    +Usually, the construction of the VisualLine will stop at the end of the DocumentLine. However, if some VisualLineElementGenerator +creates an element that's longer than the rest of the line, construction of the VisualLine may resume in another DocumentLine. +Currently, only the FoldingElementGenerator can cause one VisualLine to span multiple DocumentLines. +

    +Screenshot Folding and ImageElementGenerator +

    +Here is the full source code for a class that implements embedding images into AvalonEdit: +

    public class ImageElementGenerator : VisualLineElementGenerator
    +{
    +	readonly static Regex imageRegex = new Regex(@"<img src=""([\.\/\w\d]+)""/?>", RegexOptions.IgnoreCase);
    +	readonly string basePath;
    +	
    +	public ImageElementGenerator(string basePath)
    +	{
    +		if (basePath == null)
    +			throw new ArgumentNullException("basePath");
    +		this.basePath = basePath;
    +	}
    +	
    +	Match FindMatch(int startOffset)
    +	{
    +		// fetch the end offset of the VisualLine being generated
    +		int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset;
    +		string relevantText = CurrentContext.Document.GetText(startOffset, endOffset - startOffset);
    +		return imageRegex.Match(relevantText);
    +	}
    +	
    +	// Gets the first offset >= startOffset where the generator wants to construct an element.
    +	// Return -1 to signal no interest.
    +	public override int GetFirstInterestedOffset(int startOffset)
    +	{
    +		Match m = FindMatch(startOffset);
    +		return m.Success ? (startOffset + m.Index) : -1;
    +	}
    +	
    +	// Constructs an element at the specified offset.
    +	// May return null if no element should be constructed.
    +	public override VisualLineElement ConstructElement(int offset)
    +	{
    +		Match m = FindMatch(offset);
    +		// check whether there's a match exactly at offset
    +		if (m.Success && m.Index == 0) {
    +			BitmapImage bitmap = LoadBitmap(m.Groups[1].Value);
    +			if (bitmap != null) {
    +				Image image = new Image();
    +				image.Source = bitmap;
    +				image.Width = bitmap.PixelWidth;
    +				image.Height = bitmap.PixelHeight;
    +				// Pass the length of the match to the 'documentLength' parameter of InlineObjectElement.
    +				return new InlineObjectElement(m.Length, image);
    +			}
    +		}
    +		return null;
    +	}
    +	
    +	BitmapImage LoadBitmap(string fileName)
    +	{
    +		// TODO: add some kind of cache to avoid reloading the image whenever the VisualLine is reconstructed
    +		try {
    +			string fullFileName = Path.Combine(basePath, fileName);
    +			if (File.Exists(fullFileName)) {
    +				BitmapImage bitmap = new BitmapImage(new Uri(fullFileName));
    +				bitmap.Freeze();
    +				return bitmap;
    +			}
    +		} catch (ArgumentException) {
    +			// invalid filename syntax
    +		} catch (IOException) {
    +			// other IO error
    +		}
    +		return null;
    +	}
    +}

    Editing

    -TODO: write this section +The TextArea class is handling user input and executing the appropriate actions. +Both the caret and the selection are controlled by the TextArea.

    Points of Interest

    @@ -283,7 +387,7 @@ do anything particularly clever or wild or zany?

    Keep a running update of any changes or improvements you've made here. -

    Note: although my sample code is provided under the BSD license, ICSharpCode.AvalonEdit itself is provided under the terms of the GNU LGPL. +

    Note: although my sample code is provided under the MIT license, ICSharpCode.AvalonEdit itself is provided under the terms of the GNU LGPL. diff --git a/samples/AvalonEdit.Sample/renderingPipeline.png b/samples/AvalonEdit.Sample/renderingPipeline.png deleted file mode 100644 index f7f9c7aea1..0000000000 Binary files a/samples/AvalonEdit.Sample/renderingPipeline.png and /dev/null differ diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs index d91fb075a7..f6d58cbd38 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs @@ -32,7 +32,8 @@ namespace ICSharpCode.AvalonEdit.Document /// Gets the text document that owns this DocumentLine. O(1). /// /// This property is still available even if the line was deleted. - [ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")] + [ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. " + + "It will be removed in a future AvalonEdit version.")] public TextDocument Document { get { document.DebugVerifyAccess(); @@ -45,7 +46,9 @@ namespace ICSharpCode.AvalonEdit.Document /// Gets the text on this line. /// /// The line was deleted. - [ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")] + [ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. " + + "It will be removed in a future AvalonEdit version. " + + "Use 'document.GetText(documentLine)' instead.")] public string Text { get { return document.GetText(this.Offset, this.Length); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs index c4ed992444..19a9128618 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs @@ -34,6 +34,7 @@ namespace ICSharpCode.AvalonEdit.Document // TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint. // delimiterSize takes only two bits, the two bools take another two bits; so there's still // 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :) + // TODO: remove the 'document' pointer in release builds ///

    /// Resets the line to enable its reuse after a document rebuild. diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs index 31ceac4b04..17ec1f309a 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs @@ -136,6 +136,8 @@ namespace ICSharpCode.AvalonEdit.Document /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace", Justification = "WPF uses 'Whitespace'")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", + Justification = "Parameter cannot be ITextSource because it must belong to the DocumentLine")] public static ISegment GetLeadingWhitespace(TextDocument document, DocumentLine documentLine) { if (documentLine == null) @@ -159,6 +161,8 @@ namespace ICSharpCode.AvalonEdit.Document /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace", Justification = "WPF uses 'Whitespace'")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", + Justification = "Parameter cannot be ITextSource because it must belong to the DocumentLine")] public static ISegment GetTrailingWhitespace(TextDocument document, DocumentLine documentLine) { if (documentLine == null) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs index c687f44987..ff603028a4 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/XmlFoldingStrategy.cs @@ -85,7 +85,7 @@ namespace ICSharpCode.AvalonEdit.Folding return foldMarkers; } - int GetOffset(TextDocument document, XmlReader reader) + static int GetOffset(TextDocument document, XmlReader reader) { IXmlLineInfo info = reader as IXmlLineInfo; if (info != null && info.HasLineInfo()) { @@ -100,7 +100,7 @@ namespace ICSharpCode.AvalonEdit.Folding /// /// The text displayed when the comment is folded is the first /// line of the comment. - void CreateCommentFold(TextDocument document, List foldMarkers, XmlReader reader) + static void CreateCommentFold(TextDocument document, List foldMarkers, XmlReader reader) { string comment = reader.Value; if (comment != null) { @@ -148,7 +148,7 @@ namespace ICSharpCode.AvalonEdit.Folding /// Create an element fold if the start and end tag are on /// different lines. /// - void CreateElementFold(TextDocument document, List foldMarkers, XmlReader reader, XmlFoldStart foldStart) + static void CreateElementFold(TextDocument document, List foldMarkers, XmlReader reader, XmlFoldStart foldStart) { IXmlLineInfo lineInfo = (IXmlLineInfo)reader; int endLine = lineInfo.LineNumber; @@ -168,7 +168,7 @@ namespace ICSharpCode.AvalonEdit.Folding /// line of the start tag. It does not cater for elements where attributes /// are not on the same line as the start tag. /// - string GetAttributeFoldText(XmlReader reader) + static string GetAttributeFoldText(XmlReader reader) { StringBuilder text = new StringBuilder(); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs index 8867f72b66..c21402ccb0 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs @@ -92,6 +92,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting public SystemColorHighlightingBrush(PropertyInfo property) { Debug.Assert(property.ReflectedType == typeof(SystemColors)); + Debug.Assert(typeof(Brush).IsAssignableFrom(property.PropertyType)); this.property = property; } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingManager.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingManager.cs index f5b2a25502..2c236feda4 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingManager.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingManager.cs @@ -47,6 +47,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", + Justification = "The exception will be rethrown")] IHighlightingDefinition GetDefinition() { Func func; @@ -125,7 +127,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// /// Gets a copy of all highlightings. /// - public ReadOnlyCollection Highlightings { + public ReadOnlyCollection HighlightingDefinitions { get { lock (lockObj) { return Array.AsReadOnly(allHighlightings.ToArray()); @@ -136,7 +138,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// /// Gets the names of the registered highlightings. /// - [ObsoleteAttribute("Use the Highlightings property instead.")] + [ObsoleteAttribute("Use the HighlightingDefinitions property instead.")] public IEnumerable HighlightingNames { get { lock (lockObj) { diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CPP-Mode.xshd b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CPP-Mode.xshd index 3995b7fa89..09c1a6a497 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CPP-Mode.xshd +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CPP-Mode.xshd @@ -2,7 +2,7 @@ - + diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs index 49d78d69ed..4dbda992ee 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting hlm.RegisterHighlighting("Boo", new[] { ".boo" }, "Boo.xshd"); hlm.RegisterHighlighting("Coco", new[] { ".atg" }, "Coco-Mode.xshd"); - hlm.RegisterHighlighting("C++.NET", new[] { ".c", ".h", ".cc", ".cpp" , ".hpp" }, "CPP-Mode.xshd"); + hlm.RegisterHighlighting("C++", new[] { ".c", ".h", ".cc", ".cpp" , ".hpp" }, "CPP-Mode.xshd"); hlm.RegisterHighlighting("Java", new[] { ".java" }, "Java-Mode.xshd"); hlm.RegisterHighlighting("Patch", new[] { ".patch", ".diff" }, "Patch-Mode.xshd"); hlm.RegisterHighlighting("PHP", new[] { ".php" }, "PHP-Mode.xshd"); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Xshd/V2Loader.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Xshd/V2Loader.cs index f059de1fe7..4bc18cdeb8 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Xshd/V2Loader.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Xshd/V2Loader.cs @@ -285,7 +285,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting.Xshd { Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal)); string shortName = name.Substring(13); - var property = typeof(SystemColors).GetProperty(shortName + "BrushKey"); + var property = typeof(SystemColors).GetProperty(shortName + "Brush"); if (property == null) throw Error(lineInfo, "Cannot find '" + name + "'."); return new SystemColorHighlightingBrush(property); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index f22ce090a6..4388fb1017 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -1,4 +1,4 @@ - + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} Debug diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs index b24ca749e8..1acc4717be 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs @@ -71,8 +71,7 @@ namespace ICSharpCode.AvalonEdit.Rendering Match GetMatch(int startOffset) { - DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine; - int endOffset = endLine.Offset + endLine.Length; + int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset; string relevantText = CurrentContext.Document.GetText(startOffset, endOffset - startOffset); return linkRegex.Match(relevantText); } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs index fe6a01bd02..95be5a8ee0 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs @@ -183,6 +183,10 @@ namespace ICSharpCode.AvalonEdit set { if (value < 1) throw new ArgumentOutOfRangeException("value", value, "value must be positive"); + // sanity check; a too large value might cause WPF to crash internally much later + // (it only crashed in the hundred thousands for me; but might crash earlier with larger fonts) + if (value > 1000) + throw new ArgumentOutOfRangeException("value", value, "indentation size is too large"); if (_indentationSize != value) { _indentationSize = value; OnPropertyChanged("IndentationSize");