diff --git a/src/Main/Base/Project/Src/Dom/XmlDoc.cs b/src/Main/Base/Project/Src/Dom/XmlDoc.cs
index 1ff672b079..c94523ed89 100644
--- a/src/Main/Base/Project/Src/Dom/XmlDoc.cs
+++ b/src/Main/Base/Project/Src/Dom/XmlDoc.cs
@@ -8,18 +8,10 @@ namespace ICSharpCode.SharpDevelop.Dom
///
/// Description of XmlDoc.
///
- public class XmlDoc
+ public class XmlDoc : IDisposable
{
Dictionary xmlDescription = new Dictionary();
-
- public Dictionary XmlDescription {
- get {
- return xmlDescription;
- }
- }
- public XmlDoc()
- {
- }
+ Dictionary indexDictionary;
void ReadMembersSection(XmlTextReader reader)
{
@@ -41,6 +33,129 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
+ public string GetDocumentation(string key)
+ {
+ lock (xmlDescription) {
+ if (indexDictionary != null) {
+ if (!indexDictionary.ContainsKey(key))
+ return null;
+ }
+ if (xmlDescription.ContainsKey(key))
+ return xmlDescription[key];
+ if (indexDictionary == null)
+ return null;
+ return LoadDocumentation(key);
+ }
+ }
+
+ #region Save binary files
+ // FILE FORMAT FOR BINARY DOCUMENTATION
+ // long magic = 0x4244636f446c6d58 (identifies file type = 'XmlDocDB')
+ // short version = 1 (file version)
+ // long fileDate (last change date of xml file in DateTime ticks)
+ // int indexPointer (points to location where index starts in the file)
+ // { string docu } (all documentation strings as length-prefixed strings)
+ // indexPointer points to the start of the following section:
+ // {
+ // string key (documentation key as length-prefixed string)
+ // int index (index where the docu string starts in the file)
+ // }
+
+ const long magic = 0x4244636f446c6d58;
+ const short version = 1;
+
+ void Save(string fileName, DateTime fileDate)
+ {
+ using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) {
+ using (BinaryWriter w = new BinaryWriter(fs)) {
+ w.Write(magic);
+ w.Write(version);
+ w.Write(fileDate.Ticks);
+
+ int indexPointerPos = (int)fs.Position;
+ w.Write(0); // skip 4 bytes
+ int[] indices = new int[xmlDescription.Count];
+
+ int i = 0;
+ foreach (KeyValuePair p in xmlDescription) {
+ indices[i++] = (int)fs.Position;
+ w.Write(p.Value.Trim());
+ }
+
+ int indexStart = (int)fs.Position;
+ i = 0;
+ foreach (KeyValuePair p in xmlDescription) {
+ w.Write(p.Key);
+ w.Write(indices[i++]);
+ }
+ w.Seek(indexPointerPos, SeekOrigin.Begin);
+ w.Write(indexStart);
+ }
+ }
+ }
+ #endregion
+
+ #region Load binary files
+ BinaryReader loader;
+ FileStream fs;
+ Queue keyCacheQueue;
+ const int cacheLength = 150; // number of strings to cache when working in file-mode
+
+ bool LoadFromBinary(string fileName, DateTime fileDate)
+ {
+ indexDictionary = new Dictionary();
+ keyCacheQueue = new Queue(cacheLength);
+ fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
+ int len = (int)fs.Length;
+ loader = new BinaryReader(fs);
+ if (loader.ReadInt64() != magic) {
+ Console.WriteLine("Wrong magic");
+ return false;
+ }
+ if (loader.ReadInt16() != version) {
+ Console.WriteLine("Wrong version");
+ return false;
+ }
+ if (loader.ReadInt64() != fileDate.Ticks) {
+ Console.WriteLine("Wrong date");
+ return false;
+ }
+ fs.Position = loader.ReadInt32(); // go to start of index
+ while (fs.Position < len) {
+ string key = loader.ReadString();
+ int pos = loader.ReadInt32();
+ indexDictionary.Add(key, pos);
+ }
+ return true;
+ }
+
+ string LoadDocumentation(string key)
+ {
+ if (keyCacheQueue.Count > cacheLength - 1) {
+ xmlDescription.Remove(keyCacheQueue.Dequeue());
+ }
+ int pos = indexDictionary[key];
+ fs.Position = pos;
+ string docu = loader.ReadString();
+ xmlDescription.Add(key, docu);
+ keyCacheQueue.Enqueue(docu);
+ return docu;
+ }
+
+ public void Dispose()
+ {
+ if (loader != null) {
+ loader.Close();
+ fs.Close();
+ }
+ xmlDescription = null;
+ indexDictionary = null;
+ keyCacheQueue = null;
+ loader = null;
+ fs = null;
+ }
+ #endregion
+
public static XmlDoc Load(TextReader textReader)
{
XmlDoc newXmlDoc = new XmlDoc();
@@ -58,11 +173,43 @@ namespace ICSharpCode.SharpDevelop.Dom
return newXmlDoc;
}
+ static string MakeTempPath()
+ {
+ string tempPath = Path.Combine(Path.GetTempPath(), "SharpDevelop/DocumentationCache");
+ if (!Directory.Exists(tempPath))
+ Directory.CreateDirectory(tempPath);
+ return tempPath;
+ }
+
public static XmlDoc Load(string fileName)
{
+ string cacheName = MakeTempPath() + "/" + Path.GetFileNameWithoutExtension(fileName)
+ + "." + fileName.GetHashCode().ToString("x") + ".dat";
+ XmlDoc doc;
+ if (File.Exists(cacheName)) {
+ doc = new XmlDoc();
+ if (doc.LoadFromBinary(cacheName, File.GetLastWriteTimeUtc(fileName))) {
+ return doc;
+ } else {
+ doc.Dispose();
+ try {
+ File.Delete(cacheName);
+ } catch {}
+ }
+ }
+
using (TextReader textReader = File.OpenText(fileName)) {
- return Load(textReader);
+ doc = Load(textReader);
+ }
+
+ if (doc.xmlDescription.Count > cacheLength * 2) {
+ DateTime date = File.GetLastWriteTimeUtc(fileName);
+ doc.Save(cacheName, date);
+ doc.Dispose();
+ doc = new XmlDoc();
+ doc.LoadFromBinary(cacheName, date);
}
+ return doc;
}
}
}
diff --git a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
index 4ae1d1fa6d..e2c9331257 100644
--- a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
+++ b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs
@@ -94,12 +94,14 @@ namespace ICSharpCode.Core
public string GetXmlDocumentation(string memberTag)
{
- if (xmlDoc.XmlDescription.ContainsKey(memberTag)) {
- return xmlDoc.XmlDescription[memberTag];
+ string desc = xmlDoc.GetDocumentation(memberTag);
+ if (desc != null) {
+ return desc;
}
foreach (IProjectContent referencedContent in referencedContents) {
- if (referencedContent.XmlDoc.XmlDescription.ContainsKey(memberTag)) {
- return referencedContent.XmlDoc.XmlDescription[memberTag];
+ desc = referencedContent.XmlDoc.GetDocumentation(memberTag);
+ if (desc != null) {
+ return desc;
}
}
return null;
@@ -263,6 +265,7 @@ namespace ICSharpCode.Core
public void Dispose()
{
+ xmlDoc.Dispose();
ProjectService.ReferenceAdded -= OnReferenceAdded;
initializing = false;
}
diff --git a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs
index 68c1f4d22a..a60f03de0b 100644
--- a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs
+++ b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs
@@ -24,7 +24,7 @@ namespace ICSharpCode.Core
{
public class ProjectContentRegistry
{
- static Dictionary contents = new Dictionary();
+ static Dictionary contents = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
public static IProjectContent GetMscorlibContent()
{