📄 defaultparserservice.cs
字号:
// <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 + -