diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2012-01-19 11:52:46 +0400 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2012-01-19 11:52:46 +0400 |
commit | 63a7837c796d7e29f4401ea2369302e6e9462aeb (patch) | |
tree | 8dd0590255e56d27969323a1840a9203dafec499 /main/src | |
parent | 6a4b50b5e965b983bb9bec1c26de891ded16ad2e (diff) | |
parent | 29f45fe8d8697d3347e5e826b42088bc0a10e2ca (diff) |
Merge branch 'master' into newresolver
Diffstat (limited to 'main/src')
19 files changed, 491 insertions, 222 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Highlighting/CSharpSyntaxMode.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Highlighting/CSharpSyntaxMode.cs index 292cb872d8..3dcc911438 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Highlighting/CSharpSyntaxMode.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Highlighting/CSharpSyntaxMode.cs @@ -58,8 +58,11 @@ namespace MonoDevelop.CSharp.Highlighting { if (idx + pattern.Length > str.Length) return false; - int i = idx; - return pattern.All (ch => str[i++] == ch); + + for (int i = 0; i < pattern.Length; i++) + if (pattern [i] != str [idx + i]) + return false; + return true; } } diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs index 5a26821596..328df64795 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/PropertyPad.cs @@ -46,6 +46,7 @@ namespace MonoDevelop.DesignerSupport pg.PropertyGrid grid; MonoDevelop.Components.InvisibleFrame frame; bool customWidget; + IPadWindow container; public PropertyPad () { @@ -61,6 +62,7 @@ namespace MonoDevelop.DesignerSupport { base.Initialize (container); grid.SetToolbarProvider (new DockToolbarProvider (container.GetToolbar (Gtk.PositionType.Top))); + this.container = container; } @@ -97,6 +99,11 @@ namespace MonoDevelop.DesignerSupport internal void UseCustomWidget (Gtk.Widget widget) { + if (container != null) { + var toolbar = container.GetToolbar (Gtk.PositionType.Top); + foreach (var w in toolbar.Children) + toolbar.Remove (w); + } customWidget = true; frame.Remove (frame.Child); frame.Add (widget); diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs index f9bb1b5ca4..2b21cd1348 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs @@ -802,26 +802,34 @@ namespace MonoDevelop.VersionControl.Git return GetCommitTextContent (c, repositoryPath); } + public override DiffInfo GenerateDiff (FilePath baseLocalPath, VersionInfo vi) + { + try { + if ((vi.Status & VersionStatus.ScheduledAdd) != 0) { + var ctxt = GetFileContent (vi.LocalPath); + return new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (EmptyContent, ctxt)); + } else if ((vi.Status & VersionStatus.ScheduledDelete) != 0) { + var ctxt = GetCommitContent (GetHeadCommit (), vi.LocalPath); + return new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (ctxt, EmptyContent)); + } else if ((vi.Status & VersionStatus.Modified) != 0 || (vi.Status & VersionStatus.Conflicted) != 0) { + var ctxt1 = GetCommitContent (GetHeadCommit (), vi.LocalPath); + var ctxt2 = GetFileContent (vi.LocalPath); + return new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (ctxt1, ctxt2)); + } + } catch (Exception ex) { + LoggingService.LogError ("Could not get diff for file '" + vi.LocalPath + "'", ex); + } + return null; + } + public override DiffInfo[] PathDiff (FilePath baseLocalPath, FilePath[] localPaths, bool remoteDiff) { List<DiffInfo> diffs = new List<DiffInfo> (); VersionInfo[] vinfos = GetDirectoryVersionInfo (baseLocalPath, localPaths, false, true); foreach (VersionInfo vi in vinfos) { - try { - if ((vi.Status & VersionStatus.ScheduledAdd) != 0) { - var ctxt = GetFileContent (vi.LocalPath); - diffs.Add (new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (EmptyContent, ctxt))); - } else if ((vi.Status & VersionStatus.ScheduledDelete) != 0) { - var ctxt = GetCommitContent (GetHeadCommit (), vi.LocalPath); - diffs.Add (new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (ctxt, EmptyContent))); - } else if ((vi.Status & VersionStatus.Modified) != 0 || (vi.Status & VersionStatus.Conflicted) != 0) { - var ctxt1 = GetCommitContent (GetHeadCommit (), vi.LocalPath); - var ctxt2 = GetFileContent (vi.LocalPath); - diffs.Add (new DiffInfo (baseLocalPath, vi.LocalPath, GenerateDiff (ctxt1, ctxt2))); - } - } catch (Exception ex) { - LoggingService.LogError ("Could not get diff for file '" + vi.LocalPath + "'", ex); - } + var diff = GenerateDiff (baseLocalPath, vi); + if (diff != null) + diffs.Add (diff); } return diffs.ToArray (); } diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Subversion/MonoDevelop.VersionControl.Subversion/SubversionRepository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Subversion/MonoDevelop.VersionControl.Subversion/SubversionRepository.cs index d0993809ad..b2582b578d 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Subversion/MonoDevelop.VersionControl.Subversion/SubversionRepository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Subversion/MonoDevelop.VersionControl.Subversion/SubversionRepository.cs @@ -479,6 +479,14 @@ namespace MonoDevelop.VersionControl.Subversion }
}
+ public override DiffInfo GenerateDiff (FilePath baseLocalPath, VersionInfo versionInfo)
+ {
+ string diff = Svn.GetUnifiedDiff (versionInfo.LocalPath, false, false);
+ if (!string.IsNullOrEmpty (diff))
+ return GenerateUnifiedDiffInfo (diff, baseLocalPath, new FilePath[] { versionInfo.LocalPath }) [0];
+ return null;
+ }
+
public override DiffInfo[] PathDiff (FilePath localPath, Revision fromRevision, Revision toRevision)
{
string diff = Svn.GetUnifiedDiff (localPath, (SvnRevision)fromRevision, localPath, (SvnRevision)toRevision, true);
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs index 2061e4979b..75eab0ff56 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/StatusView.cs @@ -375,7 +375,7 @@ namespace MonoDevelop.VersionControl.Views void LoadStatus (List<VersionInfo> newList) { - statuses = newList; + statuses = newList.Where (f => FileVisible (f)).ToList (); // Remove from the changeset files/folders which have been deleted var toRemove = new List<ChangeSetItem> (); @@ -933,7 +933,26 @@ namespace MonoDevelop.VersionControl.Views delegate { ddata.diffException = null; try { - ddata.difs = vc.PathDiff (filepath, null, remote); + List<DiffInfo> diffs = new List<DiffInfo> (); + // Calling GenerateDiff and supplying the versioninfo + // is the new fast way of doing things. If we do not get + // the same number of diffs as VersionInfos, we should + // fall back to the old slow method as the VC addin probably + // has not implemented the new fast one. + // The new way can also only be used locally. + if (!remote) { + foreach (var vi in statuses) { + var diff = vc.GenerateDiff (filepath, vi); + if (diff == null) + break; + diffs.Add (diff); + } + } + + if (diffs.Count == statuses.Count) + ddata.difs = diffs.ToArray (); + else + ddata.difs = vc.PathDiff (filepath, null, remote); } catch (Exception ex) { ddata.diffException = ex; } finally { diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/SubviewAttachmentHandler.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/SubviewAttachmentHandler.cs index 42f9856bf2..1b9d9de827 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/SubviewAttachmentHandler.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/SubviewAttachmentHandler.cs @@ -36,23 +36,24 @@ namespace MonoDevelop.VersionControl.Views { protected override void Run () { - Ide.IdeApp.Workbench.DocumentOpened += HandleDocumentOpened; + Ide.IdeApp.Workbench.ActiveDocumentChanged += HandleDocumentChanged; } - void HandleDocumentOpened (object sender, Ide.Gui.DocumentEventArgs e) + void HandleDocumentChanged (object sender, EventArgs e) { - if (!e.Document.IsFile || e.Document.Project == null) + var document = Ide.IdeApp.Workbench.ActiveDocument; + if (document == null || !document.IsFile || document.Project == null || document.Window.FindView<IDiffView> () >= 0) return; - var repo = VersionControlService.GetRepository (e.Document.Project); - if (repo == null || !repo.GetVersionInfo (e.Document.FileName).IsVersioned) + var repo = VersionControlService.GetRepository (document.Project); + if (repo == null || !repo.GetVersionInfo (document.FileName).IsVersioned) return; - var item = new VersionControlItem (repo, e.Document.Project, e.Document.FileName, false, null); - TryAttachView <IDiffView> (e.Document, item, DiffCommand.DiffViewHandlers); - TryAttachView <IBlameView> (e.Document, item, BlameCommand.BlameViewHandlers); - TryAttachView <ILogView> (e.Document, item, LogCommand.LogViewHandlers); - TryAttachView <IMergeView> (e.Document, item, MergeCommand.MergeViewHandlers); + var item = new VersionControlItem (repo, document.Project, document.FileName, false, null); + TryAttachView <IDiffView> (document, item, DiffCommand.DiffViewHandlers); + TryAttachView <IBlameView> (document, item, BlameCommand.BlameViewHandlers); + TryAttachView <ILogView> (document, item, LogCommand.LogViewHandlers); + TryAttachView <IMergeView> (document, item, MergeCommand.MergeViewHandlers); } void TryAttachView <T>(Document document, VersionControlItem item, string type) diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs index 6b5353bac6..05b20fb666 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs @@ -377,6 +377,11 @@ namespace MonoDevelop.VersionControl throw new System.NotSupportedException (); } + public virtual DiffInfo GenerateDiff (FilePath baseLocalPath, VersionInfo versionInfo) + { + return null; + } + // Returns a dif description between local files and the remote files. // baseLocalPath is the root path of the diff. localPaths is optional and // it can be a list of files to compare.
diff --git a/main/src/core/MonoDevelop.Core/Makefile.am b/main/src/core/MonoDevelop.Core/Makefile.am index 777f85cc97..f274796f82 100644 --- a/main/src/core/MonoDevelop.Core/Makefile.am +++ b/main/src/core/MonoDevelop.Core/Makefile.am @@ -268,6 +268,7 @@ FILES = \ MonoDevelop.Projects.Text/TextFileReader.cs \ MonoDevelop.Projects.Text/TextFileService.cs \ MonoDevelop.Projects.Text/TextFormatter.cs \ + MonoDevelop.Projects.Utility/ByteOrderMark.cs \ MonoDevelop.Projects.Utility/DiffUtility.cs \ MonoDevelop.Projects/AuthorInformation.cs \ MonoDevelop.Projects/BuildAction.cs \ diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs index 7900849ee4..2ceaef5e95 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs @@ -239,26 +239,33 @@ namespace MonoDevelop.Core.Assemblies return aname; } + static Dictionary<string, AssemblyName> assemblyNameCache = new Dictionary<string, AssemblyName> (); internal static System.Reflection.AssemblyName GetAssemblyNameObj (string file) { - try { - AssemblyDefinition asm = AssemblyDefinition.ReadAssembly (file);
- return new AssemblyName (asm.Name.FullName); + lock (assemblyNameCache) { + AssemblyName name; + if (assemblyNameCache.TryGetValue (file, out name)) + return name; + + try { + AssemblyDefinition asm = AssemblyDefinition.ReadAssembly (file); + assemblyNameCache [file] = new AssemblyName (asm.Name.FullName); + return assemblyNameCache [file]; - // Don't use reflection to get the name since it is a common cause for deadlocks - // in Mono < 2.6.
- // return System.Reflection.AssemblyName.GetAssemblyName (file); + // Don't use reflection to get the name since it is a common cause for deadlocks + // in Mono < 2.6. + // return System.Reflection.AssemblyName.GetAssemblyName (file); - } catch (FileNotFoundException) { - // GetAssemblyName is not case insensitive in mono/windows. This is a workaround - foreach (string f in Directory.GetFiles (Path.GetDirectoryName (file), Path.GetFileName (file))) { - if (f != file) - return GetAssemblyNameObj (f); + } catch (FileNotFoundException) { + // GetAssemblyName is not case insensitive in mono/windows. This is a workaround + foreach (string f in Directory.GetFiles (Path.GetDirectoryName (file), Path.GetFileName (file))) { + if (f != file) { + assemblyNameCache [file] = GetAssemblyNameObj (f); + return assemblyNameCache [file]; + } + } + throw; } - throw; - } catch (BadImageFormatException) {
- AssemblyDefinition asm = AssemblyDefinition.ReadAssembly (file);
- return new AssemblyName (asm.Name.FullName);
} } @@ -285,7 +292,7 @@ namespace MonoDevelop.Core.Assemblies } } - BuildFrameworkRelations (frameworks);
+ BuildFrameworkRelations (frameworks); } static void BuildFrameworkRelations (Dictionary<TargetFrameworkMoniker, TargetFramework> frameworks) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj index 8655737aae..31ddce7848 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj @@ -405,6 +405,7 @@ <Compile Include="MonoDevelop.Core.LogReporting\MacCrashMonitor.cs" /> <Compile Include="MonoDevelop.Core\PasswordService.cs" /> <Compile Include="MonoDevelop.Core\IPasswordProvider.cs" /> + <Compile Include="MonoDevelop.Projects.Utility\ByteOrderMark.cs" /> </ItemGroup> <ItemGroup> <None Include="Makefile.am" /> diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs index c0caeb856a..23cf673c74 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProject.cs @@ -32,6 +32,9 @@ using System.Collections.Generic; using System.Xml; using System.Text; +using MonoDevelop.Projects.Utility; +using MonoDevelop.Projects.Text; + namespace MonoDevelop.Projects.Formats.MSBuild { public class MSBuildProject @@ -45,6 +48,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild bool endsWithEmptyLine; string newLine = Environment.NewLine; + ByteOrderMark bom; internal static XmlNamespaceManager XmlNamespaceManager { get { @@ -65,51 +69,89 @@ namespace MonoDevelop.Projects.Formats.MSBuild public void Load (string file) { - string xml = File.ReadAllText (file); - LoadXml (xml); - } - - public void LoadXml (string xml) - { + using (FileStream fs = File.OpenRead (file)) { + byte[] buf = new byte [1024]; + int nread, i; + + if ((nread = fs.Read (buf, 0, buf.Length)) <= 0) + return; + + if (ByteOrderMark.TryParse (buf, nread, out bom)) + i = bom.Length; + else + i = 0; + + do { + // Read to the first newline to figure out which line endings this file is using + while (i < nread) { + if (buf[i] == '\r') { + newLine = "\r\n"; + break; + } else if (buf[i] == '\n') { + newLine = "\n"; + break; + } + + i++; + } + + if (newLine == null) { + if ((nread = fs.Read (buf, 0, buf.Length)) <= 0) { + newLine = "\n"; + break; + } + + i = 0; + } + } while (newLine == null); + + // Check for a blank line at the end + endsWithEmptyLine = fs.Seek (-1, SeekOrigin.End) > 0 && fs.ReadByte () == (int) '\n'; + } + + // Load the XML document doc = new XmlDocument (); doc.PreserveWhitespace = false; + + // HACK: XmlStreamReader will fail if the file is encoded in UTF-8 but has <?xml version="1.0" encoding="utf-16"?> + // To work around this, we load the XML content into a string and use XmlDocument.LoadXml() instead. + string xml = File.ReadAllText (file); + doc.LoadXml (xml); - newLine = CountNewLines ("\r\n", xml) > (CountNewLines ("\n", xml) / 2) ? "\r\n" : "\n"; - if (xml.EndsWith (newLine)) - endsWithEmptyLine = true; } - class Utf8Writer: StringWriter + class ProjectWriter : StringWriter { + Encoding encoding; + + public ProjectWriter (ByteOrderMark bom) + { + encoding = bom != null ? Encoding.GetEncoding (bom.Name) : null; + ByteOrderMark = bom; + } + + public ByteOrderMark ByteOrderMark { + get; private set; + } + public override Encoding Encoding { - get { return Encoding.UTF8; } + get { return encoding ?? Encoding.UTF8; } } } - public string Save () + public void Save (string fileName) { // StringWriter.Encoding always returns UTF16. We need it to return UTF8, so the // XmlDocument will write the UTF8 header. - Utf8Writer sw = new Utf8Writer (); + ProjectWriter sw = new ProjectWriter (bom); sw.NewLine = newLine; doc.Save (sw); - string txt = sw.ToString (); - if (endsWithEmptyLine && !txt.EndsWith (newLine)) - txt += newLine; - return txt; - } - - int CountNewLines (string nl, string text) - { - int i = -1; - int c = -1; - do { - c++; - i++; - i = text.IndexOf (nl, i); - } - while (i != -1); - return c; + + string content = sw.ToString (); + if (endsWithEmptyLine && !content.EndsWith (newLine)) + content += newLine; + + TextFile.WriteFile (fileName, content, bom, true); } public string DefaultTargets { diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs index 17e8187f3b..258193d5f3 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectHandler.cs @@ -47,7 +47,6 @@ namespace MonoDevelop.Projects.Formats.MSBuild { public class MSBuildProjectHandler: MSBuildHandler, IResourceHandler, IPathHandler, IAssemblyReferenceHandler { - string fileContent; List<string> targetImports = new List<string> (); IResourceHandler customResourceHandler; List<string> subtypeGuids = new List<string> (); @@ -58,6 +57,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild ITimeTracker timer; bool useXBuild; MSBuildVerbosity verbosity; + string fileName; struct ItemInfo { public MSBuildItem Item; @@ -242,8 +242,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild timer.Trace ("Reading project file"); MSBuildProject p = new MSBuildProject (); - fileContent = File.ReadAllText (fileName); - p.LoadXml (fileContent); + this.fileName = fileName; + p.Load (fileName); //determine the file format MSBuildFileFormat format = null; @@ -340,8 +340,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild throw new Exception ("Unable to correct flavor GUID"); var gg = string.Join (";", subtypeGuids) + ";" + TypeGuid; p.GetGlobalPropertyGroup ().SetPropertyValue ("ProjectTypeGuids", gg.ToUpper ()); - fileContent = p.Save (); - MonoDevelop.Projects.Text.TextFile.WriteFile (fileName, fileContent, "UTF-8"); + p.Save (fileName); } st.UpdateImports ((SolutionEntityItem)item, targetImports); } else @@ -450,8 +449,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild foreach (var t in toRemove) msproject.RemoveItem (t); - fileContent = msproject.Save (); - MonoDevelop.Projects.Text.TextFile.WriteFile (fileName, fileContent, "UTF-8"); + + msproject.Save (fileName); } void Load (IProgressMonitor monitor, MSBuildProject msproject) @@ -782,8 +781,8 @@ namespace MonoDevelop.Projects.Formats.MSBuild DotNetProject dotNetProject = Item as DotNetProject; MSBuildProject msproject = new MSBuildProject (); - if (fileContent != null) { - msproject.LoadXml (fileContent); + if (fileName != null) { + msproject.Load (fileName); } else { msproject.DefaultTargets = "Build"; newProject = true; @@ -857,7 +856,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild langParams = dotNetProject.LanguageParameters; } - if (fileContent == null) + if (fileName == null) ser.InternalItemProperties.ItemData.Sort (globalConfigOrder); WritePropertyGroupMetadata (globalGroup, ser.InternalItemProperties.ItemData, ser, Item, langParams); @@ -1032,16 +1031,11 @@ namespace MonoDevelop.Projects.Formats.MSBuild } else msproject.RemoveProjectExtensions ("MonoDevelop"); - string txt = msproject.Save (); - // Don't save the file to disk if the content did not change - if (txt != fileContent) { - MonoDevelop.Projects.Text.TextFile.WriteFile (eitem.FileName, txt, "UTF-8"); - fileContent = txt; - - if (projectBuilder != null) - projectBuilder.Refresh (); - } + msproject.Save (eitem.FileName); + + if (projectBuilder != null) + projectBuilder.Refresh (); } void ForceDefaultValueSerialization (MSBuildSerializer ser, MSBuildPropertySet baseGroup, object ob) diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs index 166afcd3d2..e3fff3dafc 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MSBuild/MSBuildProjectService.cs @@ -615,7 +615,7 @@ namespace MonoDevelop.Projects.Formats.MSBuild static string LoadProjectTypeGuids (string fileName) { MSBuildProject project = new MSBuildProject (); - project.LoadXml (File.ReadAllText (fileName)); + project.Load (fileName); MSBuildPropertySet globalGroup = project.GetGlobalPropertyGroup (); if (globalGroup == null) 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 f04a5dcae4..41dca321ca 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFile.cs @@ -35,6 +35,7 @@ using System.Runtime.InteropServices; using Mono.Unix; using Mono.Unix.Native;
using MonoDevelop.Core; +using MonoDevelop.Projects.Utility; namespace MonoDevelop.Projects.Text { @@ -73,42 +74,6 @@ namespace MonoDevelop.Projects.Text return tf; } - class BOM - { - public string Enc { - get; - private set; - } - - public byte[] Bytes { - get; - private set; - } - - public BOM (string enc, byte[] bytes) - { - this.Enc = enc; - this.Bytes = bytes; - } - } - - static readonly BOM[] bomTable = new [] { - new BOM ("UTF-8", new byte[] {0xEF, 0xBB, 0xBF}), - new BOM ("UTF-32BE", new byte[] {0x00, 0x00, 0xFE, 0xFF}), - new BOM ("UTF-32LE", new byte[] {0xFF, 0xFE, 0x00, 0x00}), - new BOM ("UTF-16BE", new byte[] {0xFE, 0xFF}), - new BOM ("UTF-16LE", new byte[] {0xFF, 0xFE}), - new BOM ("UTF-7", new byte[] {0x2B, 0x2F, 0x76, 0x38}), - new BOM ("UTF-7", new byte[] {0x2B, 0x2F, 0x76, 0x39}), - new BOM ("UTF-7", new byte[] {0x2B, 0x2F, 0x76, 0x2B}), - new BOM ("UTF-7", new byte[] {0x2B, 0x2F, 0x76, 0x2F}), - new BOM ("UTF-1", new byte[] {0xF7, 0x64, 0x4C}), - new BOM ("UTF-EBCDIC", new byte[] {0xDD, 0x73, 0x66, 073}), - new BOM ("SCSU", new byte[] {0x0E, 0xFE, 0xFF}), - new BOM ("BOCU-1", new byte[] {0xFB, 0xEE, 0x28}), - new BOM ("GB18030",new byte[] {0x84, 0x31, 0x95, 0x33}), - };
-
public void Read (FilePath fileName, string encoding) { // Reads the file using the specified encoding. @@ -118,68 +83,61 @@ namespace MonoDevelop.Projects.Text this.name = fileName; FileInfo f = new FileInfo (fileName); - byte[] content = new byte [f.Length]; + ByteOrderMark bom = null; + byte[] content = null; + long nread; + retry: using (FileStream stream = f.Open (FileMode.Open, FileAccess.Read, FileShare.Read)) { - int n = 0, nc; - while ((nc = stream.Read (content, n, (content.Length - n))) > 0) - n += nc; + if (encoding == null) { + if (ByteOrderMark.TryParse (stream, out bom)) + stream.Seek (bom.Length, SeekOrigin.Begin); + else + stream.Seek (0, SeekOrigin.Begin); + } + + content = new byte [bom != null ? f.Length - bom.Length : f.Length]; + nread = 0; + + int n; + while ((n = stream.Read (content, (int) nread, (content.Length - (int) nread))) > 0) + nread += n; } if (encoding != null) {
- string s = ConvertFromEncoding (content, encoding); + string s = ConvertFromEncoding (content, nread, encoding); if (s == null) { - Read (fileName, null); - return; - } + // The encoding provided was wrong, fall back to trying to use the BOM if it exists... + encoding = null; + content = null; + goto retry; + } + text = new StringBuilder (s); sourceEncoding = encoding; - } else { - string enc = (from bom in bomTable where content.StartsWith (bom.Bytes) select bom.Enc).FirstOrDefault (); - if (!string.IsNullOrEmpty (enc)) { - // remove the BOM (see bug Bug 538827 – Pango crash when opening a specific file)
- byte[] bomBytes = (from bom in bomTable where enc == bom.Enc select bom.Bytes).FirstOrDefault (); - if (bomBytes != null && bomBytes.Length > 0) { - byte[] newContent = new byte [content.Length - bomBytes.Length]; - Array.Copy (content, bomBytes.Length, newContent, 0, newContent.Length); - content = newContent; - } - string s = ConvertFromEncoding (content, enc); + return; + } else if (bom != null) { + string s = ConvertFromEncoding (content, nread, bom.Name); - if (s != null) { - HadBOM = true; - sourceEncoding = enc; - text = new StringBuilder (s); - return; - } - } - HadBOM = false; - - foreach (TextEncoding co in TextEncoding.ConversionEncodings) {
- string s = ConvertFromEncoding (content, co.Id); - if (s != null) { - sourceEncoding = co.Id; - text = new StringBuilder (s); - return; - } + if (s != null) { + HadBOM = true; + sourceEncoding = bom.Name; + text = new StringBuilder (s); + return; } - -/* if (string.IsNullOrEmpty (enc)) - enc = "UTF-8"; - string s = Convert (content, "UTF-8", enc); + } + + // Fall back to trying all the encodings... + foreach (TextEncoding co in TextEncoding.ConversionEncodings) { + string s = ConvertFromEncoding (content, nread, co.Id); if (s != null) { - sourceEncoding = enc; + sourceEncoding = co.Id; text = new StringBuilder (s); return; } - enc = "ISO-8859-15"; - s = Convert (content, "UTF-8", enc); - sourceEncoding = enc; - text = new StringBuilder (s); -*/ - throw new Exception ("Unknown text file encoding"); - } + + throw new Exception ("Unknown text file encoding"); }
public static string GetFileEncoding (FilePath fileName) @@ -191,10 +149,10 @@ namespace MonoDevelop.Projects.Text #region g_convert
- static string ConvertFromEncoding (byte[] content, string fromEncoding) + static string ConvertFromEncoding (byte[] content, long nread, string fromEncoding) { try { - return Encoding.UTF8.GetString (ConvertToBytes (content, "UTF-8", fromEncoding)); + return Encoding.UTF8.GetString (ConvertToBytes (content, nread, "UTF-8", fromEncoding)); } catch (Exception e) { LoggingService.LogWarning ("Fail to use encoding " + fromEncoding, e); return null; @@ -230,12 +188,13 @@ namespace MonoDevelop.Projects.Text return System.Text.Encoding.UTF8.GetString (bytes); } - static byte[] ConvertToBytes (byte[] content, string toEncoding, string fromEncoding) + static byte[] ConvertToBytes (byte[] content, long nread, string toEncoding, string fromEncoding) { - if (content.LongLength > int.MaxValue) + if (nread > int.MaxValue) throw new Exception ("Content too large."); + IntPtr nr = IntPtr.Zero, nw = IntPtr.Zero; - IntPtr clPtr = new IntPtr (content.Length); + IntPtr clPtr = new IntPtr (nread); IntPtr errptr = IntPtr.Zero; IntPtr cc = g_convert (content, clPtr, toEncoding, fromEncoding, ref nr, ref nw, ref errptr); @@ -274,8 +233,7 @@ namespace MonoDevelop.Projects.Text } public bool HadBOM { - get; - set; + get; private set; } public bool Modified { @@ -375,35 +333,110 @@ namespace MonoDevelop.Projects.Text { WriteFile (name, text.ToString (), sourceEncoding, HadBOM); modified = false; - }
-
- public static void WriteFile (FilePath fileName, string content, string encoding) - { - WriteFile (fileName, content, encoding, false); } - public static void WriteFile (FilePath fileName, string content, string encoding, bool saveBOM) + public static void WriteFile (FilePath fileName, byte[] content, string encoding, ByteOrderMark bom, bool onlyIfChanged) { - byte[] buf = Encoding.UTF8.GetBytes (content); + int contentLength = content.Length + (bom != null ? bom.Length : 0); + byte[] converted; if (encoding != null) - buf = ConvertToBytes (buf, encoding, "UTF-8"); + converted = ConvertToBytes (content, content.LongLength, encoding, "UTF-8"); + else + converted = content; + + if (onlyIfChanged) { + FileInfo finfo = new FileInfo (fileName); + if (finfo.Length == contentLength) { + bool changed = false; + + // Open the file on disk and compare them byte by byte... + using (FileStream stream = finfo.Open (FileMode.Open, FileAccess.Read, FileShare.Read)) { + byte[] buf = new byte [4096]; + int bomOffset = 0; + int offset = 0; + int nread; + int i; + + while (!changed && (nread = stream.Read (buf, 0, buf.Length)) > 0) { + i = 0; + + if (bom != null && bomOffset < bom.Length) { + while (i < nread && bomOffset < bom.Length) { + if (bom.Bytes[bomOffset] != buf[i]) { + changed = true; + break; + } + + bomOffset++; + i++; + } + + if (changed) + break; + } + + while (i < nread && offset < converted.Length) { + if (converted[offset] != buf[i]) { + changed = true; + break; + } + + offset++; + i++; + } + + if (offset == converted.Length && i < nread) + changed = true; + } + + if (offset < converted.Length) + changed = true; + } + + if (!changed) + return; + } + + // Content has changed... + } string tempName = Path.GetDirectoryName (fileName) + Path.DirectorySeparatorChar + ".#" + Path.GetFileName (fileName); FileStream fs = new FileStream (tempName, FileMode.Create, FileAccess.Write); - if (saveBOM) { - byte[] bytes = (from bom in bomTable where bom.Enc == encoding select bom.Bytes).FirstOrDefault (); - if (bytes != null) - fs.Write (bytes, 0, bytes.Length); - } + if (bom != null) + fs.Write (bom.Bytes, 0, bom.Length); - fs.Write (buf, 0, buf.Length); + fs.Write (converted, 0, converted.Length); fs.Flush (); - fs.Close ();
-
- FileService.SystemRename (tempName, fileName);
+ fs.Close (); + + FileService.SystemRename (tempName, fileName); + } + + public static void WriteFile (FilePath fileName, string content, string encoding, ByteOrderMark bom, bool onlyIfChanged) + { + byte[] buf = Encoding.UTF8.GetBytes (content); + + WriteFile (fileName, buf, encoding, bom, onlyIfChanged); + } + + public static void WriteFile (FilePath fileName, string content, ByteOrderMark bom, bool onlyIfChanged) + { + WriteFile (fileName, content, bom != null ? bom.Name : null, bom, onlyIfChanged); + } + + public static void WriteFile (FilePath fileName, string content, string encoding) + { + WriteFile (fileName, content, encoding, false); + } + + public static void WriteFile (FilePath fileName, string content, string encoding, bool saveBOM) + { + ByteOrderMark bom = saveBOM && encoding != null ? ByteOrderMark.GetByName (encoding) : null; + + WriteFile (fileName, content, encoding, bom, false); } } diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Utility/ByteOrderMark.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Utility/ByteOrderMark.cs new file mode 100644 index 0000000000..6e31e9d3bf --- /dev/null +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Utility/ByteOrderMark.cs @@ -0,0 +1,121 @@ +// +// ByteOrderMark.cs +// +// Author: Jeffrey Stedfast <jeff@xamarin.com> +// +// Copyright (c) 2012 Xamarin Inc. +// +// 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.Projects.Utility +{ + public class ByteOrderMark + { + static readonly ByteOrderMark[] table = new [] { + new ByteOrderMark ("UTF-8", new byte[] { 0xEF, 0xBB, 0xBF }), + new ByteOrderMark ("UTF-32BE", new byte[] { 0x00, 0x00, 0xFE, 0xFF }), + new ByteOrderMark ("UTF-32LE", new byte[] { 0xFF, 0xFE, 0x00, 0x00 }), + new ByteOrderMark ("UTF-16BE", new byte[] { 0xFE, 0xFF }), + new ByteOrderMark ("UTF-16LE", new byte[] { 0xFF, 0xFE }), + new ByteOrderMark ("UTF-7", new byte[] { 0x2B, 0x2F, 0x76, 0x38 }), + new ByteOrderMark ("UTF-7", new byte[] { 0x2B, 0x2F, 0x76, 0x39 }), + new ByteOrderMark ("UTF-7", new byte[] { 0x2B, 0x2F, 0x76, 0x2B }), + new ByteOrderMark ("UTF-7", new byte[] { 0x2B, 0x2F, 0x76, 0x2F }), + new ByteOrderMark ("UTF-1", new byte[] { 0xF7, 0x64, 0x4C }), + new ByteOrderMark ("UTF-EBCDIC", new byte[] { 0xDD, 0x73, 0x66, 0x73 }), + new ByteOrderMark ("SCSU", new byte[] { 0x0E, 0xFE, 0xFF }), + new ByteOrderMark ("BOCU-1", new byte[] { 0xFB, 0xEE, 0x28 }), + new ByteOrderMark ("GB18030", new byte[] { 0x84, 0x31, 0x95, 0x33 }), + }; + + ByteOrderMark (string name, byte[] bytes) + { + Bytes = bytes; + Name = name; + } + + public string Name { + get; private set; + } + + public byte[] Bytes { + get; private set; + } + + public int Length { + get { return Bytes.Length; } + } + + public static ByteOrderMark GetByName (string name) + { + for (int i = 0; i < table.Length; i++) { + if (table[i].Name == name) + return table[i]; + } + + return null; + } + + public static bool TryParse (byte[] buffer, int available, out ByteOrderMark bom) + { + if (buffer.Length >= 2) { + for (int i = 0; i < table.Length; i++) { + bool matched = true; + + if (available < table[i].Bytes.Length) + continue; + + for (int j = 0; j < table[i].Bytes.Length; j++) { + if (buffer[j] != table[i].Bytes[j]) { + matched = false; + break; + } + } + + if (matched) { + bom = table[i]; + return true; + } + } + } + + bom = null; + + return false; + } + + public static bool TryParse (Stream stream, out ByteOrderMark bom) + { + byte[] buffer = new byte [4]; + int nread; + + if ((nread = stream.Read (buffer, 0, buffer.Length)) < 2) { + bom = null; + + return false; + } + + return TryParse (buffer, nread, out bom); + } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs index e4b81d906f..f9beb9cd05 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs @@ -60,6 +60,10 @@ namespace MonoDevelop.Components } } + public IList<Tab> Tabs { + get { return tabs.AsReadOnly (); } + } + public int TabCount { get { return tabs.Count; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs index 1497b5718d..d0231297f7 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs @@ -90,7 +90,7 @@ namespace MonoDevelop.Ide.Gui content.DirtyChanged += new EventHandler(SetTitleEvent); content.BeforeSave += new EventHandler(BeforeSave); content.ContentChanged += new EventHandler (OnContentChanged); - + IdeApp.Workbench.ActiveDocumentChanged += ActiveDocumentChanged; box.Show (); Add (box); @@ -369,6 +369,7 @@ namespace MonoDevelop.Ide.Gui content.BeforeSave -= new EventHandler(BeforeSave); content.ContentChanged -= new EventHandler (OnContentChanged); content.WorkbenchWindow = null; + IdeApp.Workbench.ActiveDocumentChanged -= ActiveDocumentChanged; content.Dispose (); DetachFromPathedDocument (); @@ -462,25 +463,43 @@ namespace MonoDevelop.Ide.Gui { CheckCreateSubViewToolbar (); updating = true; + + var addedContent = subViewToolbar.TabCount == 0 && IdeApp.Workbench.ActiveDocument == Document; + var widgetBox = new Gtk.VBox (); + var tab = new Tab (subViewToolbar, label) { + Tag = subViewToolbar.TabCount + }; - Tab tab = new Tab (subViewToolbar, label); - tab.Tag = subViewToolbar.TabCount; - tab.Activated += (sender, e) => { SetCurrentView ((int)((Tab)sender).Tag); QueueDraw (); }; - subViewToolbar.AddTab (tab); - - Gtk.VBox widgetBox = new Gtk.VBox (); - widgetBox.Realized += delegate { + // If this is the current displayed document we need to add the control immediately as the tab is already active. + if (addedContent) { widgetBox.Add (viewContent.Control); - }; + widgetBox.ShowAll (); + } + subViewToolbar.AddTab (tab); subViewNotebook.AppendPage (widgetBox, new Gtk.Label ()); - widgetBox.ShowAll (); - + tab.Activated += (sender, e) => { + if (!addedContent) { + widgetBox.Add (viewContent.Control); + widgetBox.ShowAll (); + } + addedContent = true; + SetCurrentView ((int)((Tab)sender).Tag); + QueueDraw (); + }; + EnsureToolbarBoxSeparator (); updating = false; return tab; } + + void ActiveDocumentChanged (object sender, EventArgs e) + { + if (subViewToolbar != null) + subViewToolbar.Tabs [subViewToolbar.ActiveTab].Activate (); + } + #region Track and display document's "path" internal void AttachToPathedDocument (MonoDevelop.Ide.Gui.Content.IPathedDocument pathDoc) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs index 5495794819..4027b54d7a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs @@ -82,7 +82,6 @@ namespace MonoDevelop.Ide descendantItemRemovedHandler = (EventHandler<WorkspaceItemChangeEventArgs>) DispatchService.GuiDispatch (new EventHandler<WorkspaceItemChangeEventArgs> (NotifyDescendantItemRemoved)); configurationsChanged = (EventHandler) DispatchService.GuiDispatch (new EventHandler (NotifyConfigurationsChanged)); - FileService.FileRemoved += (EventHandler<FileEventArgs>) DispatchService.GuiDispatch (new EventHandler<FileEventArgs> (CheckFileRemove)); FileService.FileRenamed += (EventHandler<FileCopyEventArgs>) DispatchService.GuiDispatch (new EventHandler<FileCopyEventArgs> (CheckFileRename)); // Set the initial active runtime @@ -1220,14 +1219,6 @@ namespace MonoDevelop.Ide LoggingService.LogError ("Error in SolutionClosed event.", ex); } } - - void CheckFileRemove(object sender, FileEventArgs e) - { - foreach (Solution sol in GetAllSolutions ()) { - foreach (FilePath p in e.Select (fi => fi.FileName)) - sol.RootFolder.RemoveFileFromProjects (p); - } - } void CheckFileRename(object sender, FileCopyEventArgs args) { diff --git a/main/src/core/MonoDevelop.Startup/app.config b/main/src/core/MonoDevelop.Startup/app.config index aa60d91311..b653baa9ff 100644 --- a/main/src/core/MonoDevelop.Startup/app.config +++ b/main/src/core/MonoDevelop.Startup/app.config @@ -6,6 +6,11 @@ <assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral" /> <bindingRedirect oldVersion="0.84.0.0" newVersion="2.84.0.0"/> </dependentAssembly> + <dependentAssembly> + <!-- This is required on Windows, since the GTK# installer only includes Mono.Cairo 2.0 --> + <assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" /> + <bindingRedirect oldVersion="4.0.0.0" newVersion="2.0.0.0"/> + </dependentAssembly> </assemblyBinding> </runtime> |