Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/core/MonoDevelop.Core')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoTargetRuntime.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/UnixFileSystemExtension.cs54
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/BacktrackingStringMatcher.cs22
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ISegment.cs406
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSource.cs206
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSourceVersion.cs74
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/StringTextSource.cs173
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs135
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextFileUtility.cs850
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextSourceVersionProvider.cs136
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/UnicodeNewLine.cs366
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj35
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs27
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs13
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs63
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/DocGenerator.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/IEditableTextFile.cs47
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/ITextFileProvider.cs38
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/HelpService.cs169
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/packages.config6
23 files changed, 2455 insertions, 381 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoTargetRuntime.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoTargetRuntime.cs
index 4c3e290a83..837dac0d7a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoTargetRuntime.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/MonoTargetRuntime.cs
@@ -34,6 +34,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
+using MonoDevelop.Core;
using MonoDevelop.Core.Execution;
using MonoDevelop.Core.AddIns;
using MonoDevelop.Core.Serialization;
@@ -240,7 +241,7 @@ namespace MonoDevelop.Core.Assemblies
return;
foreach (string pcfile in GetAllPkgConfigFiles ()) {
try {
- ParsePCFile (FileService.ResolveFullPath (pcfile));
+ ParsePCFile (new FilePath (pcfile).ResolveLinks ());
if (ShuttingDown)
return;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/UnixFileSystemExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/UnixFileSystemExtension.cs
deleted file mode 100644
index d29c7e9772..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.FileSystem/UnixFileSystemExtension.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// UnixFileSystemExtension.cs
-//
-// Author:
-// Alan McGovern <alan@xamarin.com>
-//
-// Copyright (c) 2011 Xamarin, Inc (http://www.xamarin.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.
-//
-//
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace MonoDevelop.Core.FileSystem
-{
- class UnixFileSystemExtension : DefaultFileSystemExtension
- {
- const int PATHMAX = 4096 + 1;
-
- [DllImport ("libc")]
- static extern IntPtr realpath (string path, IntPtr buffer);
-
- public override FilePath ResolveFullPath (FilePath path)
- {
- IntPtr buffer = IntPtr.Zero;
- try {
- buffer = Marshal.AllocHGlobal (PATHMAX);
- var result = realpath (path, buffer);
- return result == IntPtr.Zero ? "" : Marshal.PtrToStringAuto (buffer);
- } finally {
- if (buffer != IntPtr.Zero)
- Marshal.FreeHGlobal (buffer);
- }
- }
- }
-}
-
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/BacktrackingStringMatcher.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/BacktrackingStringMatcher.cs
index 53c9f25962..d28da461a2 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/BacktrackingStringMatcher.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/BacktrackingStringMatcher.cs
@@ -138,17 +138,23 @@ namespace MonoDevelop.Core.Text
// letter case
ch = text [j];
bool textCharIsUpper = char.IsUpper (ch);
- if (!onlyWordStart && filterChar == (textCharIsUpper ? ch : char.ToUpper (ch)) && char.IsLetter (ch)) {
- // cases don't match. Filter is upper char & letter is low, now prefer the match that does the word skip.
- if (!(textCharIsUpper || (filterTextLowerCaseTable & flag) != 0) && j + 1 < text.Length) {
- int possibleBetterResult = GetMatchChar (text, i, j + 1, onlyWordStart);
- if (possibleBetterResult >= 0)
- return possibleBetterResult;
+ if (!onlyWordStart) {
+ if (filterChar == (textCharIsUpper ? ch : char.ToUpper (ch)) && char.IsLetter (ch)) {
+ // cases don't match. Filter is upper char & letter is low, now prefer the match that does the word skip.
+ if (!(textCharIsUpper || (filterTextLowerCaseTable & flag) != 0) && j + 1 < text.Length) {
+ int possibleBetterResult = GetMatchChar (text, i, j + 1, onlyWordStart);
+ if (possibleBetterResult >= 0)
+ return possibleBetterResult;
+ }
+ return j;
+ }
+ } else {
+ if (textCharIsUpper && filterChar == ch && char.IsLetter (ch)) {
+ return j;
}
- return j;
}
+
// no match, try to continue match at the next word start
-
bool lastWasLower = false;
bool lastWasUpper = false;
int wordStart = j + 1;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ISegment.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ISegment.cs
new file mode 100644
index 0000000000..02c0acfda2
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ISegment.cs
@@ -0,0 +1,406 @@
+//
+// ISegment.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <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>
+ /// An (Offset, Length) pair representing a text span.
+ /// </summary>
+ public struct TextSegment : IEquatable<TextSegment>, ISegment
+ {
+ public static readonly TextSegment Invalid = new TextSegment (-1, 0);
+
+ readonly int offset;
+
+ /// <summary>
+ /// Gets the start offset of the segment.
+ /// </summary>
+ /// <value>
+ /// The offset.
+ /// </value>
+ public int Offset {
+ get {
+ return offset;
+ }
+ }
+
+ readonly int length;
+
+ /// <summary>
+ /// Gets the length of the segment.
+ /// </summary>
+ /// <value>
+ /// The length.
+ /// </value>
+ public int Length {
+ get {
+ return length;
+ }
+ }
+
+ /// <summary>
+ /// Gets the end offset of the segment.
+ /// </summary>
+ /// <remarks>
+ /// EndOffset = Offset + Length;
+ /// </remarks>
+ /// <value>
+ /// The end offset.
+ /// </value>
+ public int EndOffset {
+ get {
+ return Offset + Length;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is empty.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance is empty; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsEmpty {
+ get {
+ return Length == 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is invalid.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance is invalid; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsInvalid {
+ get {
+ return Offset < 0;
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TextSegment"/> struct.
+ /// </summary>
+ /// <param name='offset'>
+ /// The offset of the segment.
+ /// </param>
+ /// <param name='length'>
+ /// The length of the segment.
+ /// </param>
+ public TextSegment (int offset, int length)
+ {
+ this.offset = offset;
+ this.length = length;
+ }
+
+ public static bool operator == (TextSegment left, TextSegment right)
+ {
+ return Equals (left, right);
+ }
+
+ public static bool operator != (TextSegment left, TextSegment right)
+ {
+ return !Equals (left, right);
+ }
+
+ public static bool Equals (TextSegment left, TextSegment right)
+ {
+ return left.Offset == right.Offset && left.Length == right.Length;
+ }
+
+ /// <summary>
+ /// Determines whether this instance is inside the specified offset.
+ /// </summary>
+ /// <returns>
+ /// <c>true</c> if this instance is inside the specified offset (upper bound inclusive); otherwise, <c>false</c>.
+ /// </returns>
+ /// <param name='offset'>
+ /// The offset offset.
+ /// </param>
+ public bool IsInside (int offset)
+ {
+ return Offset <= offset && offset <= EndOffset;
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="TextSegment"/> is equal to the current <see cref="TextSegment"/>.
+ /// </summary>
+ /// <param name='other'>
+ /// The <see cref="TextSegment"/> to compare with the current <see cref="TextSegment"/>.
+ /// </param>
+ /// <returns>
+ /// <c>true</c> if the specified <see cref="TextSegment"/> is equal to the current
+ /// <see cref="TextSegment"/>; otherwise, <c>false</c>.
+ /// </returns>
+ public bool Equals (TextSegment other)
+ {
+ return Equals (this, other);
+ }
+
+ /// <summary>
+ /// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="TextSegment"/>.
+ /// </summary>
+ /// <param name='obj'>
+ /// The <see cref="System.Object"/> to compare with the current <see cref="TextSegment"/>.
+ /// </param>
+ /// <returns>
+ /// <c>true</c> if the specified <see cref="System.Object"/> is equal to the current
+ /// <see cref="TextSegment"/>; otherwise, <c>false</c>.
+ /// </returns>
+ public override bool Equals (object obj)
+ {
+ return obj is ISegment && Equals (this, (ISegment)obj);
+ }
+
+ /// <summary>
+ /// Serves as a hash function for a <see cref="TextSegment"/> object.
+ /// </summary>
+ /// <returns>
+ /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table.
+ /// </returns>
+ public override int GetHashCode ()
+ {
+ return Offset ^ Length;
+ }
+
+ public static TextSegment FromBounds (int startOffset, int endOffset)
+ {
+ if (startOffset > endOffset)
+ throw new ArgumentOutOfRangeException ("endOffset", "endOffset < startOffset");
+ return new TextSegment (startOffset, endOffset - startOffset);
+ }
+
+ /// <summary>
+ /// Returns a <see cref="System.String"/> that represents the current <see cref="TextSegment"/>.
+ /// </summary>
+ /// <returns>
+ /// A <see cref="System.String"/> that represents the current <see cref="TextSegment"/>.
+ /// </returns>
+ public override string ToString ()
+ {
+ return string.Format ("[TextSegment: Offset={0}, Length={1}]", Offset, Length);
+ }
+ }
+
+ /// <summary>
+ /// An abstract implementation of the ISegment (Offset, Length) pair representing a text span.
+ /// </summary>
+ public abstract class AbstractSegment : ISegment
+ {
+ readonly int offset;
+
+ /// <summary>
+ /// Gets the start offset of the segment.
+ /// </summary>
+ /// <value>
+ /// The offset.
+ /// </value>
+ public int Offset {
+ get {
+ return offset;
+ }
+ }
+
+ readonly int length;
+
+ /// <summary>
+ /// Gets the length of the segment.
+ /// </summary>
+ /// <value>
+ /// The length.
+ /// </value>
+ public int Length {
+ get {
+ return length;
+ }
+ }
+
+ /// <summary>
+ /// Gets the end offset of the segment.
+ /// </summary>
+ /// <remarks>
+ /// EndOffset = Offset + Length;
+ /// </remarks>
+ /// <value>
+ /// The end offset.
+ /// </value>
+ public int EndOffset {
+ get {
+ return Offset + Length;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is empty.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance is empty; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsEmpty {
+ get {
+ return Length == 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is invalid.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance is invalid; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsInvalid {
+ get {
+ return Offset < 0;
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TextSegment"/> struct.
+ /// </summary>
+ /// <param name='offset'>
+ /// The offset of the segment.
+ /// </param>
+ /// <param name='length'>
+ /// The length of the segment.
+ /// </param>
+ protected AbstractSegment (int offset, int length)
+ {
+ this.offset = offset;
+ this.length = length;
+ }
+
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="TextSegment"/> struct.
+ /// </summary>
+ protected AbstractSegment (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ this.offset = segment.Offset;
+ this.length = segment.Length;
+ }
+ }
+
+
+ /// <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)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return segment.Offset <= offset && offset + length <= segment.EndOffset;
+ }
+
+ /// <summary>
+ /// Gets whether <paramref name="segment"/> fully contains the specified segment.
+ /// </summary>
+ public static bool Contains (this ISegment segment, ISegment span)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ if (span == null)
+ throw new ArgumentNullException ("span");
+ return segment.Offset <= span.Offset && span.EndOffset <= segment.EndOffset;
+ }
+
+ /// <summary>
+ /// Gets whether the offset is within the <paramref name="segment"/>.
+ /// </summary>
+ public static bool Contains (this ISegment segment, int offset)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return unchecked((uint)(offset - segment.Offset) < (uint)segment.Length);
+ }
+
+ /// <summary>
+ /// Determines whether <paramref name="other"/> overlaps this span. Two spans are considered to overlap
+ /// if they have positions in common and neither is empty. Empty spans do not overlap with any
+ /// other span.
+ /// </summary>
+ public static bool OverlapsWith (this ISegment segment, ISegment other)
+ {
+ int overlapStart = Math.Max (segment.Offset, other.Offset);
+ int overlapEnd = Math.Min (segment.EndOffset, other.EndOffset);
+ return overlapStart < overlapEnd;
+ }
+
+ public static ISegment AdjustSegment (this ISegment segment, TextChangeEventArgs args)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ if (args.Offset < segment.Offset)
+ return new TextSegment (segment.Offset + args.InsertionLength - args.RemovalLength, segment.Length);
+ if (args.Offset <= segment.EndOffset)
+ return new TextSegment (segment.Offset, segment.Length);
+ return segment;
+ }
+
+ public static IEnumerable<ISegment> AdjustSegments (this IEnumerable<ISegment> segments, TextChangeEventArgs args)
+ {
+ if (segments == null)
+ throw new ArgumentNullException ("segments");
+ foreach (var segment in segments) {
+ yield return segment.AdjustSegment (args);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSource.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSource.cs
new file mode 100644
index 0000000000..5dcfd13c51
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSource.cs
@@ -0,0 +1,206 @@
+//
+// ITextSource.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+using System.IO;
+using System.Text;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <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>
+ /// Determines if a byte order mark was read or is going to be written.
+ /// </summary>
+ bool UseBOM { get; }
+
+ /// <summary>
+ /// Encoding of the text that was read from or is going to be saved to.
+ /// </summary>
+ Encoding Encoding { get; }
+
+ /// <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 Length { 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 this [int offset] { 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 GetTextAt (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>
+ /// 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>
+ /// 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);
+ }
+
+ public static class TextSourceExtension
+ {
+ /// <summary>
+ /// Retrieves the text for a portion of the document.
+ /// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
+ public static string GetTextAt (this ITextSource source, ISegment segment)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ return source.GetTextAt (segment.Offset, segment.Length);
+ }
+
+
+ public static string GetTextBetween (this ITextSource source, int startOffset, int endOffset)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ if (startOffset < 0 || startOffset > source.Length)
+ throw new ArgumentNullException ("startOffset");
+ if (endOffset < 0 || endOffset > source.Length)
+ throw new ArgumentNullException ("endOffset");
+ if (startOffset > endOffset)
+ throw new InvalidOperationException ();
+ return source.GetTextAt (startOffset, endOffset - startOffset);
+ }
+
+
+ /// <summary>
+ /// Writes the text from this document into a file.
+ /// </summary>
+ public static void WriteTextTo (this ITextSource source, string fileName)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ TextFileUtility.WriteText (fileName, source.Text, source.Encoding, source.UseBOM);
+ }
+
+ /// <summary>
+ /// Writes the text from this document into the TextWriter.
+ /// </summary>
+ public static void WriteTextTo (this ITextSource source, TextWriter writer, ISegment segment)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ source.WriteTextTo (writer, segment.Offset, segment.Length);
+ }
+
+ /// <summary>
+ /// Creates a new TextReader to read from this text source.
+ /// </summary>
+ public static TextReader CreateReader (this ITextSource source, ISegment segment)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return source.CreateReader (segment.Offset, segment.Length);
+ }
+
+ /// <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>
+ public static ITextSource CreateSnapshot (this ITextSource source, ISegment segment)
+ {
+ if (source == null)
+ throw new ArgumentNullException ("source");
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return source.CreateSnapshot (segment.Offset, segment.Length);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSourceVersion.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSourceVersion.cs
new file mode 100644
index 0000000000..e63b8214fd
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/ITextSourceVersion.cs
@@ -0,0 +1,74 @@
+//
+// ITextSourceVersion.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+
+using System.Collections.Generic;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <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);
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/StringTextSource.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/StringTextSource.cs
new file mode 100644
index 0000000000..d223d16bc7
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/StringTextSource.cs
@@ -0,0 +1,173 @@
+//
+// StringTextSource.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+using System.Text;
+using System.IO;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <summary>
+ /// Implements the ITextSource interface using a string.
+ /// Note that objects from this class are immutable.
+ /// </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>
+ /// Determines if a byte order mark was read or is going to be written.
+ /// </summary>
+ public bool UseBOM { get; private set; }
+
+ /// <summary>
+ /// Encoding of the text that was read from or is going to be saved to.
+ /// </summary>
+ public Encoding Encoding { get; private set; }
+
+ /// <summary>
+ /// Creates a new StringTextSource with the given text.
+ /// </summary>
+ public StringTextSource (string text, Encoding encoding = null, bool useBom = true)
+ {
+ if (text == null)
+ throw new ArgumentNullException ("text");
+ this.text = text;
+ this.UseBOM = useBom;
+ this.Encoding = encoding ?? Encoding.UTF8;
+ }
+
+ /// <summary>
+ /// Creates a new StringTextSource with the given text.
+ /// </summary>
+ public StringTextSource (string text, ITextSourceVersion version, Encoding encoding = null, bool useBom = true)
+ {
+ if (text == null)
+ throw new ArgumentNullException ("text");
+ this.text = text;
+ this.version = version;
+ this.UseBOM = useBom;
+ this.Encoding = encoding ?? Encoding.UTF8;
+ }
+
+ /// <inheritdoc/>
+ public ITextSourceVersion Version {
+ get { return version; }
+ }
+
+ /// <inheritdoc/>
+ public int Length {
+ 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 char GetCharAt (int offset)
+ {
+ return text [offset];
+ }
+
+ public char this [int offset] {
+ get {
+ return text [offset];
+ }
+ }
+
+ /// <inheritdoc/>
+ public string GetTextAt (int offset, int length)
+ {
+ return text.Substring (offset, length);
+ }
+
+ public StringTextSource WithEncoding (Encoding encoding)
+ {
+ return new StringTextSource (text, encoding, UseBOM);
+ }
+
+ public StringTextSource WithBom (bool useBom)
+ {
+ return new StringTextSource (text, Encoding, useBom);
+ }
+
+ public static StringTextSource ReadFrom (string fileName)
+ {
+ bool hadBom;
+ Encoding encoding;
+ var text = TextFileUtility.ReadAllText (fileName, out hadBom, out encoding);
+ return new StringTextSource (text, encoding, hadBom);
+ }
+
+ /// <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)
+ {
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ writer.Write (text);
+ }
+
+ /// <inheritdoc/>
+ public void WriteTextTo (TextWriter writer, int offset, int length)
+ {
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ writer.Write (text.Substring (offset, length));
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs
new file mode 100644
index 0000000000..ccd4033844
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs
@@ -0,0 +1,135 @@
+//
+// TextChangeEventArgs.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <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.Length; }
+ }
+
+ /// <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.Length; }
+ }
+
+ /// <summary>
+ /// InsertionLength - RemovalLength
+ /// </summary>
+ public int ChangeDelta {
+ get {
+ return InsertionLength - RemovalLength;
+ }
+ }
+
+ /// <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)
+ {
+ 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);
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextFileUtility.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextFileUtility.cs
new file mode 100644
index 0000000000..5d7eed6fab
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextFileUtility.cs
@@ -0,0 +1,850 @@
+//
+// TextFileUtility.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <summary>
+ /// This class handles text input from files, streams and byte arrays with auto-detect encoding.
+ /// </summary>
+ public static class TextFileUtility
+ {
+ readonly static int maxBomLength = 0;
+ readonly static Encoding[] encodingsWithBom;
+
+ static TextFileUtility ()
+ {
+ var encodings = new List<Encoding> ();
+
+ foreach (var info in Encoding.GetEncodings ()) {
+ Encoding encoding;
+ try {
+ encoding = info.GetEncoding ();
+ } catch (NotSupportedException) {
+ continue;
+ }
+ var bom = encoding.GetPreamble ();
+ if (bom == null || bom.Length == 0)
+ continue;
+ maxBomLength = Math.Max (maxBomLength, bom.Length);
+ encodings.Add (encoding);
+ }
+ encodingsWithBom = encodings.ToArray ();
+
+ // Encoding verifiers
+ var verifierList = new List<Verifier> {
+ new Utf8Verifier (),
+ new GB18030CodePageVerifier (),
+ new WindowsCodePageVerifier (),
+ new UnicodeVerifier (),
+ new BigEndianUnicodeVerifier (),
+ new CodePage858Verifier ()
+ };
+
+ verifiers = verifierList.Where (v => v.IsSupported).ToArray ();
+
+ // cache the verifier machine state tables, to do the virtual StateTable only once.
+ stateTables = new byte[verifiers.Length][][];
+ for (int i = 0; i < verifiers.Length; i++) {
+ verifiers [i].Initialize ();
+ stateTables [i] = verifiers [i].StateTable;
+ }
+ }
+
+ #region stream reader methods
+ public static StreamReader OpenStream (string fileName)
+ {
+ bool hadBom;
+ return OpenStream (File.ReadAllBytes (fileName), out hadBom);
+ }
+
+ public static StreamReader OpenStream (string fileName, out bool hadBom)
+ {
+ return OpenStream (File.ReadAllBytes (fileName), out hadBom);
+ }
+
+ public static StreamReader OpenStream (byte[] bytes)
+ {
+ bool hadBom;
+ return OpenStream (bytes, out hadBom);
+ }
+
+ public static StreamReader OpenStream (byte[] bytes, out bool hadBom)
+ {
+ if (bytes == null)
+ throw new ArgumentNullException ("bytes");
+ return OpenStream (new MemoryStream (bytes, false), out hadBom);
+ }
+
+ public static StreamReader OpenStream (Stream stream)
+ {
+ bool hadBom;
+ return OpenStream (stream, out hadBom);
+ }
+
+ public static StreamReader OpenStream (Stream stream, out bool hadBom)
+ {
+ if (stream == null)
+ throw new ArgumentNullException ("stream");
+ byte[] possibleBom = new byte[maxBomLength];
+ stream.Read (possibleBom, 0, Math.Min ((int)stream.Length, maxBomLength));
+
+ foreach (var encoding in encodingsWithBom) {
+ var bom = encoding.GetPreamble ();
+ bool invalid = false;
+ for (int i = 0; i < bom.Length; i++) {
+ if (bom [i] != possibleBom [i]) {
+ invalid = true;
+ break;
+ }
+ }
+
+ if (!invalid) {
+ hadBom = true;
+ stream.Position = bom.Length;
+ return new StreamReader (stream, encoding);
+ }
+ }
+ stream.Position = 0;
+ hadBom = false;
+ return new StreamReader (stream, AutoDetectEncoding (stream));
+ }
+ #endregion
+
+ #region string methods
+ public static string GetText (byte[] bytes)
+ {
+ using (var stream = OpenStream (bytes)) {
+ return stream.ReadToEnd ();
+ }
+ }
+
+ public static string GetText (byte[] bytes, out Encoding encoding, out bool hadBom)
+ {
+ if (bytes == null)
+ throw new ArgumentNullException ("bytes");
+ using (var stream = OpenStream (bytes, out hadBom)) {
+ encoding = stream.CurrentEncoding;
+ return stream.ReadToEnd ();
+ }
+ }
+
+ public static string GetText (byte[] bytes, Encoding encoding, out bool hadBom)
+ {
+ byte[] bom = encoding.GetPreamble ();
+ if (bom != null && bom.Length > 0 && bom.Length <= bytes.Length) {
+ hadBom = true;
+ for (int i = 0; i < bom.Length; i++) {
+ if (bytes [i] != bom [i]) {
+ hadBom = false;
+ break;
+ }
+ }
+ } else {
+ hadBom = false;
+ }
+ if (hadBom)
+ return encoding.GetString (bytes, bom.Length, bytes.Length - bom.Length);
+ return encoding.GetString (bytes);
+ }
+
+ public static string GetText (Stream inputStream)
+ {
+ using (var stream = OpenStream (inputStream)) {
+ return stream.ReadToEnd ();
+ }
+ }
+
+ public static string GetText (Stream inputStream, out Encoding encoding, out bool hadBom)
+ {
+ if (inputStream == null)
+ throw new ArgumentNullException ("inputStream");
+ using (var stream = OpenStream (inputStream, out hadBom)) {
+ encoding = stream.CurrentEncoding;
+ return stream.ReadToEnd ();
+ }
+ }
+
+ public static string GetText (string fileName)
+ {
+ using (var stream = OpenStream (fileName)) {
+ return stream.ReadToEnd ();
+ }
+ }
+
+ public static string GetText (string fileName, out Encoding encoding, out bool hadBom)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ using (var stream = OpenStream (fileName, out hadBom)) {
+ encoding = stream.CurrentEncoding;
+ return stream.ReadToEnd ();
+ }
+ }
+
+ #endregion
+
+ #region file methods
+ public static void WriteText (string fileName, string text, Encoding encoding, bool hadBom)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ if (text == null)
+ throw new ArgumentNullException ("text");
+ if (encoding == null)
+ throw new ArgumentNullException ("encoding");
+ // atomic rename only works in the same directory on linux. The tmp files may be on another partition -> breaks save.
+ string tmpPath = Path.Combine (Path.GetDirectoryName (fileName), ".#" + Path.GetFileName (fileName));
+ using (var stream = new FileStream (tmpPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write)) {
+ if (hadBom) {
+ var bom = encoding.GetPreamble ();
+ if (bom != null && bom.Length > 0)
+ stream.Write (bom, 0, bom.Length);
+ }
+ byte[] bytes = encoding.GetBytes (text);
+ stream.Write (bytes, 0, bytes.Length);
+ }
+ try {
+ SystemRename (tmpPath, fileName);
+ } catch (Exception) {
+ try {
+ File.Delete (tmpPath);
+ } catch {
+ // nothing
+ }
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Returns a byte array containing the text encoded by a specified encoding &amp; bom.
+ /// </summary>
+ /// <param name="text">The text to encode.</param>
+ /// <param name="encoding">The encoding.</param>
+ /// <param name="hadBom">If set to <c>true</c> a bom will be prepended.</param>
+ public static byte[] GetBuffer (string text, Encoding encoding, bool hadBom)
+ {
+ using (var stream = new MemoryStream ()) {
+ if (hadBom) {
+ var bom = encoding.GetPreamble ();
+ if (bom != null && bom.Length > 0)
+ stream.Write (bom, 0, bom.Length);
+ }
+ byte[] bytes = encoding.GetBytes (text);
+ stream.Write (bytes, 0, bytes.Length);
+ return stream.GetBuffer ();
+ }
+ }
+
+ // Code taken from FileService.cs
+ static void SystemRename (string sourceFile, string destFile)
+ {
+ //FIXME: use the atomic System.IO.File.Replace on NTFS
+ if (Platform.IsWindows) {
+ string wtmp = null;
+ if (File.Exists (destFile)) {
+ do {
+ wtmp = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
+ } while (File.Exists (wtmp));
+ File.Move (destFile, wtmp);
+ }
+ try {
+ File.Move (sourceFile, destFile);
+ } catch {
+ try {
+ if (wtmp != null)
+ File.Move (wtmp, destFile);
+ } catch {
+ wtmp = null;
+ }
+ throw;
+ } finally {
+ if (wtmp != null) {
+ try {
+ File.Delete (wtmp);
+ } catch {
+ }
+ }
+ }
+ } else {
+ Mono.Unix.Native.Syscall.rename (sourceFile, destFile);
+ }
+ }
+
+ public static string ReadAllText (string fileName)
+ {
+ bool hadBom;
+ Encoding encoding;
+ return ReadAllText (fileName, out hadBom, out encoding);
+ }
+
+ public static string ReadAllText (string fileName, out bool hadBom, out Encoding encoding)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ using (var stream = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
+ return GetText (stream, out encoding, out hadBom);
+ }
+ }
+
+ public static string ReadAllText (string fileName, Encoding encoding, out bool hadBom)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ if (encoding == null)
+ throw new ArgumentNullException ("encoding");
+
+ byte[] content = File.ReadAllBytes (fileName);
+ return GetText (content, encoding, out hadBom);
+ }
+ #endregion
+
+ #region ASCII encoding check
+ public static bool IsASCII (string text)
+ {
+ if (text == null)
+ throw new ArgumentNullException ("text");
+ for (int i = 0; i < text.Length; i++) {
+ var ch = text [i];
+ if (ch > 0x7F)
+ return false;
+ }
+ return true;
+ }
+ #endregion
+
+ #region Binary check
+ public static bool IsBinary (byte[] bytes)
+ {
+ if (bytes == null)
+ throw new ArgumentNullException ("bytes");
+ return IsBinary (new MemoryStream (bytes, false));
+ }
+
+ public static bool IsBinary (string fileName)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ using (var stream = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
+ return IsBinary (stream);
+ }
+ }
+
+ public static bool IsBinary (Stream stream)
+ {
+ if (stream == null)
+ throw new ArgumentNullException ("stream");
+
+ var enc = AutoDetectEncoding (stream);
+ return enc == Encoding.ASCII;
+ }
+ #endregion
+
+ #region Encoding autodetection
+ static readonly Verifier[] verifiers;
+ static readonly byte[][][] stateTables;
+
+ static unsafe Encoding AutoDetectEncoding (Stream stream)
+ {
+ try {
+ int max = (int)Math.Min (stream.Length, 50 * 1024);
+ byte[] readBuf = new byte[max];
+ int readLength = stream.Read (readBuf, 0, max);
+ stream.Position = 0;
+
+ // Store the dfa data from the verifiers in local variables.
+ byte[] states = new byte[verifiers.Length];
+ int verifiersRunning = verifiers.Length;
+
+ for (int i = 0; i < verifiers.Length; i++)
+ states [i] = verifiers [i].InitalState;
+
+ // run the verifiers
+ fixed (byte* bBeginPtr = readBuf, stateBeginPtr = states) {
+ byte* bPtr = bBeginPtr;
+ byte* bEndPtr = bBeginPtr + readLength;
+ byte* sEndPtr = stateBeginPtr + states.Length;
+
+ while (bPtr != bEndPtr) {
+ byte* sPtr = stateBeginPtr;
+ int i = 0;
+ while (sPtr != sEndPtr) {
+ byte curState = *sPtr;
+ if (curState != 0) {
+ curState = stateTables [i] [curState] [*bPtr];
+ if (curState == 0) {
+ verifiersRunning--;
+ if (verifiersRunning == 0)
+ goto finishVerify;
+ }
+ *sPtr = curState;
+ }
+ sPtr++;
+ i++;
+ }
+ bPtr++;
+ }
+ finishVerify:
+ if (verifiersRunning > 0) {
+ // Console.WriteLine ("valid encodings:");
+ // for (int i = 0; i < verifiers.Length; i++) {
+ // if (verifiers [i].IsEncodingValid (states [i]))
+ // Console.WriteLine (verifiers [i].Encoding.EncodingName);
+ // }
+ // Console.WriteLine ("---------------");
+ for (int i = 0; i < verifiers.Length; i++) {
+ if (verifiers [i].IsEncodingValid (states [i]))
+ return verifiers [i].Encoding;
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ Console.WriteLine (e);
+ }
+ return Encoding.ASCII;
+ }
+
+ abstract class Verifier
+ {
+ internal const byte Error = 0;
+ protected static readonly byte[] errorTable = new byte[(int)byte.MaxValue + 1];
+
+ public abstract byte InitalState { get; }
+
+ public abstract Encoding Encoding { get; }
+
+ public abstract byte[][] StateTable { get; }
+
+ protected abstract void Init ();
+
+ bool isInitialized = false;
+
+ public void Initialize ()
+ {
+ if (isInitialized)
+ throw new InvalidOperationException ("Already initialized");
+ isInitialized = true;
+ Init ();
+ }
+
+ public abstract bool IsSupported { get; }
+
+ public virtual bool IsEncodingValid (byte state)
+ {
+ return state != Error;
+ }
+ }
+
+ class Utf8Verifier : Verifier
+ {
+ const byte UTF1 = 1;
+ const byte UTFTail1 = 2;
+ const byte UTFTail2 = 3;
+ const byte UTFTail3 = 4;
+ const byte UTF8_3_TailPre1 = 5;
+ const byte UTF8_3_TailPre2 = 6;
+ const byte UTF8_4_TailPre1 = 7;
+ const byte UTF8_4_TailPre2 = 8;
+ const byte LAST = 9;
+ static byte[][] table;
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.UTF8 != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ protected override void Init ()
+ {
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ // UTF8-1 = %x00-7F
+ // Take out the 0 case, that indicates a UTF16/32 file.
+ for (int i = 0x00; i <= 0x7F; i++) {
+ table [UTF1] [i] = UTF1;
+ }
+
+ // UTF8-tail = %x80-BF
+ for (int i = 0x80; i <= 0xBF; i++) {
+ table [UTFTail1] [i] = UTF1;
+ table [UTFTail2] [i] = UTFTail1;
+ table [UTFTail3] [i] = UTFTail2;
+ }
+
+ // UTF8-2 = %xC2-DF UTF8-tail
+ for (int i = 0xC2; i <= 0xDF; i++)
+ table [UTF1] [i] = UTFTail1;
+
+ // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
+ // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
+ for (int i = 0xA0; i <= 0xBF; i++) {
+ table [UTF8_3_TailPre1] [i] = UTFTail1;
+ }
+ for (int i = 0x80; i <= 0x9F; i++) {
+ table [UTF8_3_TailPre2] [i] = UTFTail1;
+ }
+
+ table [UTF1] [0xE0] = UTF8_3_TailPre1;
+ for (int i = 0xE1; i <= 0xEC; i++)
+ table [UTF1] [i] = UTFTail2;
+ table [UTF1] [0xED] = UTF8_3_TailPre2;
+ for (int i = 0xEE; i <= 0xEF; i++)
+ table [UTF1] [i] = UTFTail2;
+
+ // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
+ // %xF4 %x80-8F 2( UTF8-tail )
+
+ for (int i = 0x90; i <= 0xBF; i++) {
+ table [UTF8_4_TailPre1] [i] = UTFTail2;
+ }
+ for (int i = 0x80; i <= 0xBF; i++) {
+ table [UTF8_4_TailPre2] [i] = UTFTail2;
+ }
+ table [UTF1] [0xF0] = UTF8_4_TailPre1;
+ for (int i = 0xF1; i <= 0xF3; i++)
+ table [UTF1] [i] = UTFTail3;
+ table [UTF1] [0xF4] = UTF8_4_TailPre2;
+
+ // always invalid.
+ for (int i = 0; i < table.Length; i++) {
+ table [i] [0xC0] = Error;
+ table [i] [0xC1] = Error;
+ table [i] [0xF5] = Error;
+ table [i] [0xFF] = Error;
+ }
+ }
+
+ public override byte InitalState { get { return UTF1; } }
+
+ public override Encoding Encoding { get { return Encoding.UTF8; } }
+
+ public override byte[][] StateTable { get { return table; } }
+ }
+
+ /// <summary>
+ /// Unicode verifier
+ /// </summary>
+ class UnicodeVerifier : Verifier
+ {
+ const byte Even = 1;
+ const byte Odd = 2;
+ const byte EvenPossible = 3;
+ const byte OddPossible = 4;
+ const byte LAST = 5;
+ static byte[][] table;
+
+ protected override void Init ()
+ {
+ // Simple approach - detect 0 at odd posititons, then it's likely a utf16
+ // if 0 at an even position it's regarded as no utf-16.
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ for (int i = 0x00; i <= 0xFF; i++) {
+ table [Even] [i] = Odd;
+ table [Odd] [i] = Even;
+ table [EvenPossible] [i] = OddPossible;
+ table [OddPossible] [i] = EvenPossible;
+ }
+ table [Odd] [0] = EvenPossible;
+ table [Even] [0] = Error;
+ table [EvenPossible] [0] = Error;
+ }
+
+ public override byte InitalState { get { return Even; } }
+
+ public override Encoding Encoding { get { return Encoding.Unicode; } }
+
+ public override byte[][] StateTable { get { return table; } }
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.Unicode != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ public override bool IsEncodingValid (byte state)
+ {
+ return state == EvenPossible || state == OddPossible;
+ }
+ }
+
+ class BigEndianUnicodeVerifier : Verifier
+ {
+ const byte Even = 1;
+ const byte Odd = 2;
+ const byte EvenPossible = 3;
+ const byte OddPossible = 4;
+ const byte LAST = 5;
+
+ public override byte InitalState { get { return Even; } }
+
+ public override Encoding Encoding { get { return Encoding.BigEndianUnicode; } }
+
+ public override byte[][] StateTable { get { return table; } }
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.BigEndianUnicode != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ public override bool IsEncodingValid (byte state)
+ {
+ return state == EvenPossible || state == OddPossible;
+ }
+
+ static byte[][] table;
+
+ protected override void Init ()
+ {
+ // Simple approach - detect 0 at even posititons, then it's likely a utf16be
+ // if 0 at an odd position it's regarded as no utf-16be.
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ for (int i = 0x00; i <= 0xFF; i++) {
+ table [Even] [i] = Odd;
+ table [Odd] [i] = Even;
+ table [EvenPossible] [i] = OddPossible;
+ table [OddPossible] [i] = EvenPossible;
+ }
+ table [Odd] [0] = Error;
+ table [OddPossible] [0] = Error;
+ table [Even] [0] = OddPossible;
+ }
+ }
+
+ /// <summary>
+ /// Code page 1252 was the long time default on windows. This encoding is a superset of ISO 8859-1.
+ /// </summary>
+ class WindowsCodePageVerifier : Verifier
+ {
+ const byte Valid = 1;
+ const byte LAST = 2;
+ static byte[][] table;
+ static Encoding EncodingWindows;
+
+ public override byte InitalState { get { return Valid; } }
+
+ public override Encoding Encoding { get { return EncodingWindows; } }
+
+ public override byte[][] StateTable { get { return table; } }
+
+
+ const int westernEncodingCodePage = 1252;
+ /// <summary>
+ /// Try to guess the windows code page using the default encoding, on non windows system default
+ /// to 1252 (western encoding).
+ /// </summary>
+ int WindowsCodePage {
+ get {
+ if (Platform.IsWindows) {
+ int cp = Encoding.Default.CodePage;
+ if (cp >= 1250 && cp < 1260)
+ return cp;
+ }
+ return westernEncodingCodePage;
+ }
+ }
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.GetEncoding (WindowsCodePage) != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ protected override void Init ()
+ {
+ EncodingWindows = Encoding.GetEncoding (WindowsCodePage);
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ for (int i = 0x00; i <= 0xFF; i++) {
+ table [Valid] [i] = Valid;
+ }
+ table [Valid] [0x81] = Error;
+ table [Valid] [0x8D] = Error;
+ table [Valid] [0x8F] = Error;
+ table [Valid] [0x90] = Error;
+ table [Valid] [0x9D] = Error;
+ }
+ }
+
+ /// <summary>
+ /// Code page 858 supports old DOS style files extended with the euro sign.
+ /// </summary>
+ class CodePage858Verifier : Verifier
+ {
+ const byte Valid = 1;
+ const byte LAST = 2;
+ static byte[][] table;
+ static Encoding EncodingCp858;
+
+ public override byte InitalState { get { return Valid; } }
+
+ public override Encoding Encoding { get { return EncodingCp858; } }
+
+ public override byte[][] StateTable { get { return table; } }
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.GetEncoding (858) != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ protected override void Init ()
+ {
+ EncodingCp858 = Encoding.GetEncoding (858);
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ for (int i = 0x20; i <= 0xFF; i++) {
+ table [Valid] [i] = Valid;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Try to detect chinese encoding.
+ /// </summary>
+ class GB18030CodePageVerifier : Verifier
+ {
+ const byte Valid = 1;
+ const byte Second = 2;
+ const byte Third = 3;
+ const byte Fourth = 4;
+ const byte NotValid = 5;
+
+ const byte LAST = 6;
+ static byte[][] table;
+ static Encoding EncodingWindows;
+
+ public override byte InitalState { get { return NotValid; } }
+
+ public override Encoding Encoding { get { return EncodingWindows; } }
+
+ public override byte[][] StateTable { get { return table; } }
+
+ public override bool IsEncodingValid (byte state)
+ {
+ return state == Valid;
+ }
+
+ int WindowsCodePage {
+ get {
+ return 54936;
+ }
+ }
+
+ public override bool IsSupported {
+ get {
+ try {
+ return Encoding.GetEncoding (WindowsCodePage) != null;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+
+ protected override void Init ()
+ {
+ EncodingWindows = Encoding.GetEncoding (WindowsCodePage);
+ table = new byte[LAST][];
+ table [0] = errorTable;
+ for (int i = 1; i < LAST; i++)
+ table [i] = new byte[(int)byte.MaxValue + 1];
+
+ for (int i = 0x00; i <= 0x80; i++)
+ table [Valid] [i] = Valid;
+ for (int i = 0x81; i <= 0xFE; i++)
+ table [Valid] [i] = Second;
+ table [Valid] [0xFF] = Error;
+
+ // need to encounter a multi byte sequence first.
+ for (int i = 0x00; i <= 0x80; i++)
+ table [NotValid] [i] = NotValid;
+ for (int i = 0x81; i <= 0xFE; i++)
+ table [NotValid] [i] = Second;
+ table [NotValid] [0xFF] = Error;
+
+ for (int i = 0x00; i <= 0xFF; i++)
+ table [Second] [i] = Error;
+ for (int i = 0x40; i <= 0xFE; i++)
+ table [Second] [i] = Valid;
+ for (int i = 0x30; i <= 0x39; i++)
+ table [Second] [i] = Third;
+
+ for (int i = 0x00; i <= 0xFF; i++)
+ table [Third] [i] = Error;
+ for (int i = 0x81; i <= 0xFE; i++)
+ table [Third] [i] = Fourth;
+
+ for (int i = 0x00; i <= 0xFF; i++)
+ table [Fourth] [i] = Error;
+ for (int i = 0x30; i <= 0x39; i++)
+ table [Fourth] [i] = Valid;
+ }
+ }
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextSourceVersionProvider.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextSourceVersionProvider.cs
new file mode 100644
index 0000000000..3e2cae228b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextSourceVersionProvider.cs
@@ -0,0 +1,136 @@
+//
+// TextSourceVersionProvider.cs
+//
+// Taken from NRefactory 5.
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MonoDevelop.Core.Text
+{
+ /// <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;
+ }
+
+ 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");
+ var 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 ());
+ return Enumerable.Empty<TextChangeEventArgs> ();
+ }
+
+ IEnumerable<TextChangeEventArgs> GetForwardChanges (Version other)
+ {
+ for (Version node = this; node != other; node = node.next) {
+ yield return node.change;
+ }
+ }
+
+ public int MoveOffsetTo (ITextSourceVersion other, int oldOffset)
+ {
+ int offset = oldOffset;
+ foreach (var e in GetChangesTo(other)) {
+ offset = e.GetNewOffset (offset);
+ }
+ return offset;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/UnicodeNewLine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/UnicodeNewLine.cs
new file mode 100644
index 0000000000..0f371c2f32
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/UnicodeNewLine.cs
@@ -0,0 +1,366 @@
+//
+// UnicodeNewLine.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.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.
+using System;
+
+namespace MonoDevelop.Core.Text
+{
+ public enum UnicodeNewline
+ {
+ Unknown,
+
+ /// <summary>
+ /// Line Feed, U+000A
+ /// </summary>
+ LF = 0x0A,
+
+
+ CRLF = 0x0D0A,
+
+ /// <summary>
+ /// Carriage Return, U+000D
+ /// </summary>
+ CR = 0x0D,
+
+ /// <summary>
+ /// Next Line, U+0085
+ /// </summary>
+ NEL = 0x85,
+
+ /// <summary>
+ /// Vertical Tab, U+000B
+ /// </summary>
+ VT = 0x0B,
+
+ /// <summary>
+ /// Form Feed, U+000C
+ /// </summary>
+ FF = 0x0C,
+
+ /// <summary>
+ /// Line Separator, U+2028
+ /// </summary>
+ LS = 0x2028,
+
+ /// <summary>
+ /// Paragraph Separator, U+2029
+ /// </summary>
+ PS = 0x2029
+ }
+
+
+ /// <summary>
+ /// Defines unicode new lines according to Unicode Technical Report #13
+ /// http://www.unicode.org/standard/reports/tr13/tr13-5.html
+ /// </summary>
+ public static class NewLine
+ {
+ /// <summary>
+ /// Carriage Return, U+000D
+ /// </summary>
+ public const char CR = (char)0x0D;
+
+ /// <summary>
+ /// Line Feed, U+000A
+ /// </summary>
+ public const char LF = (char)0x0A;
+
+ /// <summary>
+ /// Next Line, U+0085
+ /// </summary>
+ public const char NEL = (char)0x85;
+
+ /// <summary>
+ /// Vertical Tab, U+000B
+ /// </summary>
+ public const char VT = (char)0x0B;
+
+ /// <summary>
+ /// Form Feed, U+000C
+ /// </summary>
+ public const char FF = (char)0x0C;
+
+ /// <summary>
+ /// Line Separator, U+2028
+ /// </summary>
+ public const char LS = (char)0x2028;
+
+ /// <summary>
+ /// Paragraph Separator, U+2029
+ /// </summary>
+ public const char PS = (char)0x2029;
+
+ /// <summary>
+ /// Determines if a char is a new line delimiter.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name="nextChar">A callback getting the next character (may be null).</param>
+ public static int GetDelimiterLength (char curChar, Func<char> nextChar = null)
+ {
+ if (curChar == CR) {
+ if (nextChar != null && nextChar () == LF)
+ return 2;
+ return 1;
+ }
+
+ if (curChar == LF || curChar == NEL || curChar == VT || curChar == FF || curChar == LS || curChar == PS)
+ return 1;
+ return 0;
+ }
+
+ /// <summary>
+ /// Determines if a char is a new line delimiter.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name="nextChar">The next character (if != LF then length will always be 0 or 1).</param>
+ public static int GetDelimiterLength (char curChar, char nextChar)
+ {
+ if (curChar == CR) {
+ if (nextChar == LF)
+ return 2;
+ return 1;
+ }
+
+ if (curChar == LF || curChar == NEL || curChar == VT || curChar == FF || curChar == LS || curChar == PS)
+ return 1;
+ return 0;
+ }
+
+
+ /// <summary>
+ /// Determines if a char is a new line delimiter.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name = "length">The length of the delimiter</param>
+ /// <param name = "type">The type of the delimiter</param>
+ /// <param name="nextChar">A callback getting the next character (may be null).</param>
+ public static bool TryGetDelimiterLengthAndType (char curChar, out int length, out UnicodeNewline type, Func<char> nextChar = null)
+ {
+ if (curChar == CR) {
+ if (nextChar != null && nextChar () == LF) {
+ length = 2;
+ type = UnicodeNewline.CRLF;
+ } else {
+ length = 1;
+ type = UnicodeNewline.CR;
+
+ }
+ return true;
+ }
+
+ switch (curChar) {
+ case LF:
+ type = UnicodeNewline.LF;
+ length = 1;
+ return true;
+ case NEL:
+ type = UnicodeNewline.NEL;
+ length = 1;
+ return true;
+ case VT:
+ type = UnicodeNewline.VT;
+ length = 1;
+ return true;
+ case FF:
+ type = UnicodeNewline.FF;
+ length = 1;
+ return true;
+ case LS:
+ type = UnicodeNewline.LS;
+ length = 1;
+ return true;
+ case PS:
+ type = UnicodeNewline.PS;
+ length = 1;
+ return true;
+ }
+ length = -1;
+ type = UnicodeNewline.Unknown;
+ return false;
+ }
+
+ /// <summary>
+ /// Determines if a char is a new line delimiter.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name = "length">The length of the delimiter</param>
+ /// <param name = "type">The type of the delimiter</param>
+ /// <param name="nextChar">The next character (if != LF then length will always be 0 or 1).</param>
+ public static bool TryGetDelimiterLengthAndType (char curChar, out int length, out UnicodeNewline type, char nextChar)
+ {
+ if (curChar == CR) {
+ if (nextChar == LF) {
+ length = 2;
+ type = UnicodeNewline.CRLF;
+ } else {
+ length = 1;
+ type = UnicodeNewline.CR;
+
+ }
+ return true;
+ }
+
+ switch (curChar) {
+ case LF:
+ type = UnicodeNewline.LF;
+ length = 1;
+ return true;
+ case NEL:
+ type = UnicodeNewline.NEL;
+ length = 1;
+ return true;
+ case VT:
+ type = UnicodeNewline.VT;
+ length = 1;
+ return true;
+ case FF:
+ type = UnicodeNewline.FF;
+ length = 1;
+ return true;
+ case LS:
+ type = UnicodeNewline.LS;
+ length = 1;
+ return true;
+ case PS:
+ type = UnicodeNewline.PS;
+ length = 1;
+ return true;
+ }
+ length = -1;
+ type = UnicodeNewline.Unknown;
+ return false;
+ }
+
+ /// <summary>
+ /// Gets the new line type of a given char/next char.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name="nextChar">A callback getting the next character (may be null).</param>
+ public static UnicodeNewline GetDelimiterType (char curChar, Func<char> nextChar = null)
+ {
+ switch (curChar) {
+ case CR:
+ if (nextChar != null && nextChar () == LF)
+ return UnicodeNewline.CRLF;
+ return UnicodeNewline.CR;
+ case LF:
+ return UnicodeNewline.LF;
+ case NEL:
+ return UnicodeNewline.NEL;
+ case VT:
+ return UnicodeNewline.VT;
+ case FF:
+ return UnicodeNewline.FF;
+ case LS:
+ return UnicodeNewline.LS;
+ case PS:
+ return UnicodeNewline.PS;
+ }
+ return UnicodeNewline.Unknown;
+ }
+
+ /// <summary>
+ /// Gets the new line type of a given char/next char.
+ /// </summary>
+ /// <returns>0 == no new line, otherwise it returns either 1 or 2 depending of the length of the delimiter.</returns>
+ /// <param name="curChar">The current character.</param>
+ /// <param name="nextChar">The next character (if != LF then length will always be 0 or 1).</param>
+ public static UnicodeNewline GetDelimiterType (char curChar, char nextChar)
+ {
+ switch (curChar) {
+ case CR:
+ if (nextChar == LF)
+ return UnicodeNewline.CRLF;
+ return UnicodeNewline.CR;
+ case LF:
+ return UnicodeNewline.LF;
+ case NEL:
+ return UnicodeNewline.NEL;
+ case VT:
+ return UnicodeNewline.VT;
+ case FF:
+ return UnicodeNewline.FF;
+ case LS:
+ return UnicodeNewline.LS;
+ case PS:
+ return UnicodeNewline.PS;
+ }
+ return UnicodeNewline.Unknown;
+ }
+
+ /// <summary>
+ /// Determines if a char is a new line delimiter.
+ ///
+ /// Note that the only 2 char wide new line is CR LF and both chars are new line
+ /// chars on their own. For most cases GetDelimiterLength is the better choice.
+ /// </summary>
+ public static bool IsNewLine (char ch)
+ {
+ return
+ ch == NewLine.CR ||
+ ch == NewLine.LF ||
+ ch == NewLine.NEL ||
+ ch == NewLine.VT ||
+ ch == NewLine.FF ||
+ ch == NewLine.LS ||
+ ch == NewLine.PS;
+ }
+
+ /// <summary>
+ /// Gets the new line as a string.
+ /// </summary>
+ public static string GetString (UnicodeNewline newLine)
+ {
+ switch (newLine) {
+ case UnicodeNewline.Unknown:
+ return "";
+ case UnicodeNewline.LF:
+ return "\n";
+ case UnicodeNewline.CRLF:
+ return "\r\n";
+ case UnicodeNewline.CR:
+ return "\r";
+ case UnicodeNewline.NEL:
+ return "\u0085";
+ case UnicodeNewline.VT:
+ return "\u000B";
+ case UnicodeNewline.FF:
+ return "\u000C";
+ case UnicodeNewline.LS:
+ return "\u2028";
+ case UnicodeNewline.PS:
+ return "\u2029";
+ default:
+ throw new ArgumentOutOfRangeException ();
+ }
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
index d980d4c1ce..411f70c72e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
@@ -98,6 +98,18 @@
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Web" />
+ <Reference Include="System.Collections.Immutable">
+ <HintPath>..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reflection.Metadata">
+ <HintPath>..\..\..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.CodeAnalysis.Desktop">
+ <HintPath>..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0-rc1\lib\net45\Microsoft.CodeAnalysis.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.CodeAnalysis">
+ <HintPath>..\..\..\packages\Microsoft.CodeAnalysis.Common.1.0.0-rc1\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
+ </Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Build.Engine" />
@@ -346,9 +358,7 @@
<Compile Include="MonoDevelop.Projects.Policies\PolicyContainer.cs" />
<Compile Include="MonoDevelop.Projects.Policies\ScopedPolicy.cs" />
<Compile Include="MonoDevelop.Projects.Policies\PolicyDictionary.cs" />
- <Compile Include="MonoDevelop.Projects.Text\IEditableTextFile.cs" />
<Compile Include="MonoDevelop.Projects.Text\ITextFile.cs" />
- <Compile Include="MonoDevelop.Projects.Text\ITextFileProvider.cs" />
<Compile Include="MonoDevelop.Projects.Text\TextFile.cs" />
<Compile Include="MonoDevelop.Projects.Text\TextEncoding.cs" />
<Compile Include="MonoDevelop.Projects.Text\TextFileReader.cs" />
@@ -397,7 +407,6 @@
<Compile Include="MonoDevelop.Core\LinuxSystemInformation.cs" />
<Compile Include="MonoDevelop.Core\UnixSystemInformation.cs" />
<Compile Include="MonoDevelop.Core\ISystemInformationProvider.cs" />
- <Compile Include="MonoDevelop.Core.FileSystem\UnixFileSystemExtension.cs" />
<Compile Include="MonoDevelop.Core.LogReporting\CrashEventArgs.cs" />
<Compile Include="MonoDevelop.Core.LogReporting\CrashMonitor.cs" />
<Compile Include="MonoDevelop.Core.LogReporting\ICrashMonitor.cs" />
@@ -438,10 +447,18 @@
<Compile Include="MonoDevelop.Core.Web\STSAuthHelper.cs" />
<Compile Include="MonoDevelop.Core.Web\WIFTypeProvider.cs" />
<Compile Include="MonoDevelop.Core.Web\CredentialProviderExtensions.cs" />
+ <Compile Include="MonoDevelop.Core.Text\ISegment.cs" />
+ <Compile Include="MonoDevelop.Core.Text\UnicodeNewLine.cs" />
+ <Compile Include="MonoDevelop.Core.Text\ITextSource.cs" />
+ <Compile Include="MonoDevelop.Core.Text\TextChangeEventArgs.cs" />
+ <Compile Include="MonoDevelop.Core.Text\StringTextSource.cs" />
+ <Compile Include="MonoDevelop.Core.Text\TextFileUtility.cs" />
+ <Compile Include="MonoDevelop.Core.Text\ITextSourceVersion.cs" />
<Compile Include="MonoDevelop.Core.Execution\IDebugConsole.cs" />
<Compile Include="MonoDevelop.Projects\IDotNetFileContainer.cs" />
<Compile Include="MonoDevelop.Projects.Formats.MSBuild\IMSBuildGlobalPropertyProvider.cs" />
<Compile Include="MonoDevelop.Projects\DotNetProjectImport.cs" />
+ <Compile Include="MonoDevelop.Core.Text\TextSourceVersionProvider.cs" />
<Compile Include="MonoDevelop.Core.LogReporting\CrashReporter.cs" />
<Compile Include="MonoDevelop.Core.Instrumentation\InstrumentationConsumer.cs" />
<Compile Include="MonoDevelop.Projects\DotNetProjectExtension.cs" />
@@ -572,14 +589,6 @@
<Project>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</Project>
<Name>Newtonsoft.Json</Name>
</ProjectReference>
- <ProjectReference Include="..\..\..\external\nrefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
- <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
- <Name>ICSharpCode.NRefactory</Name>
- </ProjectReference>
- <ProjectReference Include="..\..\..\external\nrefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
- <Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
- <Name>ICSharpCode.NRefactory.CSharp</Name>
- </ProjectReference>
<ProjectReference Include="..\..\..\external\mono-addins\Mono.Addins\Mono.Addins.csproj">
<Project>{91DD5A2D-9FE3-4C3C-9253-876141874DAD}</Project>
<Name>Mono.Addins</Name>
@@ -600,10 +609,6 @@
<Project>{63E6915C-7EA4-4D76-AB28-0D7191EEA626}</Project>
<Name>Mono.Cecil.Pdb</Name>
</ProjectReference>
- <ProjectReference Include="..\..\..\external\nrefactory\ICSharpCode.NRefactory.Cecil\ICSharpCode.NRefactory.Cecil.csproj">
- <Project>{2B8F4F83-C2B3-4E84-A27B-8DEE1BE0E006}</Project>
- <Name>ICSharpCode.NRefactory.Cecil</Name>
- </ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="MonoDevelop.Core.dll.config">
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
index c972e9cce6..5718176fcd 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
@@ -28,14 +28,15 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
+using System.Runtime.InteropServices;
namespace MonoDevelop.Core
{
[Serializable]
public struct FilePath: IComparable<FilePath>, IComparable, IEquatable<FilePath>
{
- static readonly StringComparer PathComparer = (Platform.IsWindows || Platform.IsMac) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
- static readonly StringComparison PathComparison = (Platform.IsWindows || Platform.IsMac) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
+ public static readonly StringComparer PathComparer = (Platform.IsWindows || Platform.IsMac) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
+ public static readonly StringComparison PathComparison = (Platform.IsWindows || Platform.IsMac) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
readonly string fileName;
@@ -64,6 +65,28 @@ namespace MonoDevelop.Core
public bool IsEmpty {
get { return fileName != null && fileName.Length == 0; }
+ }
+
+ const int PATHMAX = 4096 + 1;
+
+ [DllImport ("libc")]
+ static extern IntPtr realpath (string path, IntPtr buffer);
+
+ public FilePath ResolveLinks ()
+ {
+ if (Platform.IsWindows) {
+ return Path.GetFullPath (this);
+ }
+
+ IntPtr buffer = IntPtr.Zero;
+ try {
+ buffer = Marshal.AllocHGlobal (PATHMAX);
+ var result = realpath (this, buffer);
+ return result == IntPtr.Zero ? "" : Marshal.PtrToStringAuto (buffer);
+ } finally {
+ if (buffer != IntPtr.Zero)
+ Marshal.FreeHGlobal (buffer);
+ }
}
public FilePath FullPath {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
index 96d24ff503..6968d7b776 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FileService.cs
@@ -50,7 +50,7 @@ namespace MonoDevelop.Core
static FileServiceErrorHandler errorHandler;
static FileSystemExtension fileSystemChain;
- static readonly FileSystemExtension defaultExtension = Platform.IsWindows ? new DefaultFileSystemExtension () : new UnixFileSystemExtension () ;
+ static readonly FileSystemExtension defaultExtension = new DefaultFileSystemExtension ();
static readonly EventQueue eventQueue = new EventQueue ();
@@ -90,17 +90,6 @@ namespace MonoDevelop.Core
}
}
- public static FilePath ResolveFullPath (FilePath path)
- {
- try {
- return GetFileSystemForPath (path, false).ResolveFullPath (path);
- } catch (Exception e) {
- if (!HandleError (GettextCatalog.GetString ("Can't resolve full path {0}", path), e))
- throw;
- return FilePath.Empty;
- }
- }
-
public static void DeleteFile (string fileName)
{
Debug.Assert (!String.IsNullOrEmpty (fileName));
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
index 2c35989714..22f5906ee3 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
@@ -28,7 +28,7 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
@@ -37,17 +37,18 @@ using System.Xml;
using System.Xml.Serialization;
using MonoDevelop.Core;
+using System.Collections.Immutable;
namespace MonoDevelop.Core
{
public class Properties : ICustomXmlSerializer
{
- Dictionary<string, object> properties = new Dictionary<string, object> ();
- Dictionary<string, object> defaultValues = new Dictionary<string, object> ();
- Dictionary<Type, TypeConverter> cachedConverters = new Dictionary<Type, TypeConverter> ();
+ ImmutableDictionary<string, object> properties = ImmutableDictionary<string, object>.Empty;
+ ImmutableDictionary<string, object> defaultValues = ImmutableDictionary<string, object>.Empty;
+ ImmutableDictionary<Type, TypeConverter> cachedConverters = ImmutableDictionary<Type, TypeConverter>.Empty;
Dictionary<string,EventHandler<PropertyChangedEventArgs>> propertyListeners;
- public ICollection<string> Keys {
+ public IEnumerable<string> Keys {
get {
return properties.Keys;
}
@@ -66,19 +67,19 @@ namespace MonoDevelop.Core
return (T) o;
TypeConverter converter = GetConverter (typeof(T));
-
- if (o is string) {
- try {
- return (T)converter.ConvertFromInvariantString (o.ToString ());
- } catch (Exception) {
- return default(T);
+
+ if (o is string) {
+ try {
+ return (T)converter.ConvertFromInvariantString (o.ToString ());
+ } catch (Exception) {
+ return default(T);
}
}
- try {
- return (T)converter.ConvertFrom (o);
- } catch (Exception) {
- return default(T);
+ try {
+ return (T)converter.ConvertFrom (o);
+ } catch (Exception) {
+ return default(T);
}
}
@@ -87,26 +88,26 @@ namespace MonoDevelop.Core
if (o == null)
return null;
TypeConverter converter = GetConverter (o.GetType ());
- return converter.ConvertToInvariantString (o);
+ return converter.ConvertToInvariantString (o);
}
TypeConverter GetConverter (Type type)
{
TypeConverter converter;
- if (!cachedConverters.TryGetValue (type, out converter)) {
+ if (!cachedConverters.TryGetValue (type, out converter)) {
converter = TypeDescriptor.GetConverter (type);
- cachedConverters [type] = converter;
+ cachedConverters = cachedConverters.SetItem (type, converter);
}
return converter;
}
public T Get<T> (string property, T defaultValue)
{
- defaultValues[property] = defaultValue;
+ defaultValues = defaultValues.SetItem (property, defaultValue);
object val;
if (GetPropertyValue<T> (property, out val))
return Convert<T> (val);
- properties[property] = defaultValue;
+ properties = properties.SetItem (property, defaultValue);
return defaultValue;
}
@@ -127,7 +128,7 @@ namespace MonoDevelop.Core
// Deserialize the data and store it in the dictionary, so
// following calls return the same object
val = ((LazyXmlDeserializer)val).Deserialize<T> ();
- properties[property] = val;
+ properties = properties.SetItem (property, val);
}
return true;
} else {
@@ -154,7 +155,7 @@ namespace MonoDevelop.Core
//avoid emitting the event if not necessary
if (val.Equals (old))
return;
- properties[key] = val;
+ properties = properties.SetItem (key, val);
if (!val.GetType ().IsClass ||(val is string)) {
if (defaultValues.ContainsKey (key)) {
if (defaultValues[key] == val)
@@ -239,14 +240,14 @@ namespace MonoDevelop.Core
}
//write out the new state to a temp file
- try {
- using (XmlTextWriter writer = new XmlTextWriter (tempFileName, System.Text.Encoding.UTF8)) {
- writer.Formatting = Formatting.Indented;
- writer.WriteStartElement (PropertiesRootNode);
- writer.WriteAttributeString (PropertiesVersionAttribute, PropertiesVersion);
- Write (writer, false);
- writer.WriteEndElement (); // PropertiesRootNode
- }
+ try {
+ using (XmlTextWriter writer = new XmlTextWriter (tempFileName, System.Text.Encoding.UTF8)) {
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartElement (PropertiesRootNode);
+ writer.WriteAttributeString (PropertiesVersionAttribute, PropertiesVersion);
+ Write (writer, false);
+ writer.WriteEndElement (); // PropertiesRootNode
+ }
//write was successful (no exception)
//so move the file to the real location, overwriting the old file
@@ -355,7 +356,7 @@ namespace MonoDevelop.Core
public Properties Clone ()
{
Properties result = new Properties ();
- result.properties = new Dictionary<string, object> (properties);
+ result.properties = properties;
return result;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/DocGenerator.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/DocGenerator.cs
index 7d5a752b09..94622ce476 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/DocGenerator.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/DocGenerator.cs
@@ -26,7 +26,7 @@
using System;
using MonoDevelop.Core;
using Mono.Addins;
-using ICSharpCode.NRefactory.TypeSystem;
+using Microsoft.CodeAnalysis;
namespace MonoDevelop.Projects.Text
{
@@ -37,7 +37,7 @@ namespace MonoDevelop.Projects.Text
private set;
}
- public abstract string GenerateDocumentation (IMember member, string linePrefix);
+ public abstract string GenerateDocumentation (ISymbol member, string linePrefix);
static DocGenerator ()
{
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/IEditableTextFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/IEditableTextFile.cs
deleted file mode 100644
index fa9a33ff06..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/IEditableTextFile.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// IEditableTextFile.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 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.
-//
-
-using System;
-
-namespace MonoDevelop.Projects.Text
-{
- public interface IEditableTextFile: ITextFile
- {
- new string Text {
- get;
- set;
- }
-
- /// <returns>
- /// The length of the inserted text. The real text may differ in lenth because
- /// of some conversions (tabs -> spaces, different line ends etc.)
- /// </returns>
- int InsertText (int position, string text);
- void DeleteText (int position, int length);
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/ITextFileProvider.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/ITextFileProvider.cs
deleted file mode 100644
index 47afc17755..0000000000
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/ITextFileProvider.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// ITextFileProvider.cs
-//
-// Author:
-// Lluis Sanchez Gual
-//
-// Copyright (C) 2005 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.
-//
-
-using System;
-using MonoDevelop.Core;
-
-namespace MonoDevelop.Projects.Text
-{
- public interface ITextFileProvider
- {
- IEditableTextFile GetEditableTextFile (FilePath filePath);
- }
-}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs
index 85f4dd8b26..7aa7443e11 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs
@@ -39,7 +39,7 @@ using MonoDevelop.Projects.Utility;
namespace MonoDevelop.Projects.Text
{
- public class TextFile: IEditableTextFile
+ public class TextFile: ITextFile
{
const string LIBGLIB = "libglib-2.0-0.dll";
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs
index 48cb680170..79cb567ff8 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetCompilerParameters.cs
@@ -72,5 +72,8 @@ namespace MonoDevelop.Projects
public virtual bool NoStdLib { get; set; }
public virtual string DebugType { get { return ""; } set {} }
+
+ public abstract Microsoft.CodeAnalysis.CompilationOptions CreateCompilationOptions ();
+ public abstract Microsoft.CodeAnalysis.ParseOptions CreateParseOptions ();
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/HelpService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/HelpService.cs
index 55148f5392..c5bf38ffcb 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/HelpService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/HelpService.cs
@@ -33,11 +33,6 @@ using Mono.Addins;
using System.IO;
using System.Collections.Generic;
using MonoDevelop.Projects.Extensions;
-using ICSharpCode.NRefactory.TypeSystem;
-using System.Text;
-using System.Xml;
-using ICSharpCode.NRefactory.Semantics;
-using ICSharpCode.NRefactory.Documentation;
namespace MonoDevelop.Projects
{
@@ -135,172 +130,12 @@ namespace MonoDevelop.Projects
//note: this method is very careful to check that the generated URLs exist in MonoDoc
//because if we send nonexistent URLS to MonoDoc, it shows empty pages
- public static string GetMonoDocHelpUrl (ResolveResult result)
+ public static string GetMonoDocHelpUrl (Microsoft.CodeAnalysis.ISymbol result)
{
if (result == null)
return null;
-
-// if (result is AggregatedResolveResult)
-// result = ((AggregatedResolveResult)result).PrimaryResult;
-
-
- if (result is NamespaceResolveResult) {
- string namespc = ((NamespaceResolveResult)result).NamespaceName;
- //verify that the namespace exists in the help tree
- //FIXME: GetHelpXml doesn't seem to work for namespaces, so forced to do full render
- Monodoc.Node dummy;
- if (!String.IsNullOrEmpty (namespc) && HelpTree != null && HelpTree.RenderUrl ("N:" + namespc, out dummy) != null)
- return "N:" + namespc;
- else
- return null;
- }
-
- IMember member = null;
-// if (result is MethodGroupResolveResult)
-// member = ((MethodGroupResolveResult)result).Methods.FirstOrDefault ();
-// else
- if (result is MemberResolveResult)
- member = ((MemberResolveResult)result).Member;
-
- if (member != null && member.GetMonodocDocumentation () != null)
- return member.GetIdString ();
-
- var type = result.Type;
- if (type != null && !String.IsNullOrEmpty (type.FullName)) {
- string t = "T:" + type.FullName;
- try {
- var tree = HelpTree;
- if (tree != null && tree.GetHelpXml (t) != null)
- return t;
- } catch (Exception) {
- return null;
- }
- }
-
- return null;
- }
- }
-
- public static class HelpExtension
- {
- static void AppendTypeReference (StringBuilder result, ITypeReference type)
- {
- if (type is ArrayTypeReference) {
- var array = (ArrayTypeReference)type;
- AppendTypeReference (result, array.ElementType);
- result.Append ("[");
- result.Append (new string (',', array.Dimensions));
- result.Append ("]");
- return;
- }
-
- if (type is PointerTypeReference) {
- var ptr = (PointerTypeReference)type;
- AppendTypeReference (result, ptr.ElementType);
- result.Append ("*");
- return;
- }
-
- if (type is IType)
- result.Append (((IType)type).FullName);
+ return result.GetDocumentationCommentId ();
}
-
-
- static void AppendHelpParameterList (StringBuilder result, IList<IParameter> parameters)
- {
- result.Append ('(');
- if (parameters != null) {
- for (int i = 0; i < parameters.Count; i++) {
- if (i > 0)
- result.Append (',');
- var p = parameters [i];
- if (p == null)
- continue;
- if (p.IsRef || p.IsOut)
- result.Append ("&");
- AppendTypeReference (result, p.Type.ToTypeReference ());
- }
- }
- result.Append (')');
- }
-
- static void AppendHelpParameterList (StringBuilder result, IList<IUnresolvedParameter> parameters)
- {
- result.Append ('(');
- if (parameters != null) {
- for (int i = 0; i < parameters.Count; i++) {
- if (i > 0)
- result.Append (',');
- var p = parameters [i];
- if (p == null)
- continue;
- if (p.IsRef || p.IsOut)
- result.Append ("&");
- AppendTypeReference (result, p.Type);
- }
- }
- result.Append (')');
- }
-
- static XmlNode FindMatch (IMethod method, XmlNodeList nodes)
- {
- foreach (XmlNode node in nodes) {
- XmlNodeList paramList = node.SelectNodes ("Parameters/*");
- if (method.Parameters.Count == 0 && paramList.Count == 0)
- return node;
- if (method.Parameters.Count != paramList.Count)
- continue;
-
-/* bool matched = true;
- for (int i = 0; i < p.Count; i++) {
- if (p [i].ReturnType.FullName != paramList [i].Attributes ["Type"].Value) {
- matched = false;
- break;
- }
- }
- if (matched)*/
- return node;
- }
- return null;
- }
-
- public static XmlNode GetMonodocDocumentation (this IEntity member)
- {
- if (member.SymbolKind == SymbolKind.TypeDefinition) {
- var helpXml = HelpService.HelpTree != null ? HelpService.HelpTree.GetHelpXml (member.GetIdString ()) : null;
- if (helpXml == null)
- return null;
- return helpXml.SelectSingleNode ("/Type/Docs");
- }
-
- var declaringXml = HelpService.HelpTree != null && member.DeclaringTypeDefinition != null ? HelpService.HelpTree.GetHelpXml (member.DeclaringTypeDefinition.GetIdString ()) : null;
- if (declaringXml == null)
- return null;
-
- switch (member.SymbolKind) {
- case SymbolKind.Method: {
- var nodes = declaringXml.SelectNodes ("/Type/Members/Member[@MemberName='" + member.Name + "']");
- XmlNode node = nodes.Count == 1 ? nodes [0] : FindMatch ((IMethod)member, nodes);
- if (node != null) {
- System.Xml.XmlNode result = node.SelectSingleNode ("Docs");
- return result;
- }
- return null;
- }
- case SymbolKind.Constructor: {
- var nodes = declaringXml.SelectNodes ("/Type/Members/Member[@MemberName='.ctor']");
- XmlNode node = nodes.Count == 1 ? nodes [0] : FindMatch ((IMethod)member, nodes);
- if (node != null) {
- System.Xml.XmlNode result = node.SelectSingleNode ("Docs");
- return result;
- }
- return null;
- }
- default:
- return declaringXml.SelectSingleNode ("/Type/Members/Member[@MemberName='" + member.Name + "']/Docs");
- }
- }
-
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
index 20dffa193b..12ce44ff8c 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
@@ -35,6 +35,8 @@ using MonoDevelop.Core.Serialization;
using MonoDevelop.Core;
using Mono.Addins;
+using MonoDevelop.Core.ProgressMonitoring;
+using MonoDevelop.Core.Execution;
using MonoDevelop.Core.Assemblies;
using MonoDevelop.Core.Instrumentation;
using MonoDevelop.Projects.Extensions;
@@ -177,7 +179,7 @@ namespace MonoDevelop.Projects
return Runtime.RunInMainThread (async delegate {
if (!File.Exists (file))
throw new IOException (GettextCatalog.GetString ("File not found: {0}", file));
- string fullpath = FileService.ResolveFullPath (file).FullPath;
+ string fullpath = file.ResolveLinks ().FullPath;
using (Counters.ReadWorkspaceItem.BeginTiming ("Read solution " + file)) {
fullpath = GetTargetFile (fullpath);
WorkspaceItem item = await GetExtensionChain ().LoadWorkspaceItem (monitor, fullpath) as WorkspaceItem;
diff --git a/main/src/core/MonoDevelop.Core/packages.config b/main/src/core/MonoDevelop.Core/packages.config
index 591f985ff1..6cc5b68cc1 100644
--- a/main/src/core/MonoDevelop.Core/packages.config
+++ b/main/src/core/MonoDevelop.Core/packages.config
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
+ <package id="Microsoft.CodeAnalysis.Common" version="1.0.0-rc1" targetFramework="net45" />
+ <package id="System.Collections.Immutable" version="1.1.33-beta" targetFramework="net45" />
+ <package id="System.Reflection.Metadata" version="1.0.18-beta" targetFramework="net45" />
</packages> \ No newline at end of file