diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs index f90540d15b..6cc26e8c8b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs @@ -5,6 +5,7 @@ // $Revision$ // +using ICSharpCode.AvalonEdit.Utils; using System; using System.Diagnostics; @@ -130,44 +131,74 @@ namespace ICSharpCode.AvalonEdit.Document /// /// A segment using text anchors as start and end positions. /// - sealed class AnchorSegment : ISegment + /// + /// 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. + /// + public sealed class AnchorSegment : ISegment { readonly TextAnchor start, end; + /// public int Offset { get { return start.Offset; } } + /// 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); + } } + /// 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); + } } + /// + /// Creates a new AnchorSegment using the specified anchors. + /// The anchors must have set to true. + /// 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; } + /// + /// Creates a new AnchorSegment that creates new anchors. + /// public AnchorSegment(TextDocument document, ISegment segment) - : this(document, segment.Offset, segment.Length) + : this(document, ThrowUtil.CheckNotNull(segment, "segment").Offset, segment.Length) { } + /// + /// Creates a new AnchorSegment that creates new anchors. + /// 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; } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs index cabc57fd6d..abdc0b1d42 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs @@ -109,8 +109,11 @@ namespace ICSharpCode.AvalonEdit.Document } /// - /// Gets the end offset of the segment. + /// Gets/Sets the end offset of the segment. /// + /// + /// Setting the end offset will change the length, the start offset will stay constant. + /// public int EndOffset { get { return StartOffset + Length; @@ -126,6 +129,9 @@ namespace ICSharpCode.AvalonEdit.Document /// /// Gets/Sets the length of the segment. /// + /// + /// Setting the length will change the end offset, the start offset will stay constant. + /// public int Length { get { return segmentLength; diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs index 5b36f898a8..49ab029bf7 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs @@ -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 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); } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs index 2bdcc0ab6e..bfb1390205 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs @@ -24,6 +24,10 @@ namespace ICSharpCode.AvalonEdit.Editing /// /// Gets the deletable segments inside the given segment. /// + /// + /// 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). + /// IEnumerable GetDeletableSegments(ISegment segment); } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs index 7a27877bb0..521a5a2178 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs @@ -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]); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs index fa668b5577..bc71d5938f 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs @@ -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; } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs index 0e7efec1c0..46f284019b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs @@ -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 { diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs index 285c014ed0..87e79fa05f 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs @@ -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 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 diff --git a/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs b/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs index cfd39fe514..a271b8e35f 100644 --- a/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs +++ b/src/Main/Base/Project/Src/Gui/AbstractViewContent.cs @@ -341,7 +341,7 @@ namespace ICSharpCode.SharpDevelop.Gui } string titleName; - LanguageDependendExtension titleNameLocalizeExtension; + LanguageDependentExtension titleNameLocalizeExtension; string IViewContent.TitleName { get { diff --git a/src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs b/src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs index 4ce3a933c9..4702407b79 100644 --- a/src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs +++ b/src/Main/ICSharpCode.Core.Presentation/LocalizeExtension.cs @@ -17,7 +17,7 @@ namespace ICSharpCode.Core.Presentation /// Markup extension that retrieves localized resource strings. /// [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 } } - public abstract class LanguageDependendExtension : MarkupExtension, INotifyPropertyChanged, IWeakEventListener + public abstract class LanguageDependentExtension : MarkupExtension, INotifyPropertyChanged, IWeakEventListener { - protected LanguageDependendExtension() + protected LanguageDependentExtension() { this.UpdateOnLanguageChange = true; } diff --git a/src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs b/src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs index ddff553a29..a06a9d165f 100644 --- a/src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs +++ b/src/Main/ICSharpCode.Core.Presentation/StringParseExtension.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.Core.Presentation /// Markup extension that works like StringParser.Parse /// [MarkupExtensionReturnType(typeof(string))] - public sealed class StringParseExtension : LanguageDependendExtension + public sealed class StringParseExtension : LanguageDependentExtension { string text;