mirror of https://github.com/icsharpcode/ILSpy.git
23 changed files with 4 additions and 2119 deletions
@ -1,206 +0,0 @@
@@ -1,206 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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 ICSharpCode.Decompiler.CSharp.Syntax; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// A document representing a source code file for refactoring.
|
||||
/// Line and column counting starts at 1.
|
||||
/// Offset counting starts at 0.
|
||||
/// </summary>
|
||||
public interface IDocument : ITextSource, IServiceProvider |
||||
{ |
||||
/// <summary>
|
||||
/// Creates an immutable snapshot of this document.
|
||||
/// </summary>
|
||||
IDocument CreateDocumentSnapshot(); |
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the text of the whole document..
|
||||
/// </summary>
|
||||
new string Text { get; set; } // hides ITextSource.Text to add the setter
|
||||
|
||||
/// <summary>
|
||||
/// This event is called directly before a change is applied to the document.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is invalid to modify the document within this event handler.
|
||||
/// Aborting the change (by throwing an exception) is likely to cause corruption of data structures
|
||||
/// that listen to the Changing and Changed events.
|
||||
/// </remarks>
|
||||
event EventHandler<TextChangeEventArgs> TextChanging; |
||||
|
||||
/// <summary>
|
||||
/// This event is called directly after a change is applied to the document.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is invalid to modify the document within this event handler.
|
||||
/// Aborting the event handler (by throwing an exception) is likely to cause corruption of data structures
|
||||
/// that listen to the Changing and Changed events.
|
||||
/// </remarks>
|
||||
event EventHandler<TextChangeEventArgs> TextChanged; |
||||
|
||||
/// <summary>
|
||||
/// This event is called after a group of changes is completed.
|
||||
/// </summary>
|
||||
/// <seealso cref="EndUndoableAction"/>
|
||||
event EventHandler ChangeCompleted; |
||||
|
||||
/// <summary>
|
||||
/// Gets the number of lines in the document.
|
||||
/// </summary>
|
||||
int LineCount { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the document line with the specified number.
|
||||
/// </summary>
|
||||
/// <param name="lineNumber">The number of the line to retrieve. The first line has number 1.</param>
|
||||
IDocumentLine GetLineByNumber(int lineNumber); |
||||
|
||||
/// <summary>
|
||||
/// Gets the document line that contains the specified offset.
|
||||
/// </summary>
|
||||
IDocumentLine GetLineByOffset(int offset); |
||||
|
||||
/// <summary>
|
||||
/// Gets the offset from a text location.
|
||||
/// </summary>
|
||||
/// <seealso cref="GetLocation"/>
|
||||
int GetOffset(int line, int column); |
||||
|
||||
/// <summary>
|
||||
/// Gets the offset from a text location.
|
||||
/// </summary>
|
||||
/// <seealso cref="GetLocation"/>
|
||||
int GetOffset(TextLocation location); |
||||
|
||||
/// <summary>
|
||||
/// Gets the location from an offset.
|
||||
/// </summary>
|
||||
/// <seealso cref="GetOffset(TextLocation)"/>
|
||||
TextLocation GetLocation(int offset); |
||||
|
||||
/// <summary>
|
||||
/// Inserts text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset at which the text is inserted.</param>
|
||||
/// <param name="text">The new text.</param>
|
||||
/// <remarks>
|
||||
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
|
||||
/// For AnchorMovementType.Default, they will move behind the inserted text.
|
||||
/// The caret will also move behind the inserted text.
|
||||
/// </remarks>
|
||||
void Insert(int offset, string text); |
||||
|
||||
/// <summary>
|
||||
/// Inserts text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset at which the text is inserted.</param>
|
||||
/// <param name="text">The new text.</param>
|
||||
/// <remarks>
|
||||
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
|
||||
/// For AnchorMovementType.Default, they will move behind the inserted text.
|
||||
/// The caret will also move behind the inserted text.
|
||||
/// </remarks>
|
||||
void Insert(int offset, ITextSource text); |
||||
|
||||
/// <summary>
|
||||
/// Inserts text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset at which the text is inserted.</param>
|
||||
/// <param name="text">The new text.</param>
|
||||
/// <param name="defaultAnchorMovementType">
|
||||
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
|
||||
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
|
||||
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
|
||||
/// </param>
|
||||
void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType); |
||||
|
||||
/// <summary>
|
||||
/// Inserts text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset at which the text is inserted.</param>
|
||||
/// <param name="text">The new text.</param>
|
||||
/// <param name="defaultAnchorMovementType">
|
||||
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
|
||||
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
|
||||
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
|
||||
/// </param>
|
||||
void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType); |
||||
|
||||
/// <summary>
|
||||
/// Removes text.
|
||||
/// </summary>
|
||||
/// <param name="offset">Starting offset of the text to be removed.</param>
|
||||
/// <param name="length">Length of the text to be removed.</param>
|
||||
void Remove(int offset, int length); |
||||
|
||||
/// <summary>
|
||||
/// Replaces text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The starting offset of the text to be replaced.</param>
|
||||
/// <param name="length">The length of the text to be replaced.</param>
|
||||
/// <param name="newText">The new text.</param>
|
||||
void Replace(int offset, int length, string newText); |
||||
|
||||
/// <summary>
|
||||
/// Replaces text.
|
||||
/// </summary>
|
||||
/// <param name="offset">The starting offset of the text to be replaced.</param>
|
||||
/// <param name="length">The length of the text to be replaced.</param>
|
||||
/// <param name="newText">The new text.</param>
|
||||
void Replace(int offset, int length, ITextSource newText); |
||||
|
||||
/// <summary>
|
||||
/// Make the document combine the following actions into a single
|
||||
/// action for undo purposes.
|
||||
/// </summary>
|
||||
void StartUndoableAction(); |
||||
|
||||
/// <summary>
|
||||
/// Ends the undoable action started with <see cref="StartUndoableAction"/>.
|
||||
/// </summary>
|
||||
void EndUndoableAction(); |
||||
|
||||
/// <summary>
|
||||
/// Creates an undo group. Dispose the returned value to close the undo group.
|
||||
/// </summary>
|
||||
/// <returns>An object that closes the undo group when Dispose() is called.</returns>
|
||||
IDisposable OpenUndoGroup(); |
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ITextAnchor"/> at the specified offset.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="ITextAnchor" select="remarks|example"/>
|
||||
ITextAnchor CreateAnchor(int offset); |
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the file the document is stored in.
|
||||
/// Could also be a non-existent dummy file name or null if no name has been set.
|
||||
/// </summary>
|
||||
string FileName { get; } |
||||
|
||||
/// <summary>
|
||||
/// Fired when the file name of the document changes.
|
||||
/// </summary>
|
||||
event EventHandler FileNameChanged; |
||||
} |
||||
} |
@ -1,59 +0,0 @@
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// A line inside a <see cref="IDocument"/>.
|
||||
/// </summary>
|
||||
public interface IDocumentLine : ISegment |
||||
{ |
||||
/// <summary>
|
||||
/// Gets the length of this line, including the line delimiter.
|
||||
/// </summary>
|
||||
int TotalLength { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the line terminator.
|
||||
/// Returns 1 or 2; or 0 at the end of the document.
|
||||
/// </summary>
|
||||
int DelimiterLength { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the number of this line.
|
||||
/// The first line has the number 1.
|
||||
/// </summary>
|
||||
int LineNumber { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the previous line. Returns null if this is the first line in the document.
|
||||
/// </summary>
|
||||
IDocumentLine PreviousLine { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the next line. Returns null if this is the last line in the document.
|
||||
/// </summary>
|
||||
IDocumentLine NextLine { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets whether the line was deleted.
|
||||
/// </summary>
|
||||
bool IsDeleted { get; } |
||||
} |
||||
} |
@ -1,70 +0,0 @@
@@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// An (Offset,Length)-pair.
|
||||
/// </summary>
|
||||
public interface ISegment |
||||
{ |
||||
/// <summary>
|
||||
/// Gets the start offset of the segment.
|
||||
/// </summary>
|
||||
int Offset { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the segment.
|
||||
/// </summary>
|
||||
/// <remarks>For line segments (IDocumentLine), the length does not include the line delimeter.</remarks>
|
||||
int Length { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the end offset of the segment.
|
||||
/// </summary>
|
||||
/// <remarks>EndOffset = Offset + Length;</remarks>
|
||||
int EndOffset { get; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ISegment"/>.
|
||||
/// </summary>
|
||||
public static class ISegmentExtensions |
||||
{ |
||||
/// <summary>
|
||||
/// Gets whether <paramref name="segment"/> fully contains the specified segment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use <c>segment.Contains(offset, 0)</c> to detect whether a segment (end inclusive) contains offset;
|
||||
/// use <c>segment.Contains(offset, 1)</c> to detect whether a segment (end exclusive) contains offset.
|
||||
/// </remarks>
|
||||
public static bool Contains (this ISegment segment, int offset, int length) |
||||
{ |
||||
return segment.Offset <= offset && offset + length <= segment.EndOffset; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets whether <paramref name="thisSegment"/> fully contains the specified segment.
|
||||
/// </summary>
|
||||
public static bool Contains (this ISegment thisSegment, ISegment segment) |
||||
{ |
||||
return segment != null && thisSegment.Offset <= segment.Offset && segment.EndOffset <= thisSegment.EndOffset; |
||||
} |
||||
} |
||||
} |
@ -1,140 +0,0 @@
@@ -1,140 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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 ICSharpCode.Decompiler.CSharp.Syntax; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// The TextAnchor class references an offset (a position between two characters).
|
||||
/// It automatically updates the offset when text is inserted/removed in front of the anchor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Use the <see cref="ITextAnchor.Offset"/> property to get the offset from a text anchor.
|
||||
/// Use the <see cref="IDocument.CreateAnchor"/> method to create an anchor from an offset.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The document will automatically update all text anchors; and because it uses weak references to do so,
|
||||
/// the garbage collector can simply collect the anchor object when you don't need it anymore.
|
||||
/// </para>
|
||||
/// <para>Moreover, the document is able to efficiently update a large number of anchors without having to look
|
||||
/// at each anchor object individually. Updating the offsets of all anchors usually only takes time logarithmic
|
||||
/// to the number of anchors. Retrieving the <see cref="ITextAnchor.Offset"/> property also runs in O(lg N).</para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// Usage:
|
||||
/// <code>TextAnchor anchor = document.CreateAnchor(offset);
|
||||
/// ChangeMyDocument();
|
||||
/// int newOffset = anchor.Offset;
|
||||
/// </code>
|
||||
/// </example>
|
||||
public interface ITextAnchor |
||||
{ |
||||
/// <summary>
|
||||
/// Gets the text location of this anchor.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
|
||||
TextLocation Location { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the offset of the text anchor.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
|
||||
int Offset { get; } |
||||
|
||||
/// <summary>
|
||||
/// Controls how the anchor moves.
|
||||
/// </summary>
|
||||
/// <remarks>Anchor movement is ambiguous if text is inserted exactly at the anchor's location.
|
||||
/// Does the anchor stay before the inserted text, or does it move after it?
|
||||
/// The property <see cref="MovementType"/> will be used to determine which of these two options the anchor will choose.
|
||||
/// The default value is <see cref="AnchorMovementType.Default"/>.</remarks>
|
||||
AnchorMovementType MovementType { get; set; } |
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Specifies whether the anchor survives deletion of the text containing it.
|
||||
/// </para><para>
|
||||
/// <c>false</c>: The anchor is deleted when the a selection that includes the anchor is deleted.
|
||||
/// <c>true</c>: The anchor is not deleted.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks><inheritdoc cref="IsDeleted" /></remarks>
|
||||
bool SurviveDeletion { get; set; } |
||||
|
||||
/// <summary>
|
||||
/// Gets whether the anchor was deleted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When a piece of text containing an anchor is removed, then that anchor will be deleted.
|
||||
/// First, the <see cref="IsDeleted"/> property is set to true on all deleted anchors,
|
||||
/// then the <see cref="Deleted"/> events are raised.
|
||||
/// You cannot retrieve the offset from an anchor that has been deleted.</para>
|
||||
/// <para>This deletion behavior might be useful when using anchors for building a bookmark feature,
|
||||
/// but in other cases you want to still be able to use the anchor. For those cases, set <c><see cref="SurviveDeletion"/> = true</c>.</para>
|
||||
/// </remarks>
|
||||
bool IsDeleted { get; } |
||||
|
||||
/// <summary>
|
||||
/// Occurs after the anchor was deleted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <inheritdoc cref="IsDeleted" />
|
||||
/// <para>Due to the 'weak reference' nature of text anchors, you will receive
|
||||
/// the Deleted event only while your code holds a reference to the TextAnchor object.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
event EventHandler Deleted; |
||||
|
||||
/// <summary>
|
||||
/// Gets the line number of the anchor.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
|
||||
int Line { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the column number of this anchor.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
|
||||
int Column { get; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Defines how a text anchor moves.
|
||||
/// </summary>
|
||||
public enum AnchorMovementType |
||||
{ |
||||
/// <summary>
|
||||
/// When text is inserted at the anchor position, the type of the insertion
|
||||
/// determines where the caret moves to. For normal insertions, the anchor will move
|
||||
/// after the inserted text.
|
||||
/// </summary>
|
||||
Default, |
||||
/// <summary>
|
||||
/// Behaves like a start marker - when text is inserted at the anchor position, the anchor will stay
|
||||
/// before the inserted text.
|
||||
/// </summary>
|
||||
BeforeInsertion, |
||||
/// <summary>
|
||||
/// Behave like an end marker - when text is insered at the anchor position, the anchor will move
|
||||
/// after the inserted text.
|
||||
/// </summary>
|
||||
AfterInsertion |
||||
} |
||||
} |
@ -1,51 +0,0 @@
@@ -1,51 +0,0 @@
|
||||
// ITextPasteHandler.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@novell.com>
|
||||
//
|
||||
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// 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.
|
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// The text paste handler can do formattings to a text that is about to be pasted
|
||||
/// into the text document.
|
||||
/// </summary>
|
||||
public interface ITextPasteHandler |
||||
{ |
||||
/// <summary>
|
||||
/// Formats plain text that is inserted at a specified offset.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The text that will get inserted at that position.
|
||||
/// </returns>
|
||||
/// <param name="offset">The offset where the text will be inserted.</param>
|
||||
/// <param name="text">The text to be inserted.</param>
|
||||
/// <param name="copyData">Additional data in case the text was copied from a Mono.TextEditor.</param>
|
||||
string FormatPlainText(int offset, string text, byte[] copyData); |
||||
|
||||
/// <summary>
|
||||
/// Gets the copy data for a specific segment inside the document. This can contain additional information.
|
||||
/// </summary>
|
||||
/// <param name="segment">The text segment that is about to be copied.</param>
|
||||
byte[] GetCopyData(ISegment segment); |
||||
} |
||||
} |
@ -1,218 +0,0 @@
@@ -1,218 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// A read-only view on a (potentially mutable) text source.
|
||||
/// The IDocument interface derives from this interface.
|
||||
/// </summary>
|
||||
public interface ITextSource |
||||
{ |
||||
/// <summary>
|
||||
/// Gets a version identifier for this text source.
|
||||
/// Returns null for unversioned text sources.
|
||||
/// </summary>
|
||||
ITextSourceVersion Version { get; } |
||||
|
||||
/// <summary>
|
||||
/// Creates an immutable snapshot of this text source.
|
||||
/// Unlike all other methods in this interface, this method is thread-safe.
|
||||
/// </summary>
|
||||
ITextSource CreateSnapshot(); |
||||
|
||||
/// <summary>
|
||||
/// Creates an immutable snapshot of a part of this text source.
|
||||
/// Unlike all other methods in this interface, this method is thread-safe.
|
||||
/// </summary>
|
||||
ITextSource CreateSnapshot(int offset, int length); |
||||
|
||||
/// <summary>
|
||||
/// Creates a new TextReader to read from this text source.
|
||||
/// </summary>
|
||||
TextReader CreateReader(); |
||||
|
||||
/// <summary>
|
||||
/// Creates a new TextReader to read from this text source.
|
||||
/// </summary>
|
||||
TextReader CreateReader(int offset, int length); |
||||
|
||||
/// <summary>
|
||||
/// Gets the total text length.
|
||||
/// </summary>
|
||||
/// <returns>The length of the text, in characters.</returns>
|
||||
/// <remarks>This is the same as Text.Length, but is more efficient because
|
||||
/// it doesn't require creating a String object.</remarks>
|
||||
int TextLength { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets the whole text as string.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] |
||||
string Text { get; } |
||||
|
||||
/// <summary>
|
||||
/// Gets a character at the specified position in the document.
|
||||
/// </summary>
|
||||
/// <paramref name="offset">The index of the character to get.</paramref>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Offset is outside the valid range (0 to TextLength-1).</exception>
|
||||
/// <returns>The character at the specified position.</returns>
|
||||
/// <remarks>This is the same as Text[offset], but is more efficient because
|
||||
/// it doesn't require creating a String object.</remarks>
|
||||
char GetCharAt(int offset); |
||||
|
||||
/// <summary>
|
||||
/// Retrieves the text for a portion of the document.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
|
||||
/// <remarks>This is the same as Text.Substring, but is more efficient because
|
||||
/// it doesn't require creating a String object for the whole document.</remarks>
|
||||
string GetText(int offset, int length); |
||||
|
||||
/// <summary>
|
||||
/// Retrieves the text for a portion of the document.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
|
||||
string GetText(ISegment segment); |
||||
|
||||
/// <summary>
|
||||
/// Writes the text from this document into the TextWriter.
|
||||
/// </summary>
|
||||
void WriteTextTo(TextWriter writer); |
||||
|
||||
/// <summary>
|
||||
/// Writes the text from this document into the TextWriter.
|
||||
/// </summary>
|
||||
void WriteTextTo(TextWriter writer, int offset, int length); |
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the first occurrence of the character in the specified array.
|
||||
/// </summary>
|
||||
/// <param name="c">Character to search for</param>
|
||||
/// <param name="startIndex">Start index of the area to search.</param>
|
||||
/// <param name="count">Length of the area to search.</param>
|
||||
/// <returns>The first index where the character was found; or -1 if no occurrence was found.</returns>
|
||||
int IndexOf(char c, int startIndex, int count); |
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the first occurrence of any character in the specified array.
|
||||
/// </summary>
|
||||
/// <param name="anyOf">Characters to search for</param>
|
||||
/// <param name="startIndex">Start index of the area to search.</param>
|
||||
/// <param name="count">Length of the area to search.</param>
|
||||
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
|
||||
int IndexOfAny(char[] anyOf, int startIndex, int count); |
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the first occurrence of the specified search text in this text source.
|
||||
/// </summary>
|
||||
/// <param name="searchText">The search text</param>
|
||||
/// <param name="startIndex">Start index of the area to search.</param>
|
||||
/// <param name="count">Length of the area to search.</param>
|
||||
/// <param name="comparisonType">String comparison to use.</param>
|
||||
/// <returns>The first index where the search term was found; or -1 if no occurrence was found.</returns>
|
||||
int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType); |
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the last occurrence of the specified character in this text source.
|
||||
/// </summary>
|
||||
/// <param name="c">The search character</param>
|
||||
/// <param name="startIndex">Start index of the area to search.</param>
|
||||
/// <param name="count">Length of the area to search.</param>
|
||||
/// <returns>The last index where the search term was found; or -1 if no occurrence was found.</returns>
|
||||
/// <remarks>The search proceeds backwards from (startIndex+count) to startIndex.
|
||||
/// This is different than the meaning of the parameters on string.LastIndexOf!</remarks>
|
||||
int LastIndexOf(char c, int startIndex, int count); |
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the last occurrence of the specified search text in this text source.
|
||||
/// </summary>
|
||||
/// <param name="searchText">The search text</param>
|
||||
/// <param name="startIndex">Start index of the area to search.</param>
|
||||
/// <param name="count">Length of the area to search.</param>
|
||||
/// <param name="comparisonType">String comparison to use.</param>
|
||||
/// <returns>The last index where the search term was found; or -1 if no occurrence was found.</returns>
|
||||
/// <remarks>The search proceeds backwards from (startIndex+count) to startIndex.
|
||||
/// This is different than the meaning of the parameters on string.LastIndexOf!</remarks>
|
||||
int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType); |
||||
|
||||
/* What about: |
||||
void Insert (int offset, string value); |
||||
void Remove (int offset, int count); |
||||
void Remove (ISegment segment); |
||||
|
||||
void Replace (int offset, int count, string value); |
||||
|
||||
Or more search operations: |
||||
|
||||
IEnumerable<int> SearchForward (string pattern, int startIndex); |
||||
IEnumerable<int> SearchForwardIgnoreCase (string pattern, int startIndex); |
||||
|
||||
IEnumerable<int> SearchBackward (string pattern, int startIndex); |
||||
IEnumerable<int> SearchBackwardIgnoreCase (string pattern, int startIndex); |
||||
*/ |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Represents a version identifier for a text source.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
|
||||
/// or even to implement incremental parsers.
|
||||
/// It is a separate class from ITextSource to allow the GC to collect the text source while
|
||||
/// the version checkpoint is still in use.
|
||||
/// </remarks>
|
||||
public interface ITextSourceVersion |
||||
{ |
||||
/// <summary>
|
||||
/// Gets whether this checkpoint belongs to the same document as the other checkpoint.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns false when given <c>null</c>.
|
||||
/// </remarks>
|
||||
bool BelongsToSameDocumentAs(ITextSourceVersion other); |
||||
|
||||
/// <summary>
|
||||
/// Compares the age of this checkpoint to the other checkpoint.
|
||||
/// </summary>
|
||||
/// <remarks>This method is thread-safe.</remarks>
|
||||
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this version.</exception>
|
||||
/// <returns>-1 if this version is older than <paramref name="other"/>.
|
||||
/// 0 if <c>this</c> version instance represents the same version as <paramref name="other"/>.
|
||||
/// 1 if this version is newer than <paramref name="other"/>.</returns>
|
||||
int CompareAge(ITextSourceVersion other); |
||||
|
||||
/// <summary>
|
||||
/// Gets the changes from this checkpoint to the other checkpoint.
|
||||
/// If 'other' is older than this checkpoint, reverse changes are calculated.
|
||||
/// </summary>
|
||||
/// <remarks>This method is thread-safe.</remarks>
|
||||
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
|
||||
IEnumerable<TextChangeEventArgs> GetChangesTo(ITextSourceVersion other); |
||||
|
||||
/// <summary>
|
||||
/// Calculates where the offset has moved in the other buffer version.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
|
||||
int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement = AnchorMovementType.Default); |
||||
} |
||||
} |
@ -1,448 +0,0 @@
@@ -1,448 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
using ICSharpCode.Decompiler.CSharp.Syntax; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// Read-only implementation of <see cref="IDocument"/>.
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public sealed class ReadOnlyDocument : IDocument |
||||
{ |
||||
readonly ITextSource textSource; |
||||
readonly string fileName; |
||||
int[] lines; |
||||
|
||||
static readonly char[] newline = { '\r', '\n' }; |
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReadOnlyDocument from the given text source.
|
||||
/// </summary>
|
||||
public ReadOnlyDocument(ITextSource textSource) |
||||
{ |
||||
if (textSource == null) |
||||
throw new ArgumentNullException("textSource"); |
||||
// ensure that underlying buffer is immutable
|
||||
this.textSource = textSource.CreateSnapshot(); |
||||
List<int> lines = new List<int>(); |
||||
lines.Add(0); |
||||
int offset = 0; |
||||
int textLength = textSource.TextLength; |
||||
while ((offset = textSource.IndexOfAny(newline, offset, textLength - offset)) >= 0) { |
||||
offset++; |
||||
if (textSource.GetCharAt(offset - 1) == '\r' && offset < textLength && textSource.GetCharAt(offset) == '\n') { |
||||
offset++; |
||||
} |
||||
lines.Add(offset); |
||||
} |
||||
this.lines = lines.ToArray(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReadOnlyDocument from the given string.
|
||||
/// </summary>
|
||||
public ReadOnlyDocument(string text) |
||||
: this(new StringTextSource(text)) |
||||
{ |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new ReadOnlyDocument from the given text source;
|
||||
/// and sets IDocument.FileName to the specified file name.
|
||||
/// </summary>
|
||||
public ReadOnlyDocument(ITextSource textSource, string fileName) |
||||
: this(textSource) |
||||
{ |
||||
this.fileName = fileName; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocumentLine GetLineByNumber(int lineNumber) |
||||
{ |
||||
if (lineNumber < 1 || lineNumber > lines.Length) |
||||
throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length); |
||||
return new ReadOnlyDocumentLine(this, lineNumber); |
||||
} |
||||
|
||||
sealed class ReadOnlyDocumentLine : IDocumentLine |
||||
{ |
||||
readonly ReadOnlyDocument doc; |
||||
readonly int lineNumber; |
||||
readonly int offset, endOffset; |
||||
|
||||
public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber) |
||||
{ |
||||
this.doc = doc; |
||||
this.lineNumber = lineNumber; |
||||
this.offset = doc.GetStartOffset(lineNumber); |
||||
this.endOffset = doc.GetEndOffset(lineNumber); |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return doc.GetHashCode() ^ lineNumber; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
ReadOnlyDocumentLine other = obj as ReadOnlyDocumentLine; |
||||
return other != null && doc == other.doc && lineNumber == other.lineNumber; |
||||
} |
||||
|
||||
public int Offset { |
||||
get { return offset; } |
||||
} |
||||
|
||||
public int Length { |
||||
get { return endOffset - offset; } |
||||
} |
||||
|
||||
public int EndOffset { |
||||
get { return endOffset; } |
||||
} |
||||
|
||||
public int TotalLength { |
||||
get { |
||||
return doc.GetTotalEndOffset(lineNumber) - offset; |
||||
} |
||||
} |
||||
|
||||
public int DelimiterLength { |
||||
get { |
||||
return doc.GetTotalEndOffset(lineNumber) - endOffset; |
||||
} |
||||
} |
||||
|
||||
public int LineNumber { |
||||
get { return lineNumber; } |
||||
} |
||||
|
||||
public IDocumentLine PreviousLine { |
||||
get { |
||||
if (lineNumber == 1) |
||||
return null; |
||||
else |
||||
return new ReadOnlyDocumentLine(doc, lineNumber - 1); |
||||
} |
||||
} |
||||
|
||||
public IDocumentLine NextLine { |
||||
get { |
||||
if (lineNumber == doc.LineCount) |
||||
return null; |
||||
else |
||||
return new ReadOnlyDocumentLine(doc, lineNumber + 1); |
||||
} |
||||
} |
||||
|
||||
public bool IsDeleted { |
||||
get { return false; } |
||||
} |
||||
} |
||||
|
||||
int GetStartOffset(int lineNumber) |
||||
{ |
||||
return lines[lineNumber-1]; |
||||
} |
||||
|
||||
int GetTotalEndOffset(int lineNumber) |
||||
{ |
||||
return lineNumber < lines.Length ? lines[lineNumber] : textSource.TextLength; |
||||
} |
||||
|
||||
int GetEndOffset(int lineNumber) |
||||
{ |
||||
if (lineNumber == lines.Length) |
||||
return textSource.TextLength; |
||||
int off = lines[lineNumber] - 1; |
||||
if (off > 0 && textSource.GetCharAt(off - 1) == '\r' && textSource.GetCharAt(off) == '\n') |
||||
off--; |
||||
return off; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocumentLine GetLineByOffset(int offset) |
||||
{ |
||||
return GetLineByNumber(GetLineNumberForOffset(offset)); |
||||
} |
||||
|
||||
int GetLineNumberForOffset(int offset) |
||||
{ |
||||
int r = Array.BinarySearch(lines, offset); |
||||
return r < 0 ? ~r : r + 1; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int GetOffset(int line, int column) |
||||
{ |
||||
if (line < 1 || line > lines.Length) |
||||
throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length); |
||||
int lineStart = GetStartOffset(line); |
||||
if (column <= 1) |
||||
return lineStart; |
||||
int lineEnd = GetEndOffset(line); |
||||
if (column - 1 >= lineEnd - lineStart) |
||||
return lineEnd; |
||||
return lineStart + column - 1; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int GetOffset(TextLocation location) |
||||
{ |
||||
return GetOffset(location.Line, location.Column); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextLocation GetLocation(int offset) |
||||
{ |
||||
if (offset < 0 || offset > textSource.TextLength) |
||||
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textSource.TextLength); |
||||
int line = GetLineNumberForOffset(offset); |
||||
return new TextLocation(line, offset-GetStartOffset(line)+1); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string Text { |
||||
get { return textSource.Text; } |
||||
set { |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LineCount { |
||||
get { return lines.Length; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSourceVersion Version { |
||||
get { return textSource.Version; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int TextLength { |
||||
get { return textSource.TextLength; } |
||||
} |
||||
|
||||
event EventHandler<TextChangeEventArgs> IDocument.TextChanging { add {} remove {} } |
||||
|
||||
event EventHandler<TextChangeEventArgs> IDocument.TextChanged { add {} remove {} } |
||||
|
||||
event EventHandler IDocument.ChangeCompleted { add {} remove {} } |
||||
|
||||
void IDocument.Insert(int offset, string text) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Remove(int offset, int length) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Replace(int offset, int length, string newText) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Insert(int offset, ITextSource text) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.Replace(int offset, int length, ITextSource newText) |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
|
||||
void IDocument.StartUndoableAction() |
||||
{ |
||||
} |
||||
|
||||
void IDocument.EndUndoableAction() |
||||
{ |
||||
} |
||||
|
||||
IDisposable IDocument.OpenUndoGroup() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextAnchor CreateAnchor(int offset) |
||||
{ |
||||
return new ReadOnlyDocumentTextAnchor(GetLocation(offset), offset); |
||||
} |
||||
|
||||
sealed class ReadOnlyDocumentTextAnchor : ITextAnchor |
||||
{ |
||||
readonly TextLocation location; |
||||
readonly int offset; |
||||
|
||||
public ReadOnlyDocumentTextAnchor(TextLocation location, int offset) |
||||
{ |
||||
this.location = location; |
||||
this.offset = offset; |
||||
} |
||||
|
||||
public event EventHandler Deleted { add {} remove {} } |
||||
|
||||
public TextLocation Location { |
||||
get { return location; } |
||||
} |
||||
|
||||
public int Offset { |
||||
get { return offset; } |
||||
} |
||||
|
||||
public AnchorMovementType MovementType { get; set; } |
||||
|
||||
public bool SurviveDeletion { get; set; } |
||||
|
||||
public bool IsDeleted { |
||||
get { return false; } |
||||
} |
||||
|
||||
public int Line { |
||||
get { return location.Line; } |
||||
} |
||||
|
||||
public int Column { |
||||
get { return location.Column; } |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot() |
||||
{ |
||||
return textSource; // textBuffer is immutable
|
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot(int offset, int length) |
||||
{ |
||||
return textSource.CreateSnapshot(offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocument CreateDocumentSnapshot() |
||||
{ |
||||
return this; // ReadOnlyDocument is immutable
|
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public System.IO.TextReader CreateReader() |
||||
{ |
||||
return textSource.CreateReader(); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public System.IO.TextReader CreateReader(int offset, int length) |
||||
{ |
||||
return textSource.CreateReader(offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(System.IO.TextWriter writer) |
||||
{ |
||||
textSource.WriteTextTo(writer); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(System.IO.TextWriter writer, int offset, int length) |
||||
{ |
||||
textSource.WriteTextTo(writer, offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public char GetCharAt(int offset) |
||||
{ |
||||
return textSource.GetCharAt(offset); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(int offset, int length) |
||||
{ |
||||
return textSource.GetText(offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(ISegment segment) |
||||
{ |
||||
return textSource.GetText(segment); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return textSource.IndexOf(c, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOfAny(char[] anyOf, int startIndex, int count) |
||||
{ |
||||
return textSource.IndexOfAny(anyOf, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return textSource.IndexOf(searchText, startIndex, count, comparisonType); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return textSource.LastIndexOf(c, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return textSource.LastIndexOf(searchText, startIndex, count, comparisonType); |
||||
} |
||||
|
||||
object IServiceProvider.GetService(Type serviceType) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>Will never be raised on <see cref="ReadOnlyDocument" />.</remarks>
|
||||
public event EventHandler FileNameChanged { add {} remove {} } |
||||
|
||||
/// <inheritdoc/>
|
||||
public string FileName { |
||||
get { return fileName; } |
||||
} |
||||
} |
||||
} |
@ -1,494 +0,0 @@
@@ -1,494 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
using System.IO; |
||||
using System.Text; |
||||
using ICSharpCode.Decompiler.CSharp.Syntax; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// Document based on a string builder.
|
||||
/// This class serves as a reference implementation for the IDocument interface.
|
||||
/// </summary>
|
||||
public class StringBuilderDocument : IDocument |
||||
{ |
||||
readonly StringBuilder b; |
||||
readonly TextSourceVersionProvider versionProvider = new TextSourceVersionProvider(); |
||||
|
||||
/// <summary>
|
||||
/// Creates a new StringBuilderDocument.
|
||||
/// </summary>
|
||||
public StringBuilderDocument() |
||||
{ |
||||
b = new StringBuilder(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new StringBuilderDocument with the specified initial text.
|
||||
/// </summary>
|
||||
public StringBuilderDocument(string text) |
||||
{ |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
b = new StringBuilder(text); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new StringBuilderDocument with the initial text copied from the specified text source.
|
||||
/// </summary>
|
||||
public StringBuilderDocument(ITextSource textSource) |
||||
{ |
||||
if (textSource == null) |
||||
throw new ArgumentNullException("textSource"); |
||||
b = new StringBuilder(textSource.TextLength); |
||||
textSource.WriteTextTo(new StringWriter(b)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<TextChangeEventArgs> TextChanging; |
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<TextChangeEventArgs> TextChanged; |
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler ChangeCompleted; |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSourceVersion Version { |
||||
get { return versionProvider.CurrentVersion; } |
||||
} |
||||
|
||||
#region Line<->Offset
|
||||
/// <inheritdoc/>
|
||||
public int LineCount { |
||||
get { return CreateDocumentSnapshot().LineCount; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocumentLine GetLineByNumber(int lineNumber) |
||||
{ |
||||
return CreateDocumentSnapshot().GetLineByNumber(lineNumber); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocumentLine GetLineByOffset(int offset) |
||||
{ |
||||
return CreateDocumentSnapshot().GetLineByOffset(offset); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int GetOffset(int line, int column) |
||||
{ |
||||
return CreateDocumentSnapshot().GetOffset(line, column); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int GetOffset(TextLocation location) |
||||
{ |
||||
return CreateDocumentSnapshot().GetOffset(location); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextLocation GetLocation(int offset) |
||||
{ |
||||
return CreateDocumentSnapshot().GetLocation(offset); |
||||
} |
||||
#endregion
|
||||
|
||||
#region Insert/Remove/Replace
|
||||
/// <inheritdoc/>
|
||||
public void Insert(int offset, string text) |
||||
{ |
||||
Replace(offset, 0, text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Insert(int offset, ITextSource text) |
||||
{ |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
Replace(offset, 0, text.Text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) |
||||
{ |
||||
if (offset < 0 || offset > this.TextLength) |
||||
throw new ArgumentOutOfRangeException("offset"); |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
if (defaultAnchorMovementType == AnchorMovementType.BeforeInsertion) |
||||
PerformChange(new InsertionWithMovementBefore(offset, text)); |
||||
else |
||||
Replace(offset, 0, text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType) |
||||
{ |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
Insert(offset, text.Text, defaultAnchorMovementType); |
||||
} |
||||
|
||||
[Serializable] |
||||
sealed class InsertionWithMovementBefore : TextChangeEventArgs |
||||
{ |
||||
public InsertionWithMovementBefore(int offset, string newText) : base(offset, string.Empty, newText) |
||||
{ |
||||
} |
||||
|
||||
public override int GetNewOffset(int offset, AnchorMovementType movementType) |
||||
{ |
||||
if (offset == this.Offset && movementType == AnchorMovementType.Default) |
||||
return offset; |
||||
else |
||||
return base.GetNewOffset(offset, movementType); |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Remove(int offset, int length) |
||||
{ |
||||
Replace(offset, length, string.Empty); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Replace(int offset, int length, string newText) |
||||
{ |
||||
if (offset < 0 || offset > this.TextLength) |
||||
throw new ArgumentOutOfRangeException("offset"); |
||||
if (length < 0 || length > this.TextLength - offset) |
||||
throw new ArgumentOutOfRangeException("length"); |
||||
if (newText == null) |
||||
throw new ArgumentNullException("newText"); |
||||
PerformChange(new TextChangeEventArgs(offset, b.ToString(offset, length), newText)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void Replace(int offset, int length, ITextSource newText) |
||||
{ |
||||
if (newText == null) |
||||
throw new ArgumentNullException("newText"); |
||||
Replace(offset, length, newText.Text); |
||||
} |
||||
|
||||
bool isInChange; |
||||
|
||||
void PerformChange(TextChangeEventArgs change) |
||||
{ |
||||
// Ensure that all changes take place inside an update group.
|
||||
// Will also take care of throwing an exception if isInChange is set.
|
||||
StartUndoableAction(); |
||||
try { |
||||
isInChange = true; |
||||
try { |
||||
if (TextChanging != null) |
||||
TextChanging(this, change); |
||||
|
||||
// Perform changes to document and Version property
|
||||
documentSnapshot = null; |
||||
cachedText = null; |
||||
b.Remove(change.Offset, change.RemovalLength); |
||||
b.Insert(change.Offset, change.InsertedText.Text); |
||||
versionProvider.AppendChange(change); |
||||
|
||||
// Update anchors and fire Deleted events
|
||||
UpdateAnchors(change); |
||||
|
||||
if (TextChanged != null) |
||||
TextChanged(this, change); |
||||
} finally { |
||||
isInChange = false; |
||||
} |
||||
} finally { |
||||
EndUndoableAction(); |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region Undo
|
||||
int undoGroupNesting = 0; |
||||
|
||||
/// <inheritdoc/>
|
||||
public void StartUndoableAction() |
||||
{ |
||||
// prevent changes from within the TextChanging/TextChanged event handlers
|
||||
if (isInChange) |
||||
throw new InvalidOperationException(); |
||||
undoGroupNesting++; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void EndUndoableAction() |
||||
{ |
||||
undoGroupNesting--; |
||||
if (undoGroupNesting == 0) { |
||||
if (ChangeCompleted != null) |
||||
ChangeCompleted(this, EventArgs.Empty); |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDisposable OpenUndoGroup() |
||||
{ |
||||
StartUndoableAction(); |
||||
return new CallbackOnDispose(EndUndoableAction); |
||||
} |
||||
#endregion
|
||||
|
||||
#region CreateSnapshot/CreateReader
|
||||
ReadOnlyDocument documentSnapshot; |
||||
|
||||
/// <inheritdoc/>
|
||||
public IDocument CreateDocumentSnapshot() |
||||
{ |
||||
if (documentSnapshot == null) |
||||
documentSnapshot = new ReadOnlyDocument(this, this.FileName); |
||||
return documentSnapshot; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot() |
||||
{ |
||||
return new StringTextSource(this.Text, versionProvider.CurrentVersion); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot(int offset, int length) |
||||
{ |
||||
return new StringTextSource(GetText(offset, length)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextReader CreateReader() |
||||
{ |
||||
return new StringReader(this.Text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextReader CreateReader(int offset, int length) |
||||
{ |
||||
return new StringReader(GetText(offset, length)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(TextWriter writer) |
||||
{ |
||||
if (writer == null) |
||||
throw new ArgumentNullException("writer"); |
||||
writer.Write(this.Text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(TextWriter writer, int offset, int length) |
||||
{ |
||||
if (writer == null) |
||||
throw new ArgumentNullException("writer"); |
||||
writer.Write(GetText(offset, length)); |
||||
} |
||||
#endregion
|
||||
|
||||
#region GetText / IndexOf
|
||||
string cachedText; |
||||
|
||||
/// <inheritdoc/>
|
||||
public string Text { |
||||
get { |
||||
if (cachedText == null) |
||||
cachedText = b.ToString(); |
||||
return cachedText; |
||||
} |
||||
set { |
||||
Replace(0, b.Length, value); |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int TextLength { |
||||
get { return b.Length; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public char GetCharAt(int offset) |
||||
{ |
||||
return b[offset]; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(int offset, int length) |
||||
{ |
||||
return b.ToString(offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(ISegment segment) |
||||
{ |
||||
if (segment == null) |
||||
throw new ArgumentNullException("segment"); |
||||
return b.ToString(segment.Offset, segment.Length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return this.Text.IndexOf(c, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOfAny(char[] anyOf, int startIndex, int count) |
||||
{ |
||||
return this.Text.IndexOfAny(anyOf, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return this.Text.IndexOf(searchText, startIndex, count, comparisonType); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return this.Text.LastIndexOf(c, startIndex + count - 1, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return this.Text.LastIndexOf(searchText, startIndex + count - 1, count, comparisonType); |
||||
} |
||||
#endregion
|
||||
|
||||
#region CreateAnchor
|
||||
readonly List<WeakReference> anchors = new List<WeakReference>(); |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextAnchor CreateAnchor(int offset) |
||||
{ |
||||
var newAnchor = new SimpleAnchor(this, offset); |
||||
for (int i = 0; i < anchors.Count; i++) { |
||||
if (!anchors[i].IsAlive) |
||||
anchors[i] = new WeakReference(newAnchor); |
||||
} |
||||
anchors.Add(new WeakReference(newAnchor)); |
||||
return newAnchor; |
||||
} |
||||
|
||||
void UpdateAnchors(TextChangeEventArgs change) |
||||
{ |
||||
// First update all anchors, then fire the deleted events.
|
||||
List<int> deletedAnchors = new List<int>(); |
||||
for (int i = 0; i < anchors.Count; i++) { |
||||
var anchor = anchors[i].Target as SimpleAnchor; |
||||
if (anchor != null) { |
||||
anchor.Update(change); |
||||
if (anchor.IsDeleted) |
||||
deletedAnchors.Add(i); |
||||
} |
||||
} |
||||
deletedAnchors.Reverse(); |
||||
foreach (var index in deletedAnchors) { |
||||
var anchor = anchors[index].Target as SimpleAnchor; |
||||
if (anchor != null) |
||||
anchor.RaiseDeletedEvent(); |
||||
anchors.RemoveAt(index); |
||||
} |
||||
} |
||||
|
||||
sealed class SimpleAnchor : ITextAnchor |
||||
{ |
||||
readonly StringBuilderDocument document; |
||||
int offset; |
||||
|
||||
public SimpleAnchor(StringBuilderDocument document, int offset) |
||||
{ |
||||
this.document = document; |
||||
this.offset = offset; |
||||
} |
||||
|
||||
public event EventHandler Deleted; |
||||
|
||||
public TextLocation Location { |
||||
get { |
||||
if (IsDeleted) |
||||
throw new InvalidOperationException(); |
||||
return document.GetLocation(offset); |
||||
} |
||||
} |
||||
|
||||
public int Offset { |
||||
get { |
||||
if (IsDeleted) |
||||
throw new InvalidOperationException(); |
||||
return offset; |
||||
} |
||||
} |
||||
|
||||
public AnchorMovementType MovementType { get; set; } |
||||
|
||||
public bool SurviveDeletion { get; set; } |
||||
|
||||
public bool IsDeleted { |
||||
get { return offset < 0; } |
||||
} |
||||
|
||||
public void Update(TextChangeEventArgs change) |
||||
{ |
||||
if (SurviveDeletion || offset <= change.Offset || offset >= change.Offset + change.RemovalLength) { |
||||
offset = change.GetNewOffset(offset, MovementType); |
||||
} else { |
||||
offset = -1; |
||||
} |
||||
} |
||||
|
||||
public void RaiseDeletedEvent() |
||||
{ |
||||
if (Deleted != null) |
||||
Deleted(this, EventArgs.Empty); |
||||
} |
||||
|
||||
public int Line { |
||||
get { return this.Location.Line; } |
||||
} |
||||
|
||||
public int Column { |
||||
get { return this.Location.Column; } |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual object GetService(Type serviceType) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual event EventHandler FileNameChanged { add {} remove {} } |
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual string FileName { |
||||
get { return string.Empty; } |
||||
} |
||||
} |
||||
} |
@ -1,160 +0,0 @@
@@ -1,160 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// Implements the ITextSource interface using a string.
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public class StringTextSource : ITextSource |
||||
{ |
||||
/// <summary>
|
||||
/// Gets a text source containing the empty string.
|
||||
/// </summary>
|
||||
public static readonly StringTextSource Empty = new StringTextSource(string.Empty); |
||||
|
||||
readonly string text; |
||||
readonly ITextSourceVersion version; |
||||
|
||||
/// <summary>
|
||||
/// Creates a new StringTextSource with the given text.
|
||||
/// </summary>
|
||||
public StringTextSource(string text) |
||||
{ |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
this.text = text; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new StringTextSource with the given text.
|
||||
/// </summary>
|
||||
public StringTextSource(string text, ITextSourceVersion version) |
||||
{ |
||||
if (text == null) |
||||
throw new ArgumentNullException("text"); |
||||
this.text = text; |
||||
this.version = version; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSourceVersion Version { |
||||
get { return version; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int TextLength { |
||||
get { return text.Length; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string Text { |
||||
get { return text; } |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot() |
||||
{ |
||||
return this; // StringTextSource is immutable
|
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public ITextSource CreateSnapshot(int offset, int length) |
||||
{ |
||||
return new StringTextSource(text.Substring(offset, length)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextReader CreateReader() |
||||
{ |
||||
return new StringReader(text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public TextReader CreateReader(int offset, int length) |
||||
{ |
||||
return new StringReader(text.Substring(offset, length)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(TextWriter writer) |
||||
{ |
||||
writer.Write(text); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public void WriteTextTo(TextWriter writer, int offset, int length) |
||||
{ |
||||
writer.Write(text.Substring(offset, length)); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public char GetCharAt(int offset) |
||||
{ |
||||
return text[offset]; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(int offset, int length) |
||||
{ |
||||
return text.Substring(offset, length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetText(ISegment segment) |
||||
{ |
||||
if (segment == null) |
||||
throw new ArgumentNullException("segment"); |
||||
return text.Substring(segment.Offset, segment.Length); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return text.IndexOf(c, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOfAny(char[] anyOf, int startIndex, int count) |
||||
{ |
||||
return text.IndexOfAny(anyOf, startIndex, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return text.IndexOf(searchText, startIndex, count, comparisonType); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(char c, int startIndex, int count) |
||||
{ |
||||
return text.LastIndexOf(c, startIndex + count - 1, count); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType) |
||||
{ |
||||
return text.LastIndexOf(searchText, startIndex + count - 1, count, comparisonType); |
||||
} |
||||
} |
||||
} |
@ -1,118 +0,0 @@
@@ -1,118 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// Describes a change of the document text.
|
||||
/// This class is thread-safe.
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public class TextChangeEventArgs : EventArgs |
||||
{ |
||||
readonly int offset; |
||||
readonly ITextSource removedText; |
||||
readonly ITextSource insertedText; |
||||
|
||||
/// <summary>
|
||||
/// The offset at which the change occurs.
|
||||
/// </summary>
|
||||
public int Offset { |
||||
get { return offset; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The text that was removed.
|
||||
/// </summary>
|
||||
public ITextSource RemovedText { |
||||
get { return removedText; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The number of characters removed.
|
||||
/// </summary>
|
||||
public int RemovalLength { |
||||
get { return removedText.TextLength; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The text that was inserted.
|
||||
/// </summary>
|
||||
public ITextSource InsertedText { |
||||
get { return insertedText; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The number of characters inserted.
|
||||
/// </summary>
|
||||
public int InsertionLength { |
||||
get { return insertedText.TextLength; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new TextChangeEventArgs object.
|
||||
/// </summary>
|
||||
public TextChangeEventArgs(int offset, string removedText, string insertedText) |
||||
{ |
||||
if (offset < 0) |
||||
throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); |
||||
this.offset = offset; |
||||
this.removedText = removedText != null ? new StringTextSource(removedText) : StringTextSource.Empty; |
||||
this.insertedText = insertedText != null ? new StringTextSource(insertedText) : StringTextSource.Empty; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates a new TextChangeEventArgs object.
|
||||
/// </summary>
|
||||
public TextChangeEventArgs(int offset, ITextSource removedText, ITextSource insertedText) |
||||
{ |
||||
if (offset < 0) |
||||
throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative"); |
||||
this.offset = offset; |
||||
this.removedText = removedText ?? StringTextSource.Empty; |
||||
this.insertedText = insertedText ?? StringTextSource.Empty; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the new offset where the specified offset moves after this document change.
|
||||
/// </summary>
|
||||
public virtual int GetNewOffset(int offset, AnchorMovementType movementType = AnchorMovementType.Default) |
||||
{ |
||||
if (offset >= this.Offset && offset <= this.Offset + this.RemovalLength) { |
||||
if (movementType == AnchorMovementType.BeforeInsertion) |
||||
return this.Offset; |
||||
else |
||||
return this.Offset + this.InsertionLength; |
||||
} else if (offset > this.Offset) { |
||||
return offset + this.InsertionLength - this.RemovalLength; |
||||
} else { |
||||
return offset; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Creates TextChangeEventArgs for the reverse change.
|
||||
/// </summary>
|
||||
public virtual TextChangeEventArgs Invert() |
||||
{ |
||||
return new TextChangeEventArgs(offset, insertedText, removedText); |
||||
} |
||||
} |
||||
} |
@ -1,131 +0,0 @@
@@ -1,131 +0,0 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.NRefactory.Editor |
||||
{ |
||||
/// <summary>
|
||||
/// Provides ITextSourceVersion instances.
|
||||
/// </summary>
|
||||
public class TextSourceVersionProvider |
||||
{ |
||||
Version currentVersion; |
||||
|
||||
public TextSourceVersionProvider() |
||||
{ |
||||
this.currentVersion = new Version(this); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the current version.
|
||||
/// </summary>
|
||||
public ITextSourceVersion CurrentVersion { |
||||
get { return currentVersion; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Replaces the current version with a new version.
|
||||
/// </summary>
|
||||
/// <param name="change">Change from current version to new version</param>
|
||||
public void AppendChange(TextChangeEventArgs change) |
||||
{ |
||||
if (change == null) |
||||
throw new ArgumentNullException("change"); |
||||
currentVersion.change = change; |
||||
currentVersion.next = new Version(currentVersion); |
||||
currentVersion = currentVersion.next; |
||||
} |
||||
|
||||
[DebuggerDisplay("Version #{id}")] |
||||
sealed class Version : ITextSourceVersion |
||||
{ |
||||
// Reference back to the provider.
|
||||
// Used to determine if two checkpoints belong to the same document.
|
||||
readonly TextSourceVersionProvider provider; |
||||
// ID used for CompareAge()
|
||||
readonly int id; |
||||
|
||||
// the change from this version to the next version
|
||||
internal TextChangeEventArgs change; |
||||
internal Version next; |
||||
|
||||
internal Version(TextSourceVersionProvider provider) |
||||
{ |
||||
this.provider = provider; |
||||
} |
||||
|
||||
internal Version(Version prev) |
||||
{ |
||||
this.provider = prev.provider; |
||||
this.id = unchecked( prev.id + 1 ); |
||||
} |
||||
|
||||
public bool BelongsToSameDocumentAs(ITextSourceVersion other) |
||||
{ |
||||
Version o = other as Version; |
||||
return o != null && provider == o.provider; |
||||
} |
||||
|
||||
public int CompareAge(ITextSourceVersion other) |
||||
{ |
||||
if (other == null) |
||||
throw new ArgumentNullException("other"); |
||||
Version o = other as Version; |
||||
if (o == null || provider != o.provider) |
||||
throw new ArgumentException("Versions do not belong to the same document."); |
||||
// We will allow overflows, but assume that the maximum distance between checkpoints is 2^31-1.
|
||||
// This is guaranteed on x86 because so many checkpoints don't fit into memory.
|
||||
return Math.Sign(unchecked( this.id - o.id )); |
||||
} |
||||
|
||||
public IEnumerable<TextChangeEventArgs> GetChangesTo(ITextSourceVersion other) |
||||
{ |
||||
int result = CompareAge(other); |
||||
Version o = (Version)other; |
||||
if (result < 0) |
||||
return GetForwardChanges(o); |
||||
else if (result > 0) |
||||
return o.GetForwardChanges(this).Reverse().Select(change => change.Invert()); |
||||
else |
||||
return EmptyList<TextChangeEventArgs>.Instance; |
||||
} |
||||
|
||||
IEnumerable<TextChangeEventArgs> GetForwardChanges(Version other) |
||||
{ |
||||
// Return changes from this(inclusive) to other(exclusive).
|
||||
for (Version node = this; node != other; node = node.next) { |
||||
yield return node.change; |
||||
} |
||||
} |
||||
|
||||
public int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement) |
||||
{ |
||||
int offset = oldOffset; |
||||
foreach (var e in GetChangesTo(other)) { |
||||
offset = e.GetNewOffset(offset, movement); |
||||
} |
||||
return offset; |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue