Browse Source

AvalonEdit: add safety check that ReadOnlySectionProvider doesn't return invalid sections.

Core.Presentation: fixed typo in class name

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4891 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
9761f2de43
  1. 49
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs
  2. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs
  3. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  4. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs
  5. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
  6. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
  7. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
  8. 19
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs
  9. 2
      src/Main/Base/Project/Src/Gui/AbstractViewContent.cs
  10. 6
      src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs
  11. 2
      src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs

49
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Diagnostics;
@ -130,44 +131,74 @@ namespace ICSharpCode.AvalonEdit.Document @@ -130,44 +131,74 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// A segment using text anchors as start and end positions.
/// </summary>
sealed class AnchorSegment : ISegment
/// <remarks>
/// For the constructors creating new anchors, the start position will be AfterInsertion and the end position will be BeforeInsertion.
/// Should the end position move before the start position, the segment will have length 0.
/// </remarks>
public sealed class AnchorSegment : ISegment
{
readonly TextAnchor start, end;
/// <inheritdoc/>
public int Offset {
get { return start.Offset; }
}
/// <inheritdoc/>
public int Length {
get { return end.Offset - start.Offset; }
get {
// Math.Max takes care of the fact that end.Offset might move before start.Offset.
return Math.Max(0, end.Offset - start.Offset);
}
}
/// <inheritdoc/>
public int EndOffset {
get { return end.Offset; }
get {
// Math.Max takes care of the fact that end.Offset might move before start.Offset.
return Math.Max(start.Offset, end.Offset);
}
}
/// <summary>
/// Creates a new AnchorSegment using the specified anchors.
/// The anchors must have <see cref="TextAnchor.SurviveDeletion"/> set to true.
/// </summary>
public AnchorSegment(TextAnchor start, TextAnchor end)
{
Debug.Assert(start != null);
Debug.Assert(end != null);
Debug.Assert(start.SurviveDeletion);
Debug.Assert(end.SurviveDeletion);
if (start == null)
throw new ArgumentNullException("start");
if (end == null)
throw new ArgumentNullException("end");
if (!start.SurviveDeletion)
throw new ArgumentException("Anchors for AnchorSegment must use SurviveDeletion", "start");
if (!end.SurviveDeletion)
throw new ArgumentException("Anchors for AnchorSegment must use SurviveDeletion", "end");
this.start = start;
this.end = end;
}
/// <summary>
/// Creates a new AnchorSegment that creates new anchors.
/// </summary>
public AnchorSegment(TextDocument document, ISegment segment)
: this(document, segment.Offset, segment.Length)
: this(document, ThrowUtil.CheckNotNull(segment, "segment").Offset, segment.Length)
{
}
/// <summary>
/// Creates a new AnchorSegment that creates new anchors.
/// </summary>
public AnchorSegment(TextDocument document, int offset, int length)
{
Debug.Assert(document != null);
if (document == null)
throw new ArgumentNullException("document");
this.start = document.CreateAnchor(offset);
this.start.SurviveDeletion = true;
this.start.MovementType = AnchorMovementType.AfterInsertion;
this.end = document.CreateAnchor(offset + length);
this.end.SurviveDeletion = true;
this.start.MovementType = AnchorMovementType.BeforeInsertion;
}
}
}

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs

@ -109,8 +109,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -109,8 +109,11 @@ namespace ICSharpCode.AvalonEdit.Document
}
/// <summary>
/// Gets the end offset of the segment.
/// Gets/Sets the end offset of the segment.
/// </summary>
/// <remarks>
/// Setting the end offset will change the length, the start offset will stay constant.
/// </remarks>
public int EndOffset {
get {
return StartOffset + Length;
@ -126,6 +129,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -126,6 +129,9 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Gets/Sets the length of the segment.
/// </summary>
/// <remarks>
/// Setting the length will change the end offset, the start offset will stay constant.
/// </remarks>
public int Length {
get {
return segmentLength;

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -151,7 +151,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -151,7 +151,7 @@ namespace ICSharpCode.AvalonEdit.Editing
}
if (segments != null) {
foreach (ISegment segment in segments.Reverse()) {
foreach (ISegment writableSegment in textArea.ReadOnlySectionProvider.GetDeletableSegments(segment).Reverse()) {
foreach (ISegment writableSegment in textArea.GetDeletableSegments(segment).Reverse()) {
transformSegment(textArea, writableSegment);
}
}
@ -208,7 +208,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -208,7 +208,7 @@ namespace ICSharpCode.AvalonEdit.Editing
int offset = line.Offset;
ISegment s = TextUtilities.GetSingleIndentationSegment(line.Document, offset, textArea.Options.IndentationSize);
if (s.Length > 0) {
s = textArea.ReadOnlySectionProvider.GetDeletableSegments(s).FirstOrDefault();
s = textArea.GetDeletableSegments(s).FirstOrDefault();
if (s != null && s.Length > 0) {
textArea.Document.Remove(s.Offset, s.Length);
}

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs

@ -24,6 +24,10 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -24,6 +24,10 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <summary>
/// Gets the deletable segments inside the given segment.
/// </summary>
/// <remarks>
/// All segments in the result must be within the given segment, and they must be returned in order
/// (e.g. if two segments are returned, EndOffset of first segment must be less than StartOffset of second segment).
/// </remarks>
IEnumerable<ISegment> GetDeletableSegments(ISegment segment);
}
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs

@ -215,9 +215,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -215,9 +215,9 @@ namespace ICSharpCode.AvalonEdit.Editing
textArea.Document.Insert(lineSegment.Offset, newText);
}
} else {
var segmentsToDelete = textArea.ReadOnlySectionProvider.GetDeletableSegments(lineSegment).ToList();
for (int i = segmentsToDelete.Count - 1; i >= 0; i--) {
if (i == segmentsToDelete.Count - 1) {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(lineSegment);
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
if (i == segmentsToDelete.Length - 1) {
textArea.Document.Replace(segmentsToDelete[i], newText);
} else {
textArea.Document.Remove(segmentsToDelete[i]);

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -270,7 +270,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -270,7 +270,7 @@ namespace ICSharpCode.AvalonEdit.Editing
DragDropEffects allowedEffects = DragDropEffects.All;
var deleteOnMove = textArea.Selection.Segments.Select(s => new AnchorSegment(textArea.Document, s)).ToList();
foreach (ISegment s in deleteOnMove) {
ISegment[] result = textArea.ReadOnlySectionProvider.GetDeletableSegments(s).ToArray();
ISegment[] result = textArea.GetDeletableSegments(s);
if (result.Length != 1 || result[0].Offset != s.Offset || result[0].EndOffset != s.EndOffset) {
allowedEffects &= ~DragDropEffects.Move;
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

@ -77,9 +77,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -77,9 +77,9 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
} else {
var segmentsToDelete = textArea.ReadOnlySectionProvider.GetDeletableSegments(this).ToList();
for (int i = segmentsToDelete.Count - 1; i >= 0; i--) {
if (i == segmentsToDelete.Count - 1) {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(this);
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
if (i == segmentsToDelete.Length - 1) {
textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
textArea.Document.Replace(segmentsToDelete[i], newText);
} else {

19
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

@ -700,7 +700,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -700,7 +700,7 @@ namespace ICSharpCode.AvalonEdit.Editing
#if DEBUG
if (!selection.IsEmpty) {
foreach (ISegment s in selection.Segments) {
Debug.Assert(ReadOnlySectionProvider.GetDeletableSegments(s).Count() == 0);
Debug.Assert(this.ReadOnlySectionProvider.GetDeletableSegments(s).Count() == 0);
}
}
#endif
@ -714,6 +714,23 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -714,6 +714,23 @@ namespace ICSharpCode.AvalonEdit.Editing
throw ThrowUtil.NoDocumentAssigned();
selection.ReplaceSelectionWithText(this, newText);
}
internal ISegment[] GetDeletableSegments(ISegment segment)
{
var deletableSegments = this.ReadOnlySectionProvider.GetDeletableSegments(segment);
if (deletableSegments == null)
throw new InvalidOperationException("ReadOnlySectionProvider.GetDeletableSegments returned null");
var array = deletableSegments.ToArray();
int lastIndex = segment.Offset;
for (int i = 0; i < array.Length; i++) {
if (array[i].Offset < lastIndex)
throw new InvalidOperationException("ReadOnlySectionProvider returned incorrect segments (outside of input segment / wrong order)");
lastIndex = array[i].EndOffset;
}
if (lastIndex > segment.EndOffset)
throw new InvalidOperationException("ReadOnlySectionProvider returned incorrect segments (outside of input segment / wrong order)");
return array;
}
#endregion
#region IndentationStrategy property

2
src/Main/Base/Project/Src/Gui/AbstractViewContent.cs

@ -341,7 +341,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -341,7 +341,7 @@ namespace ICSharpCode.SharpDevelop.Gui
}
string titleName;
LanguageDependendExtension titleNameLocalizeExtension;
LanguageDependentExtension titleNameLocalizeExtension;
string IViewContent.TitleName {
get {

6
src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs

@ -17,7 +17,7 @@ namespace ICSharpCode.Core.Presentation @@ -17,7 +17,7 @@ namespace ICSharpCode.Core.Presentation
/// Markup extension that retrieves localized resource strings.
/// </summary>
[MarkupExtensionReturnType(typeof(string))]
public sealed class LocalizeExtension : LanguageDependendExtension
public sealed class LocalizeExtension : LanguageDependentExtension
{
public LocalizeExtension(string key)
{
@ -48,9 +48,9 @@ namespace ICSharpCode.Core.Presentation @@ -48,9 +48,9 @@ namespace ICSharpCode.Core.Presentation
}
}
public abstract class LanguageDependendExtension : MarkupExtension, INotifyPropertyChanged, IWeakEventListener
public abstract class LanguageDependentExtension : MarkupExtension, INotifyPropertyChanged, IWeakEventListener
{
protected LanguageDependendExtension()
protected LanguageDependentExtension()
{
this.UpdateOnLanguageChange = true;
}

2
src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs

@ -18,7 +18,7 @@ namespace ICSharpCode.Core.Presentation @@ -18,7 +18,7 @@ namespace ICSharpCode.Core.Presentation
/// Markup extension that works like StringParser.Parse
/// </summary>
[MarkupExtensionReturnType(typeof(string))]
public sealed class StringParseExtension : LanguageDependendExtension
public sealed class StringParseExtension : LanguageDependentExtension
{
string text;

Loading…
Cancel
Save