⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 defaultparserservice.cs

📁 全功能c#编译器
💻 CS
📖 第 1 页 / 共 3 页
字号:
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krueger" email="mike@icsharpcode.net"/>
//     <version value="$version"/>
// </file>

using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Collections.Utility;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Xml;
using System.Text;

using ICSharpCode.Core.Properties;
using ICSharpCode.Core.Services;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.Core.AddIns;
using ICSharpCode.SharpDevelop.Internal.Project;
using ICSharpCode.SharpDevelop.Gui;
using SharpDevelop.Internal.Parser;

namespace ICSharpCode.SharpDevelop.Services
{
	public class DefaultParserService : AbstractService, IParserService
	{
		Hashtable classes                = new Hashtable();
		Hashtable caseInsensitiveClasses = new Hashtable();
		
		// used to map 'real' namespace hashtable inside case insensitive hashtable
		const string CaseInsensitiveKey = "__CASE_INSENSITIVE_HASH";
		Hashtable namespaces                = new Hashtable();
		Hashtable caseInsensitiveNamespaces = new Hashtable();
		
		Hashtable parsings   = new Hashtable();
		
		ParseInformation addedParseInformation = new ParseInformation();
		ParseInformation removedParseInformation = new ParseInformation();

		/// <remarks>
		/// The keys are the assemblies loaded. This hash table ensures that no
		/// assembly is loaded twice. I know that strong naming might be better but
		/// the use case isn't there. No one references 2 differnt files if he references
		/// the same assembly.
		/// </remarks>
		Hashtable loadedAssemblies = new Hashtable();
		
		ClassProxyCollection classProxies = new ClassProxyCollection();
		IParser[] parser;
		readonly static string[] assemblyList = {
			"Microsoft.VisualBasic",
			"Microsoft.JScript",
			"mscorlib",
			"System.Data",
			"System.Design",
			"System.DirectoryServices",
			"System.Drawing.Design",
			"System.Drawing",
			"System.EnterpriseServices",
			"System.Management",
			"System.Messaging",
			"System.Runtime.Remoting",
			"System.Runtime.Serialization.Formatters.Soap",

			"System.Security",
			"System.ServiceProcess",
			"System.Web.Services",
			"System.Web",
			"System.Windows.Forms",
			"System",
			"System.XML"
		};
		
		public DefaultParserService()
		{
			addedParseInformation.DirtyCompilationUnit = new DummyCompilationUnit();
			removedParseInformation.DirtyCompilationUnit = new DummyCompilationUnit();
		}
		
		public static string[] AssemblyList {
			get {
				return assemblyList;
			}
		}

		/// <remarks>
		/// The initialize method writes the location of the code completion proxy
		/// file to this string.
		/// </remarks>
		string codeCompletionProxyFile;
		string codeCompletionMainFile;

		class ClasstableEntry
		{
			IClass           myClass;
			ICompilationUnit myCompilationUnit;
			string           myFileName;

			public IClass Class {
				get {
					return myClass;
				}
			}

			public ICompilationUnit CompilationUnit {
				get {
					return myCompilationUnit;
				}
			}

			public string FileName {
				get {
					return myFileName;
				}
			}

			public ClasstableEntry(string fileName, ICompilationUnit compilationUnit, IClass c)
			{
				this.myCompilationUnit = compilationUnit;
				this.myFileName        = fileName;
				this.myClass           = c;
			}
		}
		
		public void GenerateCodeCompletionDatabase(string createPath, IProgressMonitor progressMonitor)
		{
			SetCodeCompletionFileLocation(createPath);

			// write all classes and proxies to the disc
			BinaryWriter classWriter = new BinaryWriter(new BufferedStream(new FileStream(codeCompletionMainFile, FileMode.Create, FileAccess.Write, FileShare.None)));
			BinaryWriter proxyWriter = new BinaryWriter(new BufferedStream(new FileStream(codeCompletionProxyFile, FileMode.Create, FileAccess.Write, FileShare.None)));
			if (progressMonitor != null) {
				progressMonitor.BeginTask("generate code completion database", assemblyList.Length);
			}
			
			// convert all assemblies
			for (int i = 0; i < assemblyList.Length; ++i) {
				try {
					FileUtilityService fileUtilityService = (FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));
					string path = fileUtilityService.GetDirectoryNameWithSeparator(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory());
					
					AssemblyInformation frameworkAssemblyInformation = new AssemblyInformation();
					frameworkAssemblyInformation.Load(String.Concat(path, assemblyList[i], ".dll"), false);
					// create all class proxies
					foreach (IClass newClass in frameworkAssemblyInformation.Classes) {
						ClassProxy newProxy = new ClassProxy(newClass);
						classProxies.Add(newProxy);
						AddClassToNamespaceList(newProxy);

						PersistentClass pc = new PersistentClass(classProxies, newClass);
						newProxy.Offset = (uint)classWriter.BaseStream.Position;
						newProxy.WriteTo(proxyWriter);
						pc.WriteTo(classWriter);
					}
					
					if (progressMonitor != null) {
						progressMonitor.Worked(i);
					}
				} catch (Exception) {
				}
			}

			classWriter.Close();
			proxyWriter.Close();
			if (progressMonitor != null) {
				progressMonitor.Done();
			}
		}
		
		void SetCodeCompletionFileLocation(string path)
		{
			FileUtilityService fileUtilityService = (FileUtilityService)ServiceManager.Services.GetService(typeof(FileUtilityService));
			string codeCompletionTemp = fileUtilityService.GetDirectoryNameWithSeparator(path);

			codeCompletionProxyFile = codeCompletionTemp + "CodeCompletionProxyDataV02.bin";
			codeCompletionMainFile  = codeCompletionTemp + "CodeCompletionMainDataV02.bin";
		}

		void SetDefaultCompletionFileLocation()
		{
			PropertyService propertyService = (PropertyService)ServiceManager.Services.GetService(typeof(PropertyService));
			SetCodeCompletionFileLocation(propertyService.GetProperty("SharpDevelop.CodeCompletion.DataDirectory", String.Empty).ToString());
		}

		public void LoadProxyDataFile()
		{
			if (!File.Exists(codeCompletionProxyFile)) {
				return;
			}
			BinaryReader reader = new BinaryReader(new BufferedStream(new FileStream(codeCompletionProxyFile, FileMode.Open, FileAccess.Read, FileShare.Read)));
			while (true) {
				try {
					ClassProxy newProxy = new ClassProxy(reader);
					classProxies.Add(newProxy);
					AddClassToNamespaceList(newProxy);
				} catch (Exception) {
					break;
				}
			}
			reader.Close();
		}
		
		void LoadThread()
		{
			SetDefaultCompletionFileLocation();
			
			BinaryFormatter formatter = new BinaryFormatter();
			
			if (File.Exists(codeCompletionProxyFile)) {
				LoadProxyDataFile();
			}
		}
		
		public override void InitializeService()
		{
			parser = (IParser[])(AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Parser").BuildChildItems(this)).ToArray(typeof(IParser));
			
			Thread myThread = new Thread(new ThreadStart(LoadThread));
			myThread.IsBackground = true;
			myThread.Priority = ThreadPriority.Lowest;
			myThread.Start();
			
			IProjectService projectService = (IProjectService)ICSharpCode.Core.Services.ServiceManager.Services.GetService(typeof(IProjectService));
			projectService.CombineOpened += new CombineEventHandler(OpenCombine);
		}
		
		public void AddReferenceToCompletionLookup(IProject project, ProjectReference reference)
		{
			if (reference.ReferenceType != ReferenceType.Project) {
				string fileName = reference.GetReferencedFileName(project);
				if (fileName == null || fileName.Length == 0) {
					return;
				}
				foreach (string assemblyName in assemblyList) {
					if (Path.GetFileNameWithoutExtension(fileName).ToUpper() == assemblyName.ToUpper()) {
						return;
					}
				}
				// HACK : Don't load references for non C# projects
				if (project.ProjectType != "C#") {
					return;
				}
				if (File.Exists(fileName)) {
					AssemblyLoader assemblyLoader = new AssemblyLoader(this, fileName);
					assemblyLoader.NonLocking = reference.ReferenceType != ReferenceType.Gac;
					Thread t = new Thread(new ThreadStart(assemblyLoader.LoadAssemblyParseInformations));
					t.IsBackground = true;
					t.Start();
				}
			}
		}
		
		class AssemblyLoader
		{
			DefaultParserService parserService;
			string assemblyFileName;
			bool nonLocking = false;
			
			public bool NonLocking {
				get {
					return nonLocking;
				}
				set {
					nonLocking = value;
				}
			}
			
			public AssemblyLoader(DefaultParserService parserService, string assemblyFileName)
			{
				this.parserService    = parserService;
				this.assemblyFileName = assemblyFileName;
			}
			
			public void LoadAssemblyParseInformations()
			{
				if (parserService.loadedAssemblies[assemblyFileName] != null) {
					return;
				}
				parserService.loadedAssemblies[assemblyFileName] = true;
				//Console.WriteLine("Before: " + Environment.WorkingSet / (1024 * 1024) + " -- " + assemblyFileName);
				try {
					AssemblyInformation assemblyInformation = new AssemblyInformation();
					assemblyInformation.Load(assemblyFileName, nonLocking);
					
					parserService.classes.Clear();
					parserService.caseInsensitiveClasses.Clear();
					
					foreach (IClass newClass in assemblyInformation.Classes) {
						parserService.AddClassToNamespaceList(newClass);
						lock (parserService.classes) {
							parserService.caseInsensitiveClasses[newClass.FullyQualifiedName.ToLower()] = parserService.classes[newClass.FullyQualifiedName] = new ClasstableEntry(null, null, newClass);
						}
					}
				} catch (Exception) {
				}
				//Console.WriteLine("After: " + Environment.WorkingSet / (1024 * 1024) + " -- " + assemblyFileName);
			}
		}
		
		public void OpenCombine(object sender, CombineEventArgs e)
		{
			ArrayList projects =  Combine.GetAllProjects(e.Combine);
			foreach (ProjectCombineEntry entry in projects) {
				foreach (ProjectReference r in entry.Project.ProjectReferences) {
					AddReferenceToCompletionLookup(entry.Project, r);
				}
			}
		}
		
		public void StartParserThread()
		{
			Thread parserThread = new Thread(new ThreadStart(ParserUpdateThread));
			parserThread.IsBackground  = true;
			parserThread.Start();
		}
		
		public override void UnloadService()
		{
			doneParserThread = true;
		}
		
		bool doneParserThread = false;
		Hashtable lastUpdateSize = new Hashtable();
		
		void ParserUpdateThread()
		{
// 			string fn=null;
			while (!doneParserThread) {
				////Thread.Sleep(1000); // not required
//// Alex: if some file was pulsed - during editor load and after - get file to reparse
//				fn = null; // set to null for each repetition
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//	Mike: Doesn't work with folding marker update --> look at the folding markers
//  Mike: You can't simply BREAK a feature and say I should fix it ... either bring the folding
//        markers in a working state or leave this change ... I don't see that your change is a good
//        alternative ... the current parserthread looks at the text and if it changed it reparses ...
//        it is better than the old version you fixed 
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

//				lock(DefaultParserService.ParserPulse) {
//					//Console.WriteLine("Pulse got: {0} entries",DefaultParserService.ParserPulse.Count);
//					Monitor.Wait(DefaultParserService.ParserPulse);
//					if (DefaultParserService.ParserPulse.Count>0) {
//						fn = (string)DefaultParserService.ParserPulse.Dequeue();
//					}
//				}
				try {
					if (WorkbenchSingleton.Workbench.ActiveWorkbenchWindow != null && WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent != null) {
						IEditable editable = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IEditable;
						if (editable != null) {
							string fileName = null;
							
							IViewContent viewContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ViewContent;
							IParseableContent parseableContent = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as IParseableContent;
							
							//ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it.
							string text = null;
							if (parseableContent != null) {
								fileName = parseableContent.ParseableContentName;
								text = parseableContent.ParseableText;
							} else {
								fileName = viewContent.IsUntitled ? viewContent.UntitledName : viewContent.FileName;
							}
							
							if (!(fileName == null || fileName.Length == 0)) {
//								Thread.Sleep(300); // not required 
								IParseInformation parseInformation = null;
								bool updated = false;
								if (text == null) {
									text = editable.Text;
								}
								int hash = text.GetHashCode();
								if (lastUpdateSize[fileName] == null || (int)lastUpdateSize[fileName] != hash) {
									parseInformation = ParseFile(fileName, text, !viewContent.IsUntitled);
									lastUpdateSize[fileName] = hash;
									updated = true;
								}
								if (updated) {
									if (parseInformation != null && editable is IParseInformationListener) {
										((IParseInformationListener)editable).ParseInformationUpdated(parseInformation);
									}
								}
//								if (fn != null) {
//									ParseFile(fn); // TODO: this one should update file parsings requested through queue
//								}
							}
						}
					}
				} catch (Exception) {
				}
				Thread.Sleep(2000);
			}
		}
		
		Hashtable AddClassToNamespaceList(IClass addClass)
		{
			string nSpace = addClass.Namespace;
			if (nSpace == null) {
				nSpace = String.Empty;
			}
			
			string[] path = nSpace.Split('.');
			
			lock (namespaces) {
				Hashtable cur                = namespaces;
				Hashtable caseInsensitiveCur = caseInsensitiveNamespaces;
				
				for (int i = 0; i < path.Length; ++i) {
					if (cur[path[i]] == null) {
						Hashtable hashTable                = new Hashtable();
						Hashtable caseInsensitivehashTable = new Hashtable();
						cur[path[i]] = hashTable;
						caseInsensitiveCur[path[i].ToLower()] = caseInsensitivehashTable;
						caseInsensitivehashTable[CaseInsensitiveKey] = hashTable;
					} else {
						if (!(cur[path[i]] is Hashtable)) {
							return null;
						}
					}
					cur = (Hashtable)cur[path[i]];
					
					if (caseInsensitiveCur[path[i].ToLower()] == null) {
					    caseInsensitiveCur[path[i].ToLower()] = new Hashtable();
					}
					caseInsensitiveCur = (Hashtable)caseInsensitiveCur[path[i].ToLower()];
				}
				
				string name = addClass.Name == null ? "" : addClass.Name;
				
				caseInsensitiveCur[name.ToLower()] = cur[name] = addClass;
				return cur;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -