diff --git a/ICSharpCode.Editor/IDocument.cs b/ICSharpCode.Editor/IDocument.cs new file mode 100644 index 0000000000..edffab12ab --- /dev/null +++ b/ICSharpCode.Editor/IDocument.cs @@ -0,0 +1,134 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.Editor +{ + /// + /// A document representing a source code file for refactoring. + /// Line and column counting starts at 1. + /// Offset counting starts at 0. + /// + public interface IDocument : ITextBuffer, IServiceProvider + { + /// + /// Gets/Sets the text of the whole document.. + /// + new string Text { get; set; } // hides TextBuffer.Text to add the setter + + /// + /// Gets the total number of lines in the document. + /// + int TotalNumberOfLines { get; } + + /// + /// Gets the document line with the specified number. + /// + /// The number of the line to retrieve. The first line has number 1. + IDocumentLine GetLine(int lineNumber); + + /// + /// Gets the document line that contains the specified offset. + /// + IDocumentLine GetLineByOffset(int offset); + + /// + /// Gets the offset from a text location. + /// + /// + int GetOffset(int line, int column); + + /// + /// Gets the offset from a text location. + /// + /// + int GetOffset(TextLocation location); + + /// + /// Gets the location from an offset. + /// + /// + TextLocation GetLocation(int offset); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// Anchors positioned exactly at the insertion offset will move according to their movement type. + /// For AnchorMovementType.Default, they will move behind the inserted text. + /// + void Insert(int offset, string text); + + /// + /// Inserts text. + /// + /// The offset at which the text is inserted. + /// The new text. + /// + /// 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. + /// + void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType); + + /// + /// Removes text. + /// + /// Starting offset of the text to be removed. + /// Length of the text to be removed. + void Remove(int offset, int length); + + /// + /// Replaces text. + /// + /// The starting offset of the text to be replaced. + /// The length of the text to be replaced. + /// The new text. + void Replace(int offset, int length, string newText); + + /// + /// Make the document combine the following actions into a single + /// action for undo purposes. + /// + void StartUndoableAction(); + + /// + /// Ends the undoable action started with . + /// + void EndUndoableAction(); + + /// + /// Creates an undo group. Dispose the returned value to close the undo group. + /// + /// An object that closes the undo group when Dispose() is called. + IDisposable OpenUndoGroup(); + + /// + /// Creates a new at the specified offset. + /// + /// + ITextAnchor CreateAnchor(int offset); + + /// + /// This event is called directly before a change is applied to the document. + /// + /// + /// 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. + /// + event EventHandler Changing; + + /// + /// This event is called directly after a change is applied to the document. + /// + /// + /// 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. + /// + event EventHandler Changed; + } +} diff --git a/ICSharpCode.Editor/IDocumentLine.cs b/ICSharpCode.Editor/IDocumentLine.cs new file mode 100644 index 0000000000..5709f7e374 --- /dev/null +++ b/ICSharpCode.Editor/IDocumentLine.cs @@ -0,0 +1,50 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.Editor +{ + /// + /// A line inside a . + /// + public interface IDocumentLine + { + /// + /// Gets the starting offset of the line in the document's text. + /// + int Offset { get; } + + /// + /// Gets the length of this line (=the number of characters on the line). + /// + int Length { get; } + + /// + /// Gets the ending offset of the line in the document's text (= Offset + Length). + /// + int EndOffset { get; } + + /// + /// Gets the length of this line, including the line delimiter. + /// + int TotalLength { get; } + + /// + /// Gets the length of the line terminator. + /// Returns 1 or 2; or 0 at the end of the document. + /// + int DelimiterLength { get; } + + /// + /// Gets the number of this line. + /// The first line has the number 1. + /// + int LineNumber { get; } + + /// + /// Gets the text on this line. + /// + string Text { get; } + } +} diff --git a/ICSharpCode.Editor/ITextAnchor.cs b/ICSharpCode.Editor/ITextAnchor.cs new file mode 100644 index 0000000000..dfc95c9e74 --- /dev/null +++ b/ICSharpCode.Editor/ITextAnchor.cs @@ -0,0 +1,102 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.Editor +{ + /// + /// 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. + /// + /// + /// Use the property to get the offset from a text anchor. + /// Use the method to create an anchor from an offset. + /// + /// + /// 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. + /// + /// 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 property also runs in O(lg N). + /// + /// + /// Usage: + /// TextAnchor anchor = document.CreateAnchor(offset); + /// ChangeMyDocument(); + /// int newOffset = anchor.Offset; + /// + /// + public interface ITextAnchor + { + /// + /// Gets the text location of this anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + TextLocation Location { get; } + + /// + /// Gets the offset of the text anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Offset { get; } + + /// + /// Controls how the anchor moves. + /// + AnchorMovementType MovementType { get; set; } + + /// + /// Specifies whether the anchor survives deletion of the text containing it. + /// false: The anchor is deleted when the a selection that includes the anchor is deleted. + /// true: The anchor is not deleted. + /// + bool SurviveDeletion { get; set; } + + /// + /// Gets whether the anchor was deleted. + /// + bool IsDeleted { get; } + + /// + /// Occurs after the anchor was deleted. + /// + event EventHandler Deleted; + + /// + /// Gets the line number of the anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Line { get; } + + /// + /// Gets the column number of this anchor. + /// + /// Thrown when trying to get the Offset from a deleted anchor. + int Column { get; } + } + + /// + /// Defines how a text anchor moves. + /// + public enum AnchorMovementType + { + /// + /// 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 stay + /// behind the inserted text. + /// + Default, + /// + /// Behaves like a start marker - when text is inserted at the anchor position, the anchor will stay + /// before the inserted text. + /// + BeforeInsertion, + /// + /// Behave like an end marker - when text is insered at the anchor position, the anchor will move + /// after the inserted text. + /// + AfterInsertion + } +} diff --git a/ICSharpCode.Editor/ITextBuffer.cs b/ICSharpCode.Editor/ITextBuffer.cs new file mode 100644 index 0000000000..8b950ebb7b --- /dev/null +++ b/ICSharpCode.Editor/ITextBuffer.cs @@ -0,0 +1,130 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.IO; + +namespace ICSharpCode.Editor +{ + /// + /// A read-only view on a (potentially mutable) text buffer. + /// The IDocument interfaces derives from this interface. + /// + public interface ITextBuffer + { + /// + /// Gets a version identifier for this text buffer. + /// Returns null for unversioned text buffers. + /// + ITextBufferVersion Version { get; } + + /// + /// Creates an immutable snapshot of this text buffer. + /// Unlike all other methods in this interface, this method is thread-safe. + /// + ITextBuffer CreateSnapshot(); + + /// + /// Creates an immutable snapshot of a part of this text buffer. + /// Unlike all other methods in this interface, this method is thread-safe. + /// + ITextBuffer CreateSnapshot(int offset, int length); + + /// + /// Creates a new TextReader to read from this text buffer. + /// + TextReader CreateReader(); + + /// + /// Creates a new TextReader to read from this text buffer. + /// + TextReader CreateReader(int offset, int length); + + /// + /// Gets the total text length. + /// + /// The length of the text, in characters. + /// This is the same as Text.Length, but is more efficient because + /// it doesn't require creating a String object. + int TextLength { get; } + + /// + /// Gets the whole text as string. + /// + string Text { get; } + + /// + /// Is raised when the Text property changes. + /// + event EventHandler TextChanged; + + /// + /// Gets a character at the specified position in the document. + /// + /// The index of the character to get. + /// Offset is outside the valid range (0 to TextLength-1). + /// The character at the specified position. + /// This is the same as Text[offset], but is more efficient because + /// it doesn't require creating a String object. + char GetCharAt(int offset); + + /// + /// Retrieves the text for a portion of the document. + /// + /// offset or length is outside the valid range. + /// This is the same as Text.Substring, but is more efficient because + /// it doesn't require creating a String object for the whole document. + string GetText(int offset, int length); + + /// + /// Gets the index of the first occurrence of any character in the specified array. + /// + /// Characters to search for + /// Start index of the search. + /// Length of the area to search. + /// The first index where any character was found; or -1 if no occurrence was found. + int IndexOfAny(char[] anyOf, int startIndex, int count); + } + + /// + /// Represents a version identifier for a text buffer. + /// + /// + /// This is SharpDevelop's equivalent to AvalonEdit ChangeTrackingCheckpoint. + /// It is used by the ParserService to efficiently detect whether a document has changed and needs reparsing. + /// It is a separate class from ITextBuffer to allow the GC to collect the text buffer while the version checkpoint + /// is still in use. + /// + public interface ITextBufferVersion + { + /// + /// Gets whether this checkpoint belongs to the same document as the other checkpoint. + /// + bool BelongsToSameDocumentAs(ITextBufferVersion other); + + /// + /// Compares the age of this checkpoint to the other checkpoint. + /// + /// This method is thread-safe. + /// Raised if 'other' belongs to a different document than this version. + /// -1 if this version is older than . + /// 0 if this version instance represents the same version as . + /// 1 if this version is newer than . + int CompareAge(ITextBufferVersion other); + + /// + /// Gets the changes from this checkpoint to the other checkpoint. + /// If 'other' is older than this checkpoint, reverse changes are calculated. + /// + /// This method is thread-safe. + /// Raised if 'other' belongs to a different document than this checkpoint. + IEnumerable GetChangesTo(ITextBufferVersion other); + + /// + /// Calculates where the offset has moved in the other buffer version. + /// + /// Raised if 'other' belongs to a different document than this checkpoint. + int MoveOffsetTo(ITextBufferVersion other, int oldOffset, AnchorMovementType movement); + } +} \ No newline at end of file diff --git a/ICSharpCode.Editor/ReadOnlyDocument.cs b/ICSharpCode.Editor/ReadOnlyDocument.cs new file mode 100644 index 0000000000..714ad66b7f --- /dev/null +++ b/ICSharpCode.Editor/ReadOnlyDocument.cs @@ -0,0 +1,321 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.Editor +{ + /// + /// Read-only implementation of . + /// + public sealed class ReadOnlyDocument : IDocument + { + readonly ITextBuffer textBuffer; + int[] lines; + + static readonly char[] newline = { '\r', '\n' }; + + /// + /// Creates a new ReadOnlyDocument from the given text buffer. + /// + public ReadOnlyDocument(ITextBuffer textBuffer) + { + if (textBuffer == null) + throw new ArgumentNullException("textBuffer"); + // ensure that underlying buffer is immutable + this.textBuffer = textBuffer.CreateSnapshot(); + List lines = new List(); + lines.Add(0); + int offset = 0; + int textLength = textBuffer.TextLength; + while ((offset = textBuffer.IndexOfAny(newline, offset, textLength - offset)) >= 0) { + offset++; + if (textBuffer.GetCharAt(offset - 1) == '\r' && offset < textLength && textBuffer.GetCharAt(offset) == '\n') { + offset++; + } + lines.Add(offset); + } + this.lines = lines.ToArray(); + } + + /// + /// Creates a new ReadOnlyDocument from the given string. + /// + public ReadOnlyDocument(string text) + : this(new StringTextBuffer(text)) + { + } + + /// + public IDocumentLine GetLine(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 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 string Text { + get { + return doc.GetText(this.Offset, this.Length); + } + } + } + + int GetStartOffset(int lineNumber) + { + return lines[lineNumber-1]; + } + + int GetTotalEndOffset(int lineNumber) + { + return lineNumber < lines.Length ? lines[lineNumber] : textBuffer.TextLength; + } + + int GetEndOffset(int lineNumber) + { + if (lineNumber == lines.Length) + return textBuffer.TextLength; + int off = lines[lineNumber] - 1; + if (off > 0 && textBuffer.GetCharAt(off - 1) == '\r' && textBuffer.GetCharAt(off) == '\n') + off--; + return off; + } + + /// + public IDocumentLine GetLineByOffset(int offset) + { + return GetLine(GetLineNumberForOffset(offset)); + } + + int GetLineNumberForOffset(int offset) + { + int r = Array.BinarySearch(lines, offset); + return r < 0 ? ~r : r + 1; + } + + /// + 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 <= 0) + return lineStart; + int lineEnd = GetEndOffset(line); + if (column >= lineEnd - lineStart) + return lineEnd; + return lineStart + column - 1; + } + + /// + public int GetOffset(TextLocation location) + { + return GetOffset(location.Line, location.Column); + } + + /// + public TextLocation GetLocation(int offset) + { + if (offset < 0 || offset > textBuffer.TextLength) + throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textBuffer.TextLength); + int line = GetLineNumberForOffset(offset); + return new TextLocation(offset-GetStartOffset(line)+1, line); + } + + /// + public string Text { + get { return textBuffer.Text; } + set { + throw new NotSupportedException(); + } + } + + /// + public int TotalNumberOfLines { + get { return lines.Length; } + } + + ITextBufferVersion ITextBuffer.Version { + get { return null; } + } + + /// + public int TextLength { + get { return textBuffer.TextLength; } + } + + event EventHandler IDocument.Changing { add {} remove {} } + + event EventHandler IDocument.Changed { add {} remove {} } + + event EventHandler ITextBuffer.TextChanged { 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.StartUndoableAction() + { + } + + void IDocument.EndUndoableAction() + { + } + + IDisposable IDocument.OpenUndoGroup() + { + return null; + } + + /// + 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; } + } + } + + /// + public ITextBuffer CreateSnapshot() + { + return textBuffer; // textBuffer is immutable + } + + /// + public ITextBuffer CreateSnapshot(int offset, int length) + { + return textBuffer.CreateSnapshot(offset, length); + } + + /// + public System.IO.TextReader CreateReader() + { + return textBuffer.CreateReader(); + } + + /// + public System.IO.TextReader CreateReader(int offset, int length) + { + return textBuffer.CreateReader(offset, length); + } + + /// + public char GetCharAt(int offset) + { + return textBuffer.GetCharAt(offset); + } + + /// + public string GetText(int offset, int length) + { + return textBuffer.GetText(offset, length); + } + + /// + public int IndexOfAny(char[] anyOf, int startIndex, int count) + { + return textBuffer.IndexOfAny(anyOf, startIndex, count); + } + + /// + public object GetService(Type serviceType) + { + return null; + } + } +} diff --git a/ICSharpCode.Editor/StringTextBuffer.cs b/ICSharpCode.Editor/StringTextBuffer.cs new file mode 100644 index 0000000000..cb9857dac5 --- /dev/null +++ b/ICSharpCode.Editor/StringTextBuffer.cs @@ -0,0 +1,85 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; +using System.IO; + +namespace ICSharpCode.Editor +{ + /// + /// Implements the ITextBuffer interface using a string. + /// + [Serializable] + public class StringTextBuffer : ITextBuffer + { + readonly string text; + + /// + /// Creates a new StringTextBuffer with the given text. + /// + public StringTextBuffer(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + this.text = text; + } + + event EventHandler ITextBuffer.TextChanged { add {} remove {} } + + ITextBufferVersion ITextBuffer.Version { + get { return null; } + } + + /// + public int TextLength { + get { return text.Length; } + } + + /// + public string Text { + get { return text; } + } + + /// + public ITextBuffer CreateSnapshot() + { + return this; // StringTextBuffer is immutable + } + + /// + public ITextBuffer CreateSnapshot(int offset, int length) + { + return new StringTextBuffer(text.Substring(offset, length)); + } + + /// + public TextReader CreateReader() + { + return new StringReader(text); + } + + /// + public TextReader CreateReader(int offset, int length) + { + return new StringReader(text.Substring(offset, length)); + } + + /// + public char GetCharAt(int offset) + { + return text[offset]; + } + + /// + public string GetText(int offset, int length) + { + return text.Substring(offset, length); + } + + /// + public int IndexOfAny(char[] anyOf, int startIndex, int count) + { + return text.IndexOfAny(anyOf, startIndex, count); + } + } +} diff --git a/ICSharpCode.Editor/TextChangeEventArgs.cs b/ICSharpCode.Editor/TextChangeEventArgs.cs new file mode 100644 index 0000000000..385f5104a2 --- /dev/null +++ b/ICSharpCode.Editor/TextChangeEventArgs.cs @@ -0,0 +1,64 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.Editor +{ + /// + /// Describes a change of the document text. + /// This class is thread-safe. + /// + [Serializable] + public class TextChangeEventArgs : EventArgs + { + readonly int offset; + readonly string removedText; + readonly string insertedText; + + /// + /// The offset at which the change occurs. + /// + public int Offset { + get { return offset; } + } + + /// + /// The text that was inserted. + /// + public string RemovedText { + get { return removedText; } + } + + /// + /// The number of characters removed. + /// + public int RemovalLength { + get { return removedText.Length; } + } + + /// + /// The text that was inserted. + /// + public string InsertedText { + get { return insertedText; } + } + + /// + /// The number of characters inserted. + /// + public int InsertionLength { + get { return insertedText.Length; } + } + + /// + /// Creates a new TextChangeEventArgs object. + /// + public TextChangeEventArgs(int offset, string removedText, string insertedText) + { + this.offset = offset; + this.removedText = removedText ?? string.Empty; + this.insertedText = insertedText ?? string.Empty; + } + } +} diff --git a/ICSharpCode.Editor/TextLocation.cs b/ICSharpCode.Editor/TextLocation.cs new file mode 100644 index 0000000000..eef1fcf145 --- /dev/null +++ b/ICSharpCode.Editor/TextLocation.cs @@ -0,0 +1,163 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT license (for details please see \doc\license.txt) + +using System; +using System.Globalization; + +namespace ICSharpCode.Editor +{ + /// + /// A line/column position. + /// Text editor lines/columns are counted started from one. + /// + /// + /// The document provides the methods and + /// to convert between offsets and TextLocations. + /// + [Serializable] + public struct TextLocation : IComparable, IEquatable + { + /// + /// Represents no text location (0, 0). + /// + public static readonly TextLocation Empty = new TextLocation(0, 0); + + /// + /// Creates a TextLocation instance. + /// + public TextLocation(int line, int column) + { + this.line = line; + this.column = column; + } + + int column, line; + + /// + /// Gets the line number. + /// + public int Line { + get { return line; } + } + + /// + /// Gets the column number. + /// + public int Column { + get { return column; } + } + + /// + /// Gets whether the TextLocation instance is empty. + /// + public bool IsEmpty { + get { + return column <= 0 && line <= 0; + } + } + + /// + /// Gets a string representation for debugging purposes. + /// + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "(Line {1}, Col {0})", this.column, this.line); + } + + /// + /// Gets a hash code. + /// + public override int GetHashCode() + { + return unchecked (191 * column.GetHashCode() ^ line.GetHashCode()); + } + + /// + /// Equality test. + /// + public override bool Equals(object obj) + { + if (!(obj is TextLocation)) return false; + return (TextLocation)obj == this; + } + + /// + /// Equality test. + /// + public bool Equals(TextLocation other) + { + return this == other; + } + + /// + /// Equality test. + /// + public static bool operator ==(TextLocation left, TextLocation right) + { + return left.column == right.column && left.line == right.line; + } + + /// + /// Inequality test. + /// + public static bool operator !=(TextLocation left, TextLocation right) + { + return left.column != right.column || left.line != right.line; + } + + /// + /// Compares two text locations. + /// + public static bool operator <(TextLocation left, TextLocation right) + { + if (left.line < right.line) + return true; + else if (left.line == right.line) + return left.column < right.column; + else + return false; + } + + /// + /// Compares two text locations. + /// + public static bool operator >(TextLocation left, TextLocation right) + { + if (left.line > right.line) + return true; + else if (left.line == right.line) + return left.column > right.column; + else + return false; + } + + /// + /// Compares two text locations. + /// + public static bool operator <=(TextLocation left, TextLocation right) + { + return !(left > right); + } + + /// + /// Compares two text locations. + /// + public static bool operator >=(TextLocation left, TextLocation right) + { + return !(left < right); + } + + /// + /// Compares two text locations. + /// + public int CompareTo(TextLocation other) + { + if (this == other) + return 0; + if (this < other) + return -1; + else + return 1; + } + } +} diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 79ce68c693..4d7aeb786a 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -1,4 +1,4 @@ - + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} @@ -367,6 +367,10 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil + + {F054A788-B591-4561-A8BA-AE745BBEB817} + ICSharpCode.Editor + \ No newline at end of file diff --git a/NRefactory.sln b/NRefactory.sln index c96b7b6f70..baf2f03d50 100644 --- a/NRefactory.sln +++ b/NRefactory.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.1.0.7372-alpha +# SharpDevelop 4.1.0.7590-alpha Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DC98210E-1646-483B-819A-2BB8272461E4}" ProjectSection(SolutionItems) = postProject README = README @@ -20,6 +20,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "..\Mono.Cecil EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.Demo", "ICSharpCode.NRefactory.Demo\ICSharpCode.NRefactory.Demo.csproj", "{9C19E629-C93E-4ACB-9A4B-13072B5AEF9D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Editor", "ICSharpCode.Editor\ICSharpCode.Editor.csproj", "{F054A788-B591-4561-A8BA-AE745BBEB817}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -68,6 +70,14 @@ Global {9C19E629-C93E-4ACB-9A4B-13072B5AEF9D}.Release|Any CPU.ActiveCfg = Release|x86 {9C19E629-C93E-4ACB-9A4B-13072B5AEF9D}.Release|x86.Build.0 = Release|x86 {9C19E629-C93E-4ACB-9A4B-13072B5AEF9D}.Release|x86.ActiveCfg = Release|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Debug|Any CPU.Build.0 = Debug|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Debug|x86.Build.0 = Debug|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Debug|x86.ActiveCfg = Debug|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Release|Any CPU.Build.0 = Release|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Release|Any CPU.ActiveCfg = Release|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Release|x86.Build.0 = Release|x86 + {F054A788-B591-4561-A8BA-AE745BBEB817}.Release|x86.ActiveCfg = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj diff --git a/README b/README index 551448567d..4c6a493aa3 100644 --- a/README +++ b/README @@ -1,5 +1,9 @@ Overview of the NRefactory library: +ICSharpCode.Editor: + Interfaces that abstract from the text editor control used. + Maybe future AvalonEdit versions will directly implement these interfaces, but you could also write adapters for other editors. + ICSharpCode.NRefactory.TypeSystem: Contains a language-independent representation of the .NET type system. @@ -10,8 +14,17 @@ ICSharpCode.NRefactory.CSharp.Ast: Abstract Syntax Tree for C# ICSharpCode.NRefactory.CSharp.Resolver: - Semantic analysis for C# - + Semantic analysis for C# (resolving the meaning of expressions) + +ICSharpCode.NRefactory.CSharp.Analysis: + Semantic analysis for C# (additional analysis functionality) + +ICSharpCode.NRefactory.Documentation: + Classes for working with .xml documentation files. + +ICSharpCode.NRefactory.PatternMatching: + Provides classes for pattern matching over the C# and VB ASTs. + ICSharpCode.NRefactory.Util: Various helper classes.